1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.ui.preferences;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.Iterator;
17 import java.util.StringTokenizer;
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.events.KeyEvent;
21 import org.eclipse.swt.events.KeyListener;
22 import org.eclipse.swt.events.ModifyEvent;
23 import org.eclipse.swt.events.ModifyListener;
24 import org.eclipse.swt.events.SelectionEvent;
25 import org.eclipse.swt.events.SelectionListener;
26 import org.eclipse.swt.graphics.Image;
27 import org.eclipse.swt.graphics.Point;
28 import org.eclipse.swt.layout.GridData;
29 import org.eclipse.swt.layout.GridLayout;
30 import org.eclipse.swt.widgets.Button;
31 import org.eclipse.swt.widgets.Composite;
32 import org.eclipse.swt.widgets.Control;
33 import org.eclipse.swt.widgets.Label;
34 import org.eclipse.swt.widgets.Table;
35 import org.eclipse.swt.widgets.TableColumn;
36 import org.eclipse.swt.widgets.TableItem;
37 import org.eclipse.swt.widgets.Text;
39 import org.eclipse.core.runtime.Assert;
40 import org.eclipse.core.runtime.IStatus;
42 import org.eclipse.jface.action.Action;
43 import org.eclipse.jface.dialogs.Dialog;
44 import org.eclipse.jface.layout.PixelConverter;
45 import org.eclipse.jface.preference.PreferencePage;
46 import org.eclipse.jface.viewers.CheckStateChangedEvent;
47 import org.eclipse.jface.viewers.CheckboxTableViewer;
48 import org.eclipse.jface.viewers.ColumnWeightData;
49 import org.eclipse.jface.viewers.ICheckStateListener;
50 import org.eclipse.jface.viewers.ILabelProviderListener;
51 import org.eclipse.jface.viewers.IStructuredContentProvider;
52 import org.eclipse.jface.viewers.ITableLabelProvider;
53 import org.eclipse.jface.viewers.StructuredSelection;
54 import org.eclipse.jface.viewers.TableLayout;
55 import org.eclipse.jface.viewers.TableViewer;
56 import org.eclipse.jface.viewers.Viewer;
58 import org.eclipse.jdt.internal.corext.util.Messages;
60 import org.eclipse.jdt.ui.PreferenceConstants;
62 import org.eclipse.jdt.internal.ui.JavaPlugin;
63 import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
64 import org.eclipse.jdt.internal.ui.dialogs.StatusUtil;
65 import org.eclipse.jdt.internal.ui.preferences.OverlayPreferenceStore.OverlayKey;
66 import org.eclipse.jdt.internal.ui.text.java.hover.JavaEditorTextHoverDescriptor;
67 import org.eclipse.jdt.internal.ui.util.SWTUtil;
68 import org.eclipse.jdt.internal.ui.util.TableLayoutComposite;
72 * Configures Java Editor hover preferences.
76 class JavaEditorHoverConfigurationBlock implements IPreferenceConfigurationBlock {
78 private static final String DELIMITER= PreferencesMessages.JavaEditorHoverConfigurationBlock_delimiter;
80 private static final int ENABLED_PROP= 0;
81 private static final int MODIFIER_PROP= 1;
83 // Data structure to hold the values which are edited by the user
84 private static class HoverConfig {
86 private String fModifierString;
87 private boolean fIsEnabled;
88 private int fStateMask;
90 private HoverConfig(String modifier, int stateMask, boolean enabled) {
91 fModifierString= modifier;
93 fStateMask= stateMask;
98 private class JavaEditorTextHoverDescriptorLabelProvider implements ITableLabelProvider {
100 public Image getColumnImage(Object element, int columnIndex) {
104 public String getColumnText(Object element, int columnIndex) {
105 switch (columnIndex) {
107 return ((JavaEditorTextHoverDescriptor)element).getLabel();
110 TableItem item= (TableItem)fHoverTableViewer.testFindItem(element);
111 int index= fHoverTable.indexOf(item);
112 return fHoverConfigs[index].fModifierString;
121 public void addListener(ILabelProviderListener listener) {
124 public void dispose() {
127 public boolean isLabelProperty(Object element, String property) {
131 public void removeListener(ILabelProviderListener listener) {
136 private class JavaEditorTextHoverDescriptorContentProvider implements IStructuredContentProvider {
138 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
139 // Do nothing since the viewer listens to resource deltas
142 public void dispose() {
145 public Object[] getElements(Object element) {
146 return (Object[])element;
151 private OverlayPreferenceStore fStore;
152 private HoverConfig[] fHoverConfigs;
153 private Text fModifierEditor;
154 private Table fHoverTable;
155 private TableViewer fHoverTableViewer;
156 private TableColumn fNameColumn;
157 private TableColumn fModifierColumn;
158 private Text fDescription;
160 private PreferencePage fMainPreferencePage;
162 private StatusInfo fStatus;
164 private Map<Button, String> fCheckBoxes= new HashMap<Button, String>();
165 private SelectionListener fCheckBoxListener= new SelectionListener() {
166 public void widgetDefaultSelected(SelectionEvent e) {
167 Button button= (Button) e.widget;
168 fStore.setValue(fCheckBoxes.get(button), button.getSelection());
170 public void widgetSelected(SelectionEvent e) {
171 Button button= (Button) e.widget;
172 fStore.setValue(fCheckBoxes.get(button), button.getSelection());
177 public JavaEditorHoverConfigurationBlock(PreferencePage mainPreferencePage, OverlayPreferenceStore store) {
178 Assert.isNotNull(mainPreferencePage);
179 Assert.isNotNull(store);
180 fMainPreferencePage= mainPreferencePage;
182 fStore.addKeys(createOverlayStoreKeys());
186 private OverlayPreferenceStore.OverlayKey[] createOverlayStoreKeys() {
188 ArrayList<OverlayKey> overlayKeys= new ArrayList<OverlayKey>();
190 overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER));
192 overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS));
193 overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS));
195 OverlayPreferenceStore.OverlayKey[] keys= new OverlayPreferenceStore.OverlayKey[overlayKeys.size()];
196 overlayKeys.toArray(keys);
201 * Creates page for hover preferences.
203 * @param parent the parent composite
204 * @return the control for the preference page
206 public Control createControl(Composite parent) {
208 ScrolledPageContent scrolled= new ScrolledPageContent(parent, SWT.H_SCROLL | SWT.V_SCROLL);
209 scrolled.setExpandHorizontal(true);
210 scrolled.setExpandVertical(true);
213 Composite hoverComposite= new Composite(scrolled, SWT.NONE);
214 GridLayout layout= new GridLayout();
215 layout.numColumns= 2;
216 layout.marginWidth= 0;
217 layout.marginHeight= 0;
218 hoverComposite.setLayout(layout);
220 String rollOverLabel= PreferencesMessages.JavaEditorHoverConfigurationBlock_annotationRollover;
221 addCheckBox(hoverComposite, rollOverLabel, PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER, 0);
223 addFiller(hoverComposite);
225 Label label= new Label(hoverComposite, SWT.NONE);
226 label.setText(PreferencesMessages.JavaEditorHoverConfigurationBlock_hoverPreferences);
227 GridData gd= new GridData(GridData.FILL_HORIZONTAL);
228 gd.horizontalAlignment= GridData.BEGINNING;
229 gd.horizontalSpan= 2;
230 label.setLayoutData(gd);
232 TableLayoutComposite layouter= new TableLayoutComposite(hoverComposite, SWT.NONE);
233 addColumnLayoutData(layouter);
236 fHoverTable= new Table(layouter, SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION | SWT.CHECK);
237 fHoverTable.setHeaderVisible(true);
238 fHoverTable.setLinesVisible(true);
240 gd= new GridData(GridData.FILL_HORIZONTAL);
241 gd.heightHint= SWTUtil.getTableHeightHint(fHoverTable, 10);
242 gd.horizontalSpan= 2;
243 gd.widthHint= new PixelConverter(parent).convertWidthInCharsToPixels(30);
244 layouter.setLayoutData(gd);
246 fHoverTable.addSelectionListener(new SelectionListener() {
247 public void widgetSelected(SelectionEvent e) {
248 handleHoverListSelection();
250 public void widgetDefaultSelected(SelectionEvent e) {
254 TableLayout tableLayout= new TableLayout();
255 fHoverTable.setLayout(tableLayout);
257 fNameColumn= new TableColumn(fHoverTable, SWT.NONE);
258 fNameColumn.setText(PreferencesMessages.JavaEditorHoverConfigurationBlock_nameColumnTitle);
259 fNameColumn.setResizable(true);
261 fModifierColumn= new TableColumn(fHoverTable, SWT.NONE);
262 fModifierColumn.setText(PreferencesMessages.JavaEditorHoverConfigurationBlock_modifierColumnTitle);
263 fModifierColumn.setResizable(true);
265 fHoverTableViewer= new CheckboxTableViewer(fHoverTable);
266 fHoverTableViewer.setUseHashlookup(true);
267 fHoverTableViewer.setContentProvider(new JavaEditorTextHoverDescriptorContentProvider());
268 fHoverTableViewer.setLabelProvider(new JavaEditorTextHoverDescriptorLabelProvider());
270 ((CheckboxTableViewer)fHoverTableViewer).addCheckStateListener(new ICheckStateListener() {
272 * @see org.eclipse.jface.viewers.ICheckStateListener#checkStateChanged(org.eclipse.jface.viewers.CheckStateChangedEvent)
274 public void checkStateChanged(CheckStateChangedEvent event) {
275 String id= ((JavaEditorTextHoverDescriptor)event.getElement()).getId();
278 JavaEditorTextHoverDescriptor[] descriptors= getContributedHovers();
279 HoverConfig hoverConfig= null;
280 int i= 0, length= fHoverConfigs.length;
282 if (id.equals(descriptors[i].getId())) {
283 hoverConfig= fHoverConfigs[i];
284 hoverConfig.fIsEnabled= event.getChecked();
285 fModifierEditor.setEnabled(event.getChecked());
286 fHoverTableViewer.setSelection(new StructuredSelection(descriptors[i]));
290 handleHoverListSelection();
291 updateStatus(hoverConfig);
295 // Text field for modifier string
296 label= new Label(hoverComposite, SWT.LEFT);
297 label.setText(PreferencesMessages.JavaEditorHoverConfigurationBlock_keyModifier);
298 fModifierEditor= new Text(hoverComposite, SWT.BORDER);
299 gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
300 fModifierEditor.setLayoutData(gd);
302 fModifierEditor.addKeyListener(new KeyListener() {
303 private boolean isModifierCandidate;
304 public void keyPressed(KeyEvent e) {
305 isModifierCandidate= e.keyCode > 0 && e.character == 0 && e.stateMask == 0;
308 public void keyReleased(KeyEvent e) {
309 if (isModifierCandidate && e.stateMask > 0 && e.stateMask == e.stateMask && e.character == 0) {// && e.time -time < 1000) {
310 String text= fModifierEditor.getText();
311 Point selection= fModifierEditor.getSelection();
312 int i= selection.x - 1;
313 while (i > -1 && Character.isWhitespace(text.charAt(i))) {
316 boolean needsPrefixDelimiter= i > -1 && !String.valueOf(text.charAt(i)).equals(DELIMITER);
319 while (i < text.length() && Character.isWhitespace(text.charAt(i))) {
322 boolean needsPostfixDelimiter= i < text.length() && !String.valueOf(text.charAt(i)).equals(DELIMITER);
326 if (needsPrefixDelimiter && needsPostfixDelimiter)
327 insertString= Messages.format(PreferencesMessages.JavaEditorHoverConfigurationBlock_insertDelimiterAndModifierAndDelimiter, new String[] {Action.findModifierString(e.stateMask)});
328 else if (needsPrefixDelimiter)
329 insertString= Messages.format(PreferencesMessages.JavaEditorHoverConfigurationBlock_insertDelimiterAndModifier, new String[] {Action.findModifierString(e.stateMask)});
330 else if (needsPostfixDelimiter)
331 insertString= Messages.format(PreferencesMessages.JavaEditorHoverConfigurationBlock_insertModifierAndDelimiter, new String[] {Action.findModifierString(e.stateMask)});
333 insertString= Action.findModifierString(e.stateMask);
335 if (insertString != null)
336 fModifierEditor.insert(insertString);
341 fModifierEditor.addModifyListener(new ModifyListener() {
342 public void modifyText(ModifyEvent e) {
343 handleModifierModified();
348 Label descriptionLabel= new Label(hoverComposite, SWT.LEFT);
349 descriptionLabel.setText(PreferencesMessages.JavaEditorHoverConfigurationBlock_description);
350 gd= new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
351 gd.horizontalSpan= 2;
352 descriptionLabel.setLayoutData(gd);
353 fDescription= new Text(hoverComposite, SWT.LEFT | SWT.WRAP | SWT.MULTI | SWT.READ_ONLY | SWT.BORDER);
354 gd= new GridData(GridData.FILL_BOTH);
355 gd.horizontalSpan= 2;
356 fDescription.setLayoutData(gd);
360 scrolled.setContent(hoverComposite);
361 final Point size= hoverComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT);
362 scrolled.setMinSize(size.x, size.y);
364 Dialog.applyDialogFont(scrolled);
370 private void addColumnLayoutData(TableLayoutComposite layouter) {
371 layouter.addColumnData(new ColumnWeightData(40, true));
372 layouter.addColumnData(new ColumnWeightData(60, true));
375 private JavaEditorTextHoverDescriptor[] getContributedHovers() {
376 return JavaPlugin.getDefault().getJavaEditorTextHoverDescriptors();
379 public void initialize() {
380 JavaEditorTextHoverDescriptor[] hoverDescs= getContributedHovers();
381 fHoverConfigs= new HoverConfig[hoverDescs.length];
382 for (int i= 0; i < hoverDescs.length; i++)
383 fHoverConfigs[i]= new HoverConfig(hoverDescs[i].getModifierString(), hoverDescs[i].getStateMask(), hoverDescs[i].isEnabled());
385 fHoverTableViewer.setInput(hoverDescs);
390 void initializeFields() {
391 fModifierEditor.setEnabled(false);
393 Iterator<Button> e= fCheckBoxes.keySet().iterator();
394 while (e.hasNext()) {
396 String key= fCheckBoxes.get(b);
397 b.setSelection(fStore.getBoolean(key));
400 for (int i= 0; i < fHoverConfigs.length; i++)
401 fHoverTable.getItem(i).setChecked(fHoverConfigs[i].fIsEnabled);
402 fHoverTableViewer.refresh();
405 public void performOk() {
406 StringBuffer buf= new StringBuffer();
407 StringBuffer maskBuf= new StringBuffer();
408 for (int i= 0; i < fHoverConfigs.length; i++) {
409 buf.append(getContributedHovers()[i].getId());
410 buf.append(JavaEditorTextHoverDescriptor.VALUE_SEPARATOR);
411 if (!fHoverConfigs[i].fIsEnabled)
412 buf.append(JavaEditorTextHoverDescriptor.DISABLED_TAG);
413 String modifier= fHoverConfigs[i].fModifierString;
414 if (modifier == null || modifier.length() == 0)
415 modifier= JavaEditorTextHoverDescriptor.NO_MODIFIER;
416 buf.append(modifier);
417 buf.append(JavaEditorTextHoverDescriptor.VALUE_SEPARATOR);
419 maskBuf.append(getContributedHovers()[i].getId());
420 maskBuf.append(JavaEditorTextHoverDescriptor.VALUE_SEPARATOR);
421 maskBuf.append(fHoverConfigs[i].fStateMask);
422 maskBuf.append(JavaEditorTextHoverDescriptor.VALUE_SEPARATOR);
424 fStore.setValue(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS, buf.toString());
425 fStore.setValue(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS, maskBuf.toString());
427 JavaPlugin.getDefault().resetJavaEditorTextHoverDescriptors();
430 public void performDefaults() {
431 restoreFromPreferences();
436 private void restoreFromPreferences() {
437 String compiledTextHoverModifiers= fStore.getString(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS);
439 StringTokenizer tokenizer= new StringTokenizer(compiledTextHoverModifiers, JavaEditorTextHoverDescriptor.VALUE_SEPARATOR);
440 HashMap<String, String> idToModifier= new HashMap<String, String>(tokenizer.countTokens() / 2);
442 while (tokenizer.hasMoreTokens()) {
443 String id= tokenizer.nextToken();
444 if (tokenizer.hasMoreTokens())
445 idToModifier.put(id, tokenizer.nextToken());
448 String compiledTextHoverModifierMasks= JavaPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS);
450 tokenizer= new StringTokenizer(compiledTextHoverModifierMasks, JavaEditorTextHoverDescriptor.VALUE_SEPARATOR);
451 HashMap<String, String> idToModifierMask= new HashMap<String, String>(tokenizer.countTokens() / 2);
453 while (tokenizer.hasMoreTokens()) {
454 String id= tokenizer.nextToken();
455 if (tokenizer.hasMoreTokens())
456 idToModifierMask.put(id, tokenizer.nextToken());
459 for (int i= 0; i < fHoverConfigs.length; i++) {
460 String modifierString= idToModifier.get(getContributedHovers()[i].getId());
461 boolean enabled= true;
462 if (modifierString == null)
463 modifierString= JavaEditorTextHoverDescriptor.DISABLED_TAG;
465 if (modifierString.startsWith(JavaEditorTextHoverDescriptor.DISABLED_TAG)) {
467 modifierString= modifierString.substring(1);
470 if (modifierString.equals(JavaEditorTextHoverDescriptor.NO_MODIFIER))
471 modifierString= ""; //$NON-NLS-1$
473 fHoverConfigs[i].fModifierString= modifierString;
474 fHoverConfigs[i].fIsEnabled= enabled;
475 fHoverConfigs[i].fStateMask= JavaEditorTextHoverDescriptor.computeStateMask(modifierString);
477 if (fHoverConfigs[i].fStateMask == -1) {
479 fHoverConfigs[i].fStateMask= Integer.parseInt(idToModifierMask.get(getContributedHovers()[i].getId()));
480 } catch (NumberFormatException ex) {
481 fHoverConfigs[i].fStateMask= -1;
487 private void handleModifierModified() {
488 int i= fHoverTable.getSelectionIndex();
492 String modifiers= fModifierEditor.getText();
493 fHoverConfigs[i].fModifierString= modifiers;
494 fHoverConfigs[i].fStateMask= JavaEditorTextHoverDescriptor.computeStateMask(modifiers);
497 fHoverTableViewer.refresh(getContributedHovers()[i]);
499 updateStatus(fHoverConfigs[i]);
502 private void handleHoverListSelection() {
503 int i= fHoverTable.getSelectionIndex();
506 if (fHoverTable.getSelectionCount() == 0)
507 fModifierEditor.setEnabled(false);
511 boolean enabled= fHoverConfigs[i].fIsEnabled;
512 fModifierEditor.setEnabled(enabled);
513 fModifierEditor.setText(fHoverConfigs[i].fModifierString);
514 String description= getContributedHovers()[i].getDescription();
515 if (description == null)
516 description= ""; //$NON-NLS-1$
517 fDescription.setText(description);
520 IStatus getStatus() {
522 fStatus= new StatusInfo();
526 private void updateStatus(HoverConfig hoverConfig) {
527 if (hoverConfig != null && hoverConfig.fIsEnabled && hoverConfig.fStateMask == -1)
528 fStatus= new StatusInfo(IStatus.ERROR, Messages.format(PreferencesMessages.JavaEditorHoverConfigurationBlock_modifierIsNotValid, hoverConfig.fModifierString));
530 fStatus= new StatusInfo();
533 HashMap<Integer, String> stateMasks= new HashMap<Integer, String>(fHoverConfigs.length);
534 while (fStatus.isOK() && i < fHoverConfigs.length) {
535 if (fHoverConfigs[i].fIsEnabled) {
536 String label= getContributedHovers()[i].getLabel();
537 Integer stateMask= new Integer(fHoverConfigs[i].fStateMask);
538 if (fHoverConfigs[i].fStateMask == -1)
539 fStatus= new StatusInfo(IStatus.ERROR, Messages.format(PreferencesMessages.JavaEditorHoverConfigurationBlock_modifierIsNotValidForHover, new String[] {fHoverConfigs[i].fModifierString, label}));
540 else if (stateMasks.containsKey(stateMask))
541 fStatus= new StatusInfo(IStatus.ERROR, Messages.format(PreferencesMessages.JavaEditorHoverConfigurationBlock_duplicateModifier, new String[] {label, stateMasks.get(stateMask)}));
543 stateMasks.put(stateMask, label);
548 fMainPreferencePage.setValid(fStatus.isOK());
549 StatusUtil.applyToStatusLine(fMainPreferencePage, fStatus);
552 private Button addCheckBox(Composite parent, String label, String key, int indentation) {
553 Button checkBox= new Button(parent, SWT.CHECK);
554 checkBox.setText(label);
556 GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
557 gd.horizontalIndent= indentation;
558 gd.horizontalSpan= 2;
559 checkBox.setLayoutData(gd);
560 checkBox.addSelectionListener(fCheckBoxListener);
562 fCheckBoxes.put(checkBox, key);
567 private void addFiller(Composite composite) {
568 PixelConverter pixelConverter= new PixelConverter(composite);
569 Label filler= new Label(composite, SWT.LEFT );
570 GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
571 gd.horizontalSpan= 2;
572 gd.heightHint= pixelConverter.convertHeightInCharsToPixels(1) / 2;
573 filler.setLayoutData(gd);
577 * @see DialogPage#dispose()
579 public void dispose() {
580 // nothing to dispose