1 11 12 package org.eclipse.jdt.apt.ui.internal.preferences; 13 14 import java.util.ArrayList ; 15 import java.util.Collections ; 16 import java.util.HashMap ; 17 import java.util.LinkedHashMap ; 18 import java.util.List ; 19 import java.util.Map ; 20 21 import org.eclipse.core.resources.IFolder; 22 import org.eclipse.core.resources.IProject; 23 import org.eclipse.core.resources.ProjectScope; 24 import org.eclipse.core.runtime.IStatus; 25 import org.eclipse.core.runtime.preferences.IEclipsePreferences; 26 import org.eclipse.core.runtime.preferences.IScopeContext; 27 import org.eclipse.core.runtime.preferences.InstanceScope; 28 import org.eclipse.jdt.apt.core.internal.AptPlugin; 29 import org.eclipse.jdt.apt.core.util.AptConfig; 30 import org.eclipse.jdt.apt.core.util.AptPreferenceConstants; 31 import org.eclipse.jdt.core.IJavaProject; 32 import org.eclipse.jdt.core.JavaCore; 33 import org.eclipse.jdt.internal.ui.dialogs.StatusInfo; 34 import org.eclipse.jdt.internal.ui.util.PixelConverter; 35 import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener; 36 import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField; 37 import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener; 38 import org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter; 39 import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil; 40 import org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField; 41 import org.eclipse.jdt.internal.ui.wizards.dialogfields.SelectionButtonDialogField; 42 import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringDialogField; 43 import org.eclipse.jface.dialogs.Dialog; 44 import org.eclipse.jface.viewers.ITableLabelProvider; 45 import org.eclipse.jface.viewers.LabelProvider; 46 import org.eclipse.jface.viewers.Viewer; 47 import org.eclipse.jface.viewers.ViewerComparator; 48 import org.eclipse.jface.window.Window; 49 import org.eclipse.swt.SWT; 50 import org.eclipse.swt.graphics.Image; 51 import org.eclipse.swt.layout.GridData; 52 import org.eclipse.swt.layout.GridLayout; 53 import org.eclipse.swt.widgets.Composite; 54 import org.eclipse.swt.widgets.Control; 55 import org.eclipse.swt.widgets.Label; 56 import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer; 57 import org.osgi.service.prefs.BackingStoreException; 58 59 66 public class AptConfigurationBlock extends BaseConfigurationBlock { 67 68 private static final Key KEY_APTENABLED= getKey(AptPlugin.PLUGIN_ID, AptPreferenceConstants.APT_ENABLED); 69 private static final Key KEY_RECONCILEENABLED= getKey(AptPlugin.PLUGIN_ID, AptPreferenceConstants.APT_RECONCILEENABLED); 70 private static final Key KEY_GENSRCDIR= getKey(AptPlugin.PLUGIN_ID, AptPreferenceConstants.APT_GENSRCDIR); 71 72 private static Key[] getAllKeys() { 73 return new Key[] { 74 KEY_APTENABLED, KEY_RECONCILEENABLED, KEY_GENSRCDIR 75 }; 76 } 77 78 private static final int IDX_ADD= 0; 79 private static final int IDX_EDIT= 1; 80 private static final int IDX_REMOVE= 2; 81 82 private final IJavaProject fJProj; 83 84 private SelectionButtonDialogField fAptEnabledField; 85 private SelectionButtonDialogField fReconcileEnabledField; 86 private StringDialogField fGenSrcDirField; 87 private ListDialogField fProcessorOptionsField; 88 89 private PixelConverter fPixelConverter; 90 private Composite fBlockControl; 91 92 private Map <String , String > fOriginalProcOptions; private String fOriginalGenSrcDir; 94 private boolean fOriginalAptEnabled; 95 private boolean fOriginalReconcileEnabled; 96 97 private boolean fPerProjSettingsEnabled; 99 100 103 private class ProcessorOptionsAdapter implements IListAdapter, IDialogFieldListener { 104 105 public void customButtonPressed(ListDialogField field, int index) { 106 switch (index) { 107 case IDX_ADD: 108 editOrAddProcessorOption(null); 109 break; 110 case IDX_EDIT: 111 tryToEdit(field); 112 break; 113 } 114 } 115 116 @SuppressWarnings ("unchecked") 117 public void selectionChanged(ListDialogField field) { 118 List selectedElements= field.getSelectedElements(); 119 field.enableButton(IDX_EDIT, canEdit(field, selectedElements)); 120 } 121 122 public void doubleClicked(ListDialogField field) { 123 tryToEdit(field); 124 } 125 126 public void dialogFieldChanged(DialogField field) { 127 updateModel(field); 128 } 129 130 @SuppressWarnings ("unchecked") 131 private boolean canEdit(DialogField field, List selectedElements) { 132 if (!field.isEnabled()) 133 return false; 134 return selectedElements.size() == 1; 135 } 136 137 private void tryToEdit(ListDialogField field) { 138 List <ProcessorOption> selection= getListSelection(); 139 if (canEdit(field, selection)) { 140 editOrAddProcessorOption(selection.get(0)); 141 } 142 } 143 } 144 145 148 public static class ProcessorOption { 149 public String key; 150 public String value; 151 } 152 153 156 private static class ProcessorOptionSorter extends ViewerComparator { 157 @SuppressWarnings ("unchecked") public int compare(Viewer viewer, Object e1, Object e2) { 159 return getComparator().compare(((ProcessorOption) e1).key, ((ProcessorOption) e2).key); 160 } 161 } 162 163 166 private class ProcessorOptionsLabelProvider extends LabelProvider implements ITableLabelProvider { 167 168 171 public Image getColumnImage(Object element, int columnIndex) { 172 return null; 173 } 174 175 178 public String getColumnText(Object element, int columnIndex) { 179 ProcessorOption o = (ProcessorOption) element; 180 if (columnIndex == 0) { 181 return o.key; 182 } 183 else if (columnIndex == 1) { 184 return o.value; 185 } 186 else { 187 return ""; } 189 } 190 } 191 192 public AptConfigurationBlock(IStatusChangeListener context, IProject project, IWorkbenchPreferenceContainer container) { 193 super(context, project, getAllKeys(), container); 194 195 fJProj = JavaCore.create(project); 196 197 UpdateAdapter adapter= new UpdateAdapter(); 198 199 if (fJProj != null) { 200 fAptEnabledField= new SelectionButtonDialogField(SWT.CHECK); 201 fAptEnabledField.setDialogFieldListener(adapter); 202 fAptEnabledField.setLabelText(Messages.AptConfigurationBlock_enable); 203 } 204 else { 205 fAptEnabledField = null; 206 } 207 208 fReconcileEnabledField= new SelectionButtonDialogField(SWT.CHECK); 209 fReconcileEnabledField.setDialogFieldListener(adapter); 210 fReconcileEnabledField.setLabelText(Messages.AptConfigurationBlock_enableReconcileProcessing); 211 212 fGenSrcDirField = new StringDialogField(); 213 fGenSrcDirField.setDialogFieldListener(adapter); 214 fGenSrcDirField.setLabelText(Messages.AptConfigurationBlock_generatedSrcDir); 215 216 String [] buttons= new String [] { 217 Messages.AptConfigurationBlock_add, 218 Messages.AptConfigurationBlock_edit, 219 Messages.AptConfigurationBlock_remove 220 }; 221 ProcessorOptionsAdapter optionsAdapter = new ProcessorOptionsAdapter(); 222 fProcessorOptionsField = new ListDialogField(optionsAdapter, buttons, new ProcessorOptionsLabelProvider()); 223 fProcessorOptionsField.setDialogFieldListener(optionsAdapter); 224 fProcessorOptionsField.setRemoveButtonIndex(IDX_REMOVE); 225 String [] columnHeaders= new String [] { 226 Messages.AptConfigurationBlock_key, 227 Messages.AptConfigurationBlock_value 228 }; 229 fProcessorOptionsField.setTableColumns(new ListDialogField.ColumnsDescription(columnHeaders, true)); 230 fProcessorOptionsField.setViewerComparator(new ProcessorOptionSorter()); 231 fProcessorOptionsField.setLabelText(Messages.AptConfigurationBlock_options); 232 233 updateControls(); 234 235 if (fProcessorOptionsField.getSize() > 0) { 236 fProcessorOptionsField.selectFirstElement(); 237 } else { 238 fProcessorOptionsField.enableButton(IDX_EDIT, false); 239 } 240 241 } 242 243 246 @Override 247 protected String [] getFullBuildDialogStrings(boolean workspaceSettings) { 248 if (workspaceSettings) 249 return null; 250 if (fOriginalGenSrcDir.equals(fGenSrcDirField.getText())) { 252 if (fOriginalAptEnabled == fAptEnabledField.isSelected()) { 253 if (!procOptionsChanged()) { 254 return null; 255 } 256 } 257 } 258 return super.getFullBuildDialogStrings(workspaceSettings); 259 } 260 261 264 @SuppressWarnings ("unchecked") 265 private List <ProcessorOption> getListElements() { 266 return fProcessorOptionsField.getElements(); 267 } 268 269 272 @SuppressWarnings ("unchecked") 273 private List <ProcessorOption> getListSelection() { 274 return fProcessorOptionsField.getSelectedElements(); 275 } 276 277 private void editOrAddProcessorOption(ProcessorOption original) { 278 ProcessorOptionInputDialog dialog= new ProcessorOptionInputDialog(getShell(), original, getListElements()); 279 if (dialog.open() == Window.OK) { 280 if (original != null) { 281 fProcessorOptionsField.replaceElement(original, dialog.getResult()); 282 } else { 283 fProcessorOptionsField.addElement(dialog.getResult()); 284 } 285 } 286 } 287 288 @Override 289 protected Control createContents(Composite parent) { 290 setShell(parent.getShell()); 291 292 fPixelConverter= new PixelConverter(parent); 293 int indent= fPixelConverter.convertWidthInCharsToPixels(4); 294 295 fBlockControl = new Composite(parent, SWT.NONE); 296 fBlockControl.setFont(parent.getFont()); 297 298 GridLayout layout= new GridLayout(); 299 layout.numColumns= 2; 300 layout.marginWidth= 0; 301 layout.marginHeight= 0; 302 303 fBlockControl.setLayout(layout); 304 305 DialogField[] fields = fAptEnabledField != null ? 306 new DialogField[] { 307 fAptEnabledField, 308 fReconcileEnabledField, 309 fGenSrcDirField, 310 fProcessorOptionsField, 311 } : 312 new DialogField[] { 313 fReconcileEnabledField, 314 fGenSrcDirField, 315 fProcessorOptionsField, 316 }; 317 LayoutUtil.doDefaultLayout(fBlockControl, fields, true, SWT.DEFAULT, SWT.DEFAULT); 318 LayoutUtil.setHorizontalGrabbing(fProcessorOptionsField.getListControl(null)); 319 320 GridData reconcileGD= (GridData)fReconcileEnabledField.getSelectionButton(parent).getLayoutData(); 321 reconcileGD.horizontalIndent = indent; 322 fReconcileEnabledField.getSelectionButton(parent).setLayoutData(reconcileGD); 323 324 Label description= new Label(fBlockControl, SWT.WRAP); 325 description.setText(Messages.AptConfigurationBlock_classpathAddedAutomaticallyNote); 326 GridData gdLabel= new GridData(GridData.HORIZONTAL_ALIGN_FILL); 327 gdLabel.horizontalSpan= 2; 328 gdLabel.widthHint= fPixelConverter.convertWidthInCharsToPixels(60); 329 description.setLayoutData(gdLabel); 330 331 Dialog.applyDialogFont(fBlockControl); 332 333 validateSettings(null, null, null); 334 335 return fBlockControl; 336 } 337 338 @Override 339 protected void cacheOriginalValues() { 340 super.cacheOriginalValues(); 341 fOriginalProcOptions= AptConfig.getRawProcessorOptions(fJProj); 342 fOriginalGenSrcDir = AptConfig.getGenSrcDir(fJProj); 343 fOriginalAptEnabled = AptConfig.isEnabled(fJProj); 344 fOriginalReconcileEnabled = AptConfig.shouldProcessDuringReconcile(fJProj); 345 fPerProjSettingsEnabled = hasProjectSpecificOptionsNoCache(fProject); 346 } 347 348 protected void initContents() { 349 loadProcessorOptions(fJProj); 350 } 351 352 @Override 353 protected void saveSettings() { 354 List <ProcessorOption> elements; 355 boolean isProjSpecificDisabled = (fJProj != null) && !fBlockControl.isEnabled(); 356 if (isProjSpecificDisabled) { 357 elements = Collections.<ProcessorOption>emptyList(); 361 } 362 else { 363 elements = getListElements(); 364 } 365 saveProcessorOptions(elements); 366 super.saveSettings(); 367 if (null != fAptProject) { 368 if (isProjSpecificDisabled) { if (!fOriginalGenSrcDir.equals(AptConfig.getGenSrcDir(null))) { 370 fAptProject.preferenceChanged(AptPreferenceConstants.APT_GENSRCDIR); 371 } 372 if (fOriginalAptEnabled != AptConfig.isEnabled(null)) { 373 fAptProject.preferenceChanged(AptPreferenceConstants.APT_ENABLED); 374 setJDTProcessAnnotationsSetting(fAptEnabledField.isSelected()); 376 } 377 if (fOriginalReconcileEnabled != AptConfig.shouldProcessDuringReconcile(null)) { 378 fAptProject.preferenceChanged(AptPreferenceConstants.APT_RECONCILEENABLED); 379 } 380 } 381 else { if (!fOriginalGenSrcDir.equals(fGenSrcDirField.getText())) 383 fAptProject.preferenceChanged(AptPreferenceConstants.APT_GENSRCDIR); 384 boolean isAptEnabled = fAptEnabledField.isSelected(); 385 if (fOriginalAptEnabled != isAptEnabled) { 386 fAptProject.preferenceChanged(AptPreferenceConstants.APT_ENABLED); 387 setJDTProcessAnnotationsSetting(isAptEnabled); 389 } 390 if (fOriginalReconcileEnabled != fReconcileEnabledField.isSelected()) 391 fAptProject.preferenceChanged(AptPreferenceConstants.APT_RECONCILEENABLED); 392 } 393 } 394 } 395 396 404 private void setJDTProcessAnnotationsSetting(boolean enable) { 405 IScopeContext context = (null != fJProj) ? 406 new ProjectScope(fJProj.getProject()) : new InstanceScope(); 407 IEclipsePreferences node = context.getNode(JavaCore.PLUGIN_ID); 408 final String value = enable ? AptPreferenceConstants.ENABLED : AptPreferenceConstants.DISABLED; 409 node.put(AptPreferenceConstants.APT_PROCESSANNOTATIONS, value); 410 try { 411 node.flush(); 412 } 413 catch (BackingStoreException e){ 414 AptPlugin.log(e, "Failed to save preference: " + AptPreferenceConstants.APT_PROCESSANNOTATIONS); } 416 } 417 418 422 private boolean procOptionsChanged() { 423 Map <String , String > savedProcOptions = new HashMap <String , String >(fOriginalProcOptions); 424 for (ProcessorOption o : getListElements()) { 425 final String savedVal = savedProcOptions.get(o.key); 426 if (savedVal != null && savedVal.equals(o.value)) { 427 savedProcOptions.remove(o.key); 428 } 429 else { 430 return true; 432 } 433 } 434 if (!savedProcOptions.isEmpty()) { 435 return true; 437 } 438 return false; 439 } 440 441 445 @Override 446 protected boolean settingsChanged(IScopeContext currContext) { 447 if (procOptionsChanged()) 448 return true; 449 else 450 return super.settingsChanged(currContext); 451 } 452 453 459 @Override 460 protected void validateSettings(Key changedKey, String oldValue, String newValue) { 461 IStatus status = null; 462 463 status = validateGenSrcDir(); 464 if (status.getSeverity() == IStatus.OK) { 465 status = validateProcessorOptions(); 466 } 467 468 fContext.statusChanged(status); 469 } 470 471 476 private IStatus validateGenSrcDir() { 477 String dirName = fGenSrcDirField.getText(); 478 if (!AptConfig.validateGenSrcDir(fJProj, dirName)) { 479 return new StatusInfo(IStatus.ERROR, Messages.AptConfigurationBlock_genSrcDirMustBeValidRelativePath); 480 } 481 if (fJProj != null && !dirName.equals(fOriginalGenSrcDir)) { 482 IFolder folder = fJProj.getProject().getFolder( dirName ); 483 if (folder != null && folder.exists() && !folder.isDerived()) { 484 return new StatusInfo(IStatus.WARNING, Messages.AptConfigurationBlock_warningContentsMayBeDeleted); 485 } 486 } 487 return new StatusInfo(); 488 } 489 490 496 private IStatus validateProcessorOptions() { 497 List <ProcessorOption> elements = getListElements(); 498 for (ProcessorOption o : elements) { 499 if (AptConfig.isAutomaticProcessorOption(o.key)) { 500 return new StatusInfo(IStatus.WARNING, 501 Messages.AptConfigurationBlock_warningIgnoredOptions + ": " + o.key); } 503 } 504 return new StatusInfo(); 505 } 506 507 510 @Override 511 protected void updateControls() { 512 if (fAptEnabledField != null) { 513 boolean aptEnabled= Boolean.valueOf(getValue(KEY_APTENABLED)).booleanValue(); 514 fAptEnabledField.setSelection(aptEnabled); 515 } 516 boolean reconcileEnabled= Boolean.valueOf(getValue(KEY_RECONCILEENABLED)).booleanValue(); 517 fReconcileEnabledField.setSelection(reconcileEnabled); 518 String str= getValue(KEY_GENSRCDIR); 519 fGenSrcDirField.setText(str == null ? "" : str); } 521 522 525 protected final void updateModel(DialogField field) { 526 527 if (fAptEnabledField != null && field == fAptEnabledField) { 528 String newVal = String.valueOf(fAptEnabledField.isSelected()); 529 setValue(KEY_APTENABLED, newVal); 530 } else if (field == fGenSrcDirField) { 531 String newVal = fGenSrcDirField.getText(); 532 setValue(KEY_GENSRCDIR, newVal); 533 } else if (field == fReconcileEnabledField) { 534 String newVal = String.valueOf(fReconcileEnabledField.isSelected()); 535 setValue(KEY_RECONCILEENABLED, newVal); 536 } 537 validateSettings(null, null, null); } 539 540 543 @Override 544 public void useProjectSpecificSettings(boolean enable) { 545 super.useProjectSpecificSettings(enable); 546 if (enable ^ fPerProjSettingsEnabled) { 547 fAptEnabledField.setSelection(enable); 548 fPerProjSettingsEnabled = enable; 549 } 550 } 551 552 555 private void saveProcessorOptions(List <ProcessorOption> elements) { 556 Map <String , String > map = new LinkedHashMap <String , String >(elements.size()); 557 for (ProcessorOption o : elements) { 558 map.put(o.key, (o.value.length() > 0) ? o.value : null); 559 } 560 AptConfig.setProcessorOptions(map, fJProj); 561 } 562 563 566 private void loadProcessorOptions(IJavaProject jproj) { 567 List <ProcessorOption> options= new ArrayList <ProcessorOption>(); 568 Map <String , String > parsedOptions = AptConfig.getRawProcessorOptions(jproj); 569 for (Map.Entry <String , String > entry : parsedOptions.entrySet()) { 570 ProcessorOption o = new ProcessorOption(); 571 o.key = entry.getKey(); 572 if (o.key == null || o.key.length() < 1) { 573 continue; 575 } 576 o.value = (entry.getValue() == null) ? "" : entry.getValue(); options.add(o); 578 } 579 fProcessorOptionsField.setElements(options); 580 } 581 582 @Override 583 public void performDefaults() { 584 fPerProjSettingsEnabled = false; 585 if (fJProj != null) { 586 loadProcessorOptions(null); 588 } 589 else { 590 fProcessorOptionsField.removeAllElements(); 592 } 593 super.performDefaults(); 594 } 595 596 } 597 598 599 | Popular Tags |