1 /*******************************************************************************
2 * Copyright (c) 2002, 2010 QNX Software Systems 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 * QNX Software Systems - Initial API and implementation
10 * Anton Leherbauer (Wind River Systems)
11 *******************************************************************************/
13 package org.eclipse.cdt.internal.ui.preferences;
15 import java.util.ArrayList;
16 import java.util.HashMap;
17 import java.util.StringTokenizer;
19 import org.eclipse.core.runtime.Assert;
20 import org.eclipse.core.runtime.IStatus;
21 import org.eclipse.jface.action.Action;
22 import org.eclipse.jface.dialogs.Dialog;
23 import org.eclipse.jface.layout.PixelConverter;
24 import org.eclipse.jface.preference.PreferencePage;
25 import org.eclipse.jface.viewers.CheckStateChangedEvent;
26 import org.eclipse.jface.viewers.CheckboxTableViewer;
27 import org.eclipse.jface.viewers.ColumnWeightData;
28 import org.eclipse.jface.viewers.ICheckStateListener;
29 import org.eclipse.jface.viewers.ILabelProviderListener;
30 import org.eclipse.jface.viewers.IStructuredContentProvider;
31 import org.eclipse.jface.viewers.ITableLabelProvider;
32 import org.eclipse.jface.viewers.TableLayout;
33 import org.eclipse.jface.viewers.TableViewer;
34 import org.eclipse.jface.viewers.Viewer;
35 import org.eclipse.osgi.util.NLS;
36 import org.eclipse.swt.SWT;
37 import org.eclipse.swt.events.KeyEvent;
38 import org.eclipse.swt.events.KeyListener;
39 import org.eclipse.swt.events.ModifyEvent;
40 import org.eclipse.swt.events.ModifyListener;
41 import org.eclipse.swt.events.SelectionEvent;
42 import org.eclipse.swt.events.SelectionListener;
43 import org.eclipse.swt.graphics.Image;
44 import org.eclipse.swt.graphics.Point;
45 import org.eclipse.swt.layout.GridData;
46 import org.eclipse.swt.layout.GridLayout;
47 import org.eclipse.swt.widgets.Composite;
48 import org.eclipse.swt.widgets.Control;
49 import org.eclipse.swt.widgets.Label;
50 import org.eclipse.swt.widgets.Table;
51 import org.eclipse.swt.widgets.TableColumn;
52 import org.eclipse.swt.widgets.TableItem;
53 import org.eclipse.swt.widgets.Text;
54 import org.eclipse.cdt.ui.CUIPlugin;
55 import org.eclipse.cdt.ui.PreferenceConstants;
57 import org.eclipse.cdt.internal.ui.dialogs.StatusInfo;
58 import org.eclipse.cdt.internal.ui.dialogs.StatusUtil;
59 import org.eclipse.cdt.internal.ui.preferences.OverlayPreferenceStore.OverlayKey;
60 import org.eclipse.cdt.internal.ui.text.c.hover.CEditorTextHoverDescriptor;
61 import org.eclipse.cdt.internal.ui.util.SWTUtil;
62 import org.eclipse.cdt.internal.ui.util.TableLayoutComposite;
65 * Configures C/C++ Editor hover preferences.
67 public class CEditorHoverConfigurationBlock implements IPreferenceConfigurationBlock {
68 static final String DELIMITER= PreferencesMessages.CEditorHoverConfigurationBlock_delimiter;
70 private static final int ENABLED_PROP= 0;
71 private static final int MODIFIER_PROP= 1;
73 // Data structure to hold the values which are edited by the user
74 private static class HoverConfig {
76 String fModifierString;
80 private HoverConfig(String modifier, int stateMask, boolean enabled) {
81 fModifierString= modifier;
83 fStateMask= stateMask;
88 private class CEditorTextHoverDescriptorLabelProvider implements ITableLabelProvider {
90 public Image getColumnImage(Object element, int columnIndex) {
94 public String getColumnText(Object element, int columnIndex) {
95 switch (columnIndex) {
97 return ((CEditorTextHoverDescriptor)element).getLabel();
100 TableItem item= (TableItem)fHoverTableViewer.testFindItem(element);
101 int index= fHoverTable.indexOf(item);
102 return fHoverConfigs[index].fModifierString;
111 public void addListener(ILabelProviderListener listener) {
114 public void dispose() {
117 public boolean isLabelProperty(Object element, String property) {
121 public void removeListener(ILabelProviderListener listener) {
126 private class CEditorTextHoverDescriptorContentProvider implements IStructuredContentProvider {
128 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
129 // Do nothing since the viewer listens to resource deltas
132 public void dispose() {
135 public Object[] getElements(Object element) {
136 return (Object[])element;
141 OverlayPreferenceStore fStore;
142 HoverConfig[] fHoverConfigs;
143 Text fModifierEditor;
145 TableViewer fHoverTableViewer;
146 private TableColumn fNameColumn;
147 private TableColumn fModifierColumn;
148 private Text fDescription;
150 private PreferencePage fMainPreferencePage;
152 private StatusInfo fStatus;
154 public CEditorHoverConfigurationBlock(PreferencePage mainPreferencePage, OverlayPreferenceStore store) {
155 Assert.isNotNull(mainPreferencePage);
156 Assert.isNotNull(store);
157 fMainPreferencePage= mainPreferencePage;
159 fStore.addKeys(createOverlayStoreKeys());
163 private OverlayPreferenceStore.OverlayKey[] createOverlayStoreKeys() {
165 ArrayList<OverlayKey> overlayKeys= new ArrayList<OverlayKey>();
167 //overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER));
168 overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS));
169 overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS));
171 OverlayPreferenceStore.OverlayKey[] keys= new OverlayPreferenceStore.OverlayKey[overlayKeys.size()];
172 overlayKeys.toArray(keys);
177 * Creates page for hover preferences.
179 * @param parent the parent composite
180 * @return the control for the preference page
182 public Control createControl(Composite parent) {
184 ScrolledPageContent scrolled= new ScrolledPageContent(parent, SWT.H_SCROLL | SWT.V_SCROLL);
185 scrolled.setExpandHorizontal(true);
186 scrolled.setExpandVertical(true);
189 Composite hoverComposite= new Composite(scrolled, SWT.NONE);
190 GridLayout layout= new GridLayout();
191 layout.numColumns= 2;
192 layout.marginWidth= 0;
193 layout.marginHeight= 0;
194 hoverComposite.setLayout(layout);
195 hoverComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
197 //String rollOverLabel= PreferencesMessages.getString("CEditorHoverConfigurationBlock.annotationRollover"); //$NON-NLS-1$
198 //addCheckBox(hoverComposite, rollOverLabel, PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER, 0); //$NON-NLS-1$
200 //addFiller(hoverComposite);
202 Label label= new Label(hoverComposite, SWT.NONE);
203 label.setText(PreferencesMessages.CEditorHoverConfigurationBlock_hoverPreferences);
204 GridData gd= new GridData(GridData.FILL_HORIZONTAL);
205 gd.horizontalAlignment= GridData.BEGINNING;
206 gd.horizontalSpan= 2;
207 label.setLayoutData(gd);
209 TableLayoutComposite layouter= new TableLayoutComposite(hoverComposite, SWT.NONE);
210 addColumnLayoutData(layouter);
213 fHoverTable= new Table(layouter, SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION | SWT.CHECK);
214 fHoverTable.setHeaderVisible(true);
215 fHoverTable.setLinesVisible(true);
217 gd= new GridData(GridData.FILL_HORIZONTAL);
218 gd.heightHint= SWTUtil.getTableHeightHint(fHoverTable, 10);
219 gd.horizontalSpan= 2;
220 gd.widthHint= new PixelConverter(parent).convertWidthInCharsToPixels(30);
221 layouter.setLayoutData(gd);
223 fHoverTable.addSelectionListener(new SelectionListener() {
224 public void widgetSelected(SelectionEvent e) {
225 handleHoverListSelection();
227 public void widgetDefaultSelected(SelectionEvent e) {
231 TableLayout tableLayout= new TableLayout();
232 fHoverTable.setLayout(tableLayout);
234 fNameColumn= new TableColumn(fHoverTable, SWT.NONE);
235 fNameColumn.setText(PreferencesMessages.CEditorHoverConfigurationBlock_nameColumnTitle);
236 fNameColumn.setResizable(true);
238 fModifierColumn= new TableColumn(fHoverTable, SWT.NONE);
239 fModifierColumn.setText(PreferencesMessages.CEditorHoverConfigurationBlock_modifierColumnTitle);
240 fModifierColumn.setResizable(true);
242 fHoverTableViewer= new CheckboxTableViewer(fHoverTable);
243 fHoverTableViewer.setUseHashlookup(true);
244 fHoverTableViewer.setContentProvider(new CEditorTextHoverDescriptorContentProvider());
245 fHoverTableViewer.setLabelProvider(new CEditorTextHoverDescriptorLabelProvider());
247 ((CheckboxTableViewer)fHoverTableViewer).addCheckStateListener(new ICheckStateListener() {
249 * @see org.eclipse.jface.viewers.ICheckStateListener#checkStateChanged(org.eclipse.jface.viewers.CheckStateChangedEvent)
251 public void checkStateChanged(CheckStateChangedEvent event) {
252 String id= ((CEditorTextHoverDescriptor)event.getElement()).getId();
255 CEditorTextHoverDescriptor[] descriptors= getContributedHovers();
256 HoverConfig hoverConfig = null;
257 int i= 0, length= fHoverConfigs.length;
259 if (id.equals(descriptors[i].getId())) {
260 hoverConfig = fHoverConfigs[i];
261 hoverConfig.fIsEnabled= event.getChecked();
262 fModifierEditor.setEnabled(event.getChecked());
267 updateStatus(hoverConfig);
271 // Text field for modifier string
272 label= new Label(hoverComposite, SWT.LEFT);
273 label.setText(PreferencesMessages.CEditorHoverConfigurationBlock_keyModifier);
274 fModifierEditor= new Text(hoverComposite, SWT.BORDER);
275 gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
276 fModifierEditor.setLayoutData(gd);
278 fModifierEditor.addKeyListener(new KeyListener() {
279 private boolean isModifierCandidate;
280 public void keyPressed(KeyEvent e) {
281 isModifierCandidate= e.keyCode > 0 && e.character == 0 && e.stateMask == 0;
284 public void keyReleased(KeyEvent e) {
285 if (isModifierCandidate && e.stateMask > 0 && e.stateMask == e.stateMask && e.character == 0) {// && e.time -time < 1000) {
286 String text= fModifierEditor.getText();
287 Point selection= fModifierEditor.getSelection();
288 int i= selection.x - 1;
289 while (i > -1 && Character.isWhitespace(text.charAt(i))) {
292 boolean needsPrefixDelimiter= i > -1 && !String.valueOf(text.charAt(i)).equals(DELIMITER);
295 while (i < text.length() && Character.isWhitespace(text.charAt(i))) {
298 boolean needsPostfixDelimiter= i < text.length() && !String.valueOf(text.charAt(i)).equals(DELIMITER);
302 if (needsPrefixDelimiter && needsPostfixDelimiter)
303 insertString= NLS.bind(PreferencesMessages.CEditorHoverConfigurationBlock_insertDelimiterAndModifierAndDelimiter, new String[] {Action.findModifierString(e.stateMask)});
304 else if (needsPrefixDelimiter)
305 insertString= NLS.bind(PreferencesMessages.CEditorHoverConfigurationBlock_insertDelimiterAndModifier, new String[] {Action.findModifierString(e.stateMask)});
306 else if (needsPostfixDelimiter)
307 insertString= NLS.bind(PreferencesMessages.CEditorHoverConfigurationBlock_insertModifierAndDelimiter, new String[] {Action.findModifierString(e.stateMask)});
309 insertString= Action.findModifierString(e.stateMask);
311 if (insertString != null)
312 fModifierEditor.insert(insertString);
317 fModifierEditor.addModifyListener(new ModifyListener() {
318 public void modifyText(ModifyEvent e) {
319 handleModifierModified();
324 Label descriptionLabel= new Label(hoverComposite, SWT.LEFT);
325 descriptionLabel.setText(PreferencesMessages.CEditorHoverConfigurationBlock_description);
326 gd= new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
327 gd.horizontalSpan= 2;
328 descriptionLabel.setLayoutData(gd);
329 fDescription= new Text(hoverComposite, SWT.LEFT | SWT.WRAP | SWT.MULTI | SWT.READ_ONLY | SWT.BORDER);
330 gd= new GridData(GridData.FILL_BOTH);
331 gd.horizontalSpan= 2;
332 fDescription.setLayoutData(gd);
336 scrolled.setContent(hoverComposite);
337 final Point size= hoverComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT);
338 scrolled.setMinSize(size.x, size.y);
340 Dialog.applyDialogFont(scrolled);
345 private void addColumnLayoutData(TableLayoutComposite layouter) {
346 layouter.addColumnData(new ColumnWeightData(40, true));
347 layouter.addColumnData(new ColumnWeightData(60, true));
350 CEditorTextHoverDescriptor[] getContributedHovers() {
351 return CUIPlugin.getDefault().getCEditorTextHoverDescriptors();
355 * @see org.eclipse.cdt.internal.ui.preferences.IPreferenceConfigurationBlock#initialize()
357 public void initialize() {
358 CEditorTextHoverDescriptor[] hoverDescs= getContributedHovers();
359 fHoverConfigs= new HoverConfig[hoverDescs.length];
360 for (int i= 0; i < hoverDescs.length; i++)
361 fHoverConfigs[i]= new HoverConfig(hoverDescs[i].getModifierString(), hoverDescs[i].getStateMask(), hoverDescs[i].isEnabled());
363 fHoverTableViewer.setInput(hoverDescs);
368 void initializeFields() {
369 fModifierEditor.setEnabled(false);
371 CEditorTextHoverDescriptor[] hoverDescs= getContributedHovers();
372 for (int i= 0; i < hoverDescs.length; i++)
373 fHoverTable.getItem(i).setChecked(hoverDescs[i].isEnabled());
374 fHoverTableViewer.refresh();
378 * @see org.eclipse.cdt.internal.ui.preferences.IPreferenceConfigurationBlock#performOk()
380 public void performOk() {
381 StringBuffer buf= new StringBuffer();
382 StringBuffer maskBuf= new StringBuffer();
383 for (int i= 0; i < fHoverConfigs.length; i++) {
384 buf.append(getContributedHovers()[i].getId());
385 buf.append(CEditorTextHoverDescriptor.VALUE_SEPARATOR);
386 if (!fHoverConfigs[i].fIsEnabled)
387 buf.append(CEditorTextHoverDescriptor.DISABLED_TAG);
388 String modifier= fHoverConfigs[i].fModifierString;
389 if (modifier == null || modifier.length() == 0)
390 modifier= CEditorTextHoverDescriptor.NO_MODIFIER;
391 buf.append(modifier);
392 buf.append(CEditorTextHoverDescriptor.VALUE_SEPARATOR);
394 maskBuf.append(getContributedHovers()[i].getId());
395 maskBuf.append(CEditorTextHoverDescriptor.VALUE_SEPARATOR);
396 maskBuf.append(fHoverConfigs[i].fStateMask);
397 maskBuf.append(CEditorTextHoverDescriptor.VALUE_SEPARATOR);
399 fStore.setValue(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS, buf.toString());
400 fStore.setValue(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS, maskBuf.toString());
402 CUIPlugin.getDefault().resetCEditorTextHoverDescriptors();
406 * @see org.eclipse.cdt.internal.ui.preferences.IPreferenceConfigurationBlock#performDefaults()
408 public void performDefaults() {
409 restoreFromPreferences();
414 private void restoreFromPreferences() {
415 String compiledTextHoverModifiers= fStore.getString(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS);
417 StringTokenizer tokenizer= new StringTokenizer(compiledTextHoverModifiers, CEditorTextHoverDescriptor.VALUE_SEPARATOR);
418 HashMap<String, String> idToModifier= new HashMap<String, String>(tokenizer.countTokens() / 2);
420 while (tokenizer.hasMoreTokens()) {
421 String id= tokenizer.nextToken();
422 if (tokenizer.hasMoreTokens())
423 idToModifier.put(id, tokenizer.nextToken());
426 String compiledTextHoverModifierMasks= CUIPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS);
428 tokenizer= new StringTokenizer(compiledTextHoverModifierMasks, CEditorTextHoverDescriptor.VALUE_SEPARATOR);
429 HashMap<String, String> idToModifierMask= new HashMap<String, String>(tokenizer.countTokens() / 2);
431 while (tokenizer.hasMoreTokens()) {
432 String id= tokenizer.nextToken();
433 if (tokenizer.hasMoreTokens())
434 idToModifierMask.put(id, tokenizer.nextToken());
437 for (int i= 0; i < fHoverConfigs.length; i++) {
438 String modifierString= idToModifier.get(getContributedHovers()[i].getId());
439 boolean enabled= true;
440 if (modifierString == null)
441 modifierString= CEditorTextHoverDescriptor.DISABLED_TAG;
443 if (modifierString.startsWith(CEditorTextHoverDescriptor.DISABLED_TAG)) {
445 modifierString= modifierString.substring(1);
448 if (modifierString.equals(CEditorTextHoverDescriptor.NO_MODIFIER))
449 modifierString= ""; //$NON-NLS-1$
451 fHoverConfigs[i].fModifierString= modifierString;
452 fHoverConfigs[i].fIsEnabled= enabled;
453 fHoverConfigs[i].fStateMask= CEditorTextHoverDescriptor.computeStateMask(modifierString);
455 if (fHoverConfigs[i].fStateMask == -1) {
457 fHoverConfigs[i].fStateMask= Integer.parseInt(idToModifierMask.get(getContributedHovers()[i].getId()));
458 } catch (NumberFormatException ex) {
459 fHoverConfigs[i].fStateMask= -1;
465 void handleModifierModified() {
466 int i= fHoverTable.getSelectionIndex();
467 String modifiers= fModifierEditor.getText();
468 fHoverConfigs[i].fModifierString= modifiers;
469 fHoverConfigs[i].fStateMask= CEditorTextHoverDescriptor.computeStateMask(modifiers);
470 if (fHoverConfigs[i].fIsEnabled && fHoverConfigs[i].fStateMask == -1)
471 fStatus= new StatusInfo(IStatus.ERROR, NLS.bind(PreferencesMessages.CEditorHoverConfigurationBlock_modifierIsNotValid, fHoverConfigs[i].fModifierString));
473 fStatus= new StatusInfo();
476 fHoverTableViewer.refresh(getContributedHovers()[i]);
478 updateStatus(fHoverConfigs[i]);
481 void handleHoverListSelection() {
482 int i= fHoverTable.getSelectionIndex();
485 if (fHoverTable.getSelectionCount() == 0)
486 fModifierEditor.setEnabled(false);
490 boolean enabled= fHoverConfigs[i].fIsEnabled;
491 fModifierEditor.setEnabled(enabled);
492 fModifierEditor.setText(fHoverConfigs[i].fModifierString);
493 String description= getContributedHovers()[i].getDescription();
494 if (description == null)
495 description= ""; //$NON-NLS-1$
496 fDescription.setText(description);
499 IStatus getStatus() {
501 fStatus= new StatusInfo();
505 void updateStatus(HoverConfig hoverConfig) {
506 if (hoverConfig != null && hoverConfig.fIsEnabled && hoverConfig.fStateMask == -1)
507 fStatus= new StatusInfo(IStatus.ERROR, NLS.bind(PreferencesMessages.CEditorHoverConfigurationBlock_modifierIsNotValid, hoverConfig.fModifierString));
509 fStatus= new StatusInfo();
512 HashMap<Integer, String> stateMasks= new HashMap<Integer, String>(fHoverConfigs.length);
513 while (fStatus.isOK() && i < fHoverConfigs.length) {
514 if (fHoverConfigs[i].fIsEnabled) {
515 String label= getContributedHovers()[i].getLabel();
516 Integer stateMask= new Integer(fHoverConfigs[i].fStateMask);
517 if (fHoverConfigs[i].fStateMask == -1)
518 fStatus= new StatusInfo(IStatus.ERROR, NLS.bind(PreferencesMessages.CEditorHoverConfigurationBlock_modifierIsNotValidForHover, new String[] {fHoverConfigs[i].fModifierString, label}));
519 else if (stateMasks.containsKey(stateMask))
520 fStatus= new StatusInfo(IStatus.ERROR, NLS.bind(PreferencesMessages.CEditorHoverConfigurationBlock_duplicateModifier, new String[] {label, stateMasks.get(stateMask)}));
522 stateMasks.put(stateMask, label);
527 fMainPreferencePage.setValid(fStatus.isOK());
528 StatusUtil.applyToStatusLine(fMainPreferencePage, fStatus);
532 // private void addFiller(Composite composite) {
533 // PixelConverter pixelConverter= new PixelConverter(composite);
534 // Label filler= new Label(composite, SWT.LEFT );
535 // GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
536 // gd.horizontalSpan= 2;
537 // gd.heightHint= pixelConverter.convertHeightInCharsToPixels(1) / 2;
538 // filler.setLayoutData(gd);
542 * @see DialogPage#dispose()
544 public void dispose() {
545 // nothing to dispose