1 /******************************************************************************* 2 * Copyright (c) 2000, 2016 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Remy Chi Jian Suen <remy.suen@gmail.com> - Bug 175069 [Preferences] ResourceInfoPage is not setting dialog font on all widgets 14 * Serge Beauchamp (Freescale Semiconductor) - [229633] Project Path Variable Support 15 * Lars Vogel <Lars.Vogel@vogella.com> - Bug 474273 16 * Simon Scholz <simon.scholz@vogella.com> - Bug 486777 17 *******************************************************************************/ 18 package org.eclipse.ui.internal.ide.dialogs; 19 20 import java.net.URI; 21 import java.net.URL; 22 import java.util.ArrayList; 23 import java.util.Collections; 24 import java.util.HashSet; 25 import java.util.Iterator; 26 import java.util.List; 27 import java.util.Set; 28 29 import org.eclipse.core.commands.Command; 30 import org.eclipse.core.commands.ParameterizedCommand; 31 import org.eclipse.core.filesystem.EFS; 32 import org.eclipse.core.filesystem.IFileInfo; 33 import org.eclipse.core.filesystem.IFileStore; 34 import org.eclipse.core.filesystem.IFileSystem; 35 import org.eclipse.core.filesystem.URIUtil; 36 import org.eclipse.core.resources.IContainer; 37 import org.eclipse.core.resources.IFile; 38 import org.eclipse.core.resources.IFolder; 39 import org.eclipse.core.resources.IResource; 40 import org.eclipse.core.resources.ResourceAttributes; 41 import org.eclipse.core.runtime.Adapters; 42 import org.eclipse.core.runtime.CoreException; 43 import org.eclipse.core.runtime.FileLocator; 44 import org.eclipse.core.runtime.IPath; 45 import org.eclipse.core.runtime.NullProgressMonitor; 46 import org.eclipse.core.runtime.OperationCanceledException; 47 import org.eclipse.core.runtime.Path; 48 import org.eclipse.core.runtime.Status; 49 import org.eclipse.core.runtime.SubMonitor; 50 import org.eclipse.core.runtime.content.IContentDescription; 51 import org.eclipse.core.runtime.jobs.Job; 52 import org.eclipse.e4.core.commands.ECommandService; 53 import org.eclipse.e4.core.commands.EHandlerService; 54 import org.eclipse.jface.dialogs.Dialog; 55 import org.eclipse.jface.dialogs.ErrorDialog; 56 import org.eclipse.jface.dialogs.IDialogConstants; 57 import org.eclipse.jface.dialogs.MessageDialog; 58 import org.eclipse.jface.layout.GridDataFactory; 59 import org.eclipse.jface.preference.FieldEditor; 60 import org.eclipse.jface.resource.ImageDescriptor; 61 import org.eclipse.jface.resource.JFaceResources; 62 import org.eclipse.jface.resource.LocalResourceManager; 63 import org.eclipse.jface.resource.ResourceManager; 64 import org.eclipse.jface.window.Window; 65 import org.eclipse.osgi.util.NLS; 66 import org.eclipse.osgi.util.TextProcessor; 67 import org.eclipse.swt.SWT; 68 import org.eclipse.swt.custom.TableEditor; 69 import org.eclipse.swt.events.SelectionAdapter; 70 import org.eclipse.swt.events.SelectionEvent; 71 import org.eclipse.swt.events.SelectionListener; 72 import org.eclipse.swt.graphics.Font; 73 import org.eclipse.swt.layout.GridData; 74 import org.eclipse.swt.layout.GridLayout; 75 import org.eclipse.swt.widgets.Button; 76 import org.eclipse.swt.widgets.Composite; 77 import org.eclipse.swt.widgets.Control; 78 import org.eclipse.swt.widgets.Label; 79 import org.eclipse.swt.widgets.Table; 80 import org.eclipse.swt.widgets.TableColumn; 81 import org.eclipse.swt.widgets.TableItem; 82 import org.eclipse.swt.widgets.Text; 83 import org.eclipse.ui.PlatformUI; 84 import org.eclipse.ui.dialogs.PropertyPage; 85 import org.eclipse.ui.ide.dialogs.ResourceEncodingFieldEditor; 86 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; 87 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; 88 import org.eclipse.ui.internal.ide.IIDEHelpContextIds; 89 import org.eclipse.ui.internal.ide.LineDelimiterEditor; 90 import org.eclipse.ui.internal.ide.handlers.ShowInSystemExplorerHandler; 91 import org.osgi.framework.Bundle; 92 import org.osgi.framework.FrameworkUtil; 93 94 /** 95 * The ResourceInfoPage is the page that shows the basic info about the 96 * resource. 97 */ 98 public class ResourceInfoPage extends PropertyPage { 99 private interface IResourceChange { getMessage()100 public String getMessage(); 101 performChange(IResource resource)102 public void performChange(IResource resource) throws CoreException; 103 } 104 105 private Button editableBox; 106 107 private Button executableBox; 108 109 private Button archiveBox; 110 111 private Button derivedBox; 112 113 private Button immutableBox; 114 115 private Button permissionBoxes[]; 116 117 private boolean previousReadOnlyValue; 118 119 private boolean previousExecutableValue; 120 121 private boolean previousArchiveValue; 122 123 private boolean previousDerivedValue; 124 125 private int previousPermissionsValue; 126 127 private IContentDescription cachedContentDescription; 128 129 private ResourceEncodingFieldEditor encodingEditor; 130 131 private LineDelimiterEditor lineDelimiterEditor; 132 133 private static String READ_ONLY = IDEWorkbenchMessages.ResourceInfo_readOnly; 134 135 private static String EXECUTABLE = IDEWorkbenchMessages.ResourceInfo_executable; 136 137 private static String LOCKED = IDEWorkbenchMessages.ResourceInfo_locked; 138 139 private static String ARCHIVE = IDEWorkbenchMessages.ResourceInfo_archive; 140 141 private static String DERIVED = IDEWorkbenchMessages.ResourceInfo_derived; 142 143 private static String DERIVED_HAS_DERIVED_ANCESTOR = IDEWorkbenchMessages.ResourceInfo_derivedHasDerivedAncestor; 144 145 private static String TYPE_TITLE = IDEWorkbenchMessages.ResourceInfo_type; 146 147 private static String LOCATION_TITLE = IDEWorkbenchMessages.ResourceInfo_location; 148 149 private static String LOCATION_BUTTON_TOOLTIP = IDEWorkbenchMessages.ResourceInfo_location_button_tooltip; 150 151 private static String RESOLVED_LOCATION_TITLE = IDEWorkbenchMessages.ResourceInfo_resolvedLocation; 152 153 private static String SIZE_TITLE = IDEWorkbenchMessages.ResourceInfo_size; 154 155 private static String PATH_TITLE = IDEWorkbenchMessages.ResourceInfo_path; 156 157 private static String TIMESTAMP_TITLE = IDEWorkbenchMessages.ResourceInfo_lastModified; 158 159 private static String FILE_ENCODING_TITLE = IDEWorkbenchMessages.WorkbenchPreference_encoding; 160 161 private static String CONTAINER_ENCODING_TITLE = IDEWorkbenchMessages.ResourceInfo_fileEncodingTitle; 162 163 private static String EDIT_TITLE = IDEWorkbenchMessages.ResourceInfo_edit; 164 165 private Text resolvedLocationValue = null; 166 private Text locationValue = null; 167 private Text sizeValue = null; 168 private IPath newResourceLocation = null; 169 170 // Max value width in characters before wrapping 171 private static final int MAX_VALUE_WIDTH = 80; 172 173 /** 174 * Create the group that shows the name, location, size and type. 175 * 176 * @param parent 177 * the composite the group will be created in 178 * @param resource 179 * the resource the information is being taken from. 180 * @return the composite for the group 181 */ createBasicInfoGroup(Composite parent, IResource resource)182 private Composite createBasicInfoGroup(Composite parent, IResource resource) { 183 initializeDialogUnits(parent); 184 185 Composite basicInfoComposite = new Composite(parent, SWT.NULL); 186 GridLayout layout = new GridLayout(); 187 layout.numColumns = 3; 188 layout.marginWidth = 0; 189 layout.marginHeight = 0; 190 basicInfoComposite.setLayout(layout); 191 GridData data = new GridData(); 192 data.verticalAlignment = GridData.FILL; 193 data.horizontalAlignment = GridData.FILL; 194 basicInfoComposite.setLayoutData(data); 195 196 // The group for path 197 Label pathLabel = new Label(basicInfoComposite, SWT.NONE); 198 pathLabel.setText(PATH_TITLE); 199 GridData gd = new GridData(); 200 gd.verticalAlignment = SWT.TOP; 201 pathLabel.setLayoutData(gd); 202 203 // path value label 204 Text pathValueText = new Text(basicInfoComposite, SWT.WRAP 205 | SWT.READ_ONLY); 206 String pathString = TextProcessor.process(resource.getFullPath() 207 .toString()); 208 pathValueText.setText(pathString); 209 gd = new GridData(); 210 gd.widthHint = convertWidthInCharsToPixels(MAX_VALUE_WIDTH); 211 gd.grabExcessHorizontalSpace = true; 212 gd.horizontalAlignment = GridData.FILL; 213 gd.horizontalSpan = 2; 214 pathValueText.setLayoutData(gd); 215 pathValueText.setBackground(pathValueText.getDisplay().getSystemColor( 216 SWT.COLOR_WIDGET_BACKGROUND)); 217 218 // The group for types 219 Label typeTitle = new Label(basicInfoComposite, SWT.LEFT); 220 typeTitle.setText(TYPE_TITLE); 221 222 Text typeValue = new Text(basicInfoComposite, SWT.LEFT | SWT.READ_ONLY); 223 GridDataFactory.swtDefaults().span(2, SWT.DEFAULT).applyTo(typeValue); 224 typeValue.setText(IDEResourceInfoUtils.getTypeString(resource, 225 getContentDescription(resource))); 226 typeValue.setBackground(typeValue.getDisplay().getSystemColor( 227 SWT.COLOR_WIDGET_BACKGROUND)); 228 229 if (resource.isLinked() && !resource.isVirtual()) { 230 // The group for location 231 Label locationTitle = new Label(basicInfoComposite, SWT.LEFT); 232 locationTitle.setText(LOCATION_TITLE); 233 gd = new GridData(); 234 gd.verticalAlignment = SWT.TOP; 235 locationTitle.setLayoutData(gd); 236 237 Composite locationComposite = new Composite(basicInfoComposite, 238 SWT.NULL); 239 layout = new GridLayout(); 240 layout.numColumns = 2; 241 layout.marginWidth = 0; 242 layout.marginHeight = 0; 243 locationComposite.setLayout(layout); 244 gd = new GridData(); 245 gd.widthHint = convertWidthInCharsToPixels(MAX_VALUE_WIDTH); 246 gd.grabExcessHorizontalSpace = true; 247 gd.verticalAlignment = SWT.TOP; 248 gd.horizontalAlignment = GridData.FILL; 249 gd.horizontalSpan = 2; 250 locationComposite.setLayoutData(gd); 251 252 locationValue = new Text(locationComposite, SWT.WRAP 253 | SWT.READ_ONLY); 254 String locationStr = TextProcessor.process(IDEResourceInfoUtils 255 .getLocationText(resource)); 256 locationValue.setText(locationStr); 257 gd = new GridData(); 258 gd.widthHint = convertWidthInCharsToPixels(MAX_VALUE_WIDTH); 259 gd.grabExcessHorizontalSpace = true; 260 gd.verticalAlignment = SWT.TOP; 261 gd.horizontalAlignment = GridData.FILL; 262 locationValue.setLayoutData(gd); 263 locationValue.setBackground(locationValue.getDisplay().getSystemColor( 264 SWT.COLOR_WIDGET_BACKGROUND)); 265 266 Button editButton = new Button(locationComposite, SWT.PUSH); 267 editButton.setText(EDIT_TITLE); 268 setButtonLayoutData(editButton); 269 ((GridData) editButton.getLayoutData()).verticalAlignment = SWT.TOP; 270 int locationValueHeight = locationValue.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).y; 271 int editButtonHeight = editButton.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).y; 272 int verticalIndent = (editButtonHeight - locationValueHeight) / 2 ; 273 ((GridData) locationTitle.getLayoutData()).verticalIndent = verticalIndent; 274 ((GridData) locationValue.getLayoutData()).verticalIndent = verticalIndent; 275 editButton.addSelectionListener(new SelectionListener() { 276 @Override 277 public void widgetDefaultSelected(SelectionEvent e) { 278 editLinkLocation(); 279 } 280 281 @Override 282 public void widgetSelected(SelectionEvent e) { 283 editLinkLocation(); 284 } 285 }); 286 287 // displayed in all cases since the link can be changed to a path variable any time by the user in this dialog 288 Label resolvedLocationTitle = new Label(basicInfoComposite, 289 SWT.LEFT); 290 resolvedLocationTitle.setText(RESOLVED_LOCATION_TITLE); 291 gd = new GridData(); 292 gd.verticalAlignment = SWT.TOP; 293 resolvedLocationTitle.setLayoutData(gd); 294 295 resolvedLocationValue = new Text(basicInfoComposite, SWT.WRAP 296 | SWT.READ_ONLY); 297 resolvedLocationValue.setText(IDEResourceInfoUtils 298 .getResolvedLocationText(resource)); 299 gd = new GridData(); 300 gd.widthHint = convertWidthInCharsToPixels(MAX_VALUE_WIDTH); 301 gd.grabExcessHorizontalSpace = true; 302 gd.horizontalAlignment = GridData.FILL; 303 gd.horizontalSpan = 2; 304 resolvedLocationValue.setLayoutData(gd); 305 resolvedLocationValue.setBackground(resolvedLocationValue 306 .getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); 307 } else { 308 if (!resource.isVirtual()) { 309 // The group for location 310 Label locationTitle = new Label(basicInfoComposite, SWT.LEFT); 311 locationTitle.setText(LOCATION_TITLE); 312 gd = new GridData(); 313 locationTitle.setLayoutData(gd); 314 315 Text locationValue = new Text(basicInfoComposite, SWT.WRAP 316 | SWT.READ_ONLY); 317 final String locationStr = TextProcessor.process(IDEResourceInfoUtils 318 .getLocationText(resource)); 319 locationValue.setText(locationStr); 320 gd = new GridData(); 321 gd.horizontalAlignment = GridData.FILL; 322 locationValue.setLayoutData(gd); 323 locationValue.setBackground(locationValue.getDisplay() 324 .getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); 325 326 Button goToLocationButton = new Button(basicInfoComposite, SWT.PUSH); 327 gd = new GridData(); 328 gd.verticalAlignment = SWT.TOP; 329 goToLocationButton.setLayoutData(gd); 330 ResourceManager resourceManager = new LocalResourceManager(JFaceResources.getResources(), 331 goToLocationButton); 332 Bundle bundle = FrameworkUtil.getBundle(getClass()); 333 URL goToFolderUrl = FileLocator.find(bundle, new Path("icons/full/obj16/goto_input.png"), //$NON-NLS-1$ 334 null); 335 goToLocationButton.setImage(resourceManager.createImage(ImageDescriptor.createFromURL(goToFolderUrl))); 336 goToLocationButton.setToolTipText(LOCATION_BUTTON_TOOLTIP); 337 goToLocationButton.addSelectionListener(new SelectionAdapter() { 338 339 @SuppressWarnings("restriction") 340 @Override 341 public void widgetSelected(SelectionEvent e) { 342 ECommandService commandService = PlatformUI.getWorkbench().getService(ECommandService.class); 343 EHandlerService handlerService = PlatformUI.getWorkbench().getService(EHandlerService.class); 344 345 Command command = commandService.getCommand(ShowInSystemExplorerHandler.ID); 346 if (command.isDefined()) { 347 ParameterizedCommand parameterizedCommand = commandService 348 .createCommand(ShowInSystemExplorerHandler.ID, Collections.singletonMap( 349 ShowInSystemExplorerHandler.RESOURCE_PATH_PARAMETER, locationStr)); 350 if (handlerService.canExecute(parameterizedCommand)) { 351 handlerService.executeHandler(parameterizedCommand); 352 } 353 } 354 } 355 }); 356 } 357 } 358 if (resource.getType() == IResource.FILE) { 359 // The group for size 360 Label sizeTitle = new Label(basicInfoComposite, SWT.LEFT); 361 sizeTitle.setText(SIZE_TITLE); 362 363 Text sizeValue = new Text(basicInfoComposite, SWT.LEFT 364 | SWT.READ_ONLY); 365 sizeValue.setText(IDEResourceInfoUtils.getSizeString(resource)); 366 gd = new GridData(); 367 gd.widthHint = convertWidthInCharsToPixels(MAX_VALUE_WIDTH); 368 gd.grabExcessHorizontalSpace = true; 369 gd.horizontalAlignment = GridData.FILL; 370 gd.horizontalSpan = 2; 371 sizeValue.setLayoutData(gd); 372 sizeValue.setBackground(sizeValue.getDisplay().getSystemColor( 373 SWT.COLOR_WIDGET_BACKGROUND)); 374 } 375 376 Label timeStampLabel = new Label(basicInfoComposite, SWT.NONE); 377 timeStampLabel.setText(TIMESTAMP_TITLE); 378 379 // timeStamp value label 380 Text timeStampValue = new Text(basicInfoComposite, SWT.READ_ONLY); 381 timeStampValue.setText(IDEResourceInfoUtils 382 .getDateStringValue(resource)); 383 timeStampValue.setBackground(timeStampValue.getDisplay() 384 .getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); 385 GridData gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL); 386 gridData.horizontalSpan = 2; 387 timeStampValue.setLayoutData(gridData); 388 389 return basicInfoComposite; 390 } 391 editLinkLocation()392 protected void editLinkLocation() { 393 IResource resource = Adapters.adapt(getElement(), IResource.class); 394 String locationFormat = resource.getPathVariableManager().convertFromUserEditableFormat(locationValue.getText(), true); 395 IPath location = Path.fromOSString(locationFormat); 396 397 PathVariableDialog dialog = new PathVariableDialog(getShell(), 398 PathVariableDialog.EDIT_LINK_LOCATION, resource.getType(), 399 resource.getPathVariableManager(), null); 400 dialog.setLinkLocation(location); 401 dialog.setResource(resource); 402 // opens the dialog - just returns if the user cancels it 403 if (dialog.open() == Window.CANCEL) { 404 return; 405 } 406 location = Path.fromOSString(dialog.getVariableValue()); 407 newResourceLocation = location; 408 refreshLinkLocation(); 409 } 410 refreshLinkLocation()411 private void refreshLinkLocation() { 412 IResource resource = Adapters.adapt(getElement(), IResource.class); 413 414 String userEditableFormat = resource.getPathVariableManager().convertToUserEditableFormat(newResourceLocation.toOSString(), true); 415 locationValue.setText(userEditableFormat); 416 417 URI resolvedURI = resource.getPathVariableManager() 418 .resolveURI(URIUtil.toURI(newResourceLocation)); 419 IPath resolved = URIUtil.toPath(resolvedURI); 420 if (!IDEResourceInfoUtils.exists(resolved.toOSString())) { 421 resolvedLocationValue 422 .setText(IDEWorkbenchMessages.ResourceInfo_undefinedPathVariable); 423 if (sizeValue != null) 424 sizeValue.setText(IDEWorkbenchMessages.ResourceInfo_notExist); 425 } else { 426 resolvedLocationValue.setText(resolved.toPortableString()); 427 if (sizeValue != null) { 428 IFileInfo info = IDEResourceInfoUtils.getFileInfo(resolved 429 .toPortableString()); 430 if (info != null) 431 sizeValue.setText(NLS.bind( 432 IDEWorkbenchMessages.ResourceInfo_bytes, Long 433 .toString(info.getLength()))); 434 else 435 sizeValue 436 .setText(IDEWorkbenchMessages.ResourceInfo_unknown); 437 } 438 } 439 } 440 441 @Override createContents(Composite parent)442 protected Control createContents(Composite parent) { 443 444 PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), 445 IIDEHelpContextIds.RESOURCE_INFO_PROPERTY_PAGE); 446 447 // layout the page 448 IResource resource = Adapters.adapt(getElement(), IResource.class); 449 450 if (resource == null) { 451 Label label = new Label(parent, SWT.NONE); 452 label.setText(IDEWorkbenchMessages.ResourceInfoPage_noResource); 453 return label; 454 } 455 456 if (resource.getType() != IResource.PROJECT) { 457 ResourceAttributes attrs = resource.getResourceAttributes(); 458 if (attrs != null) { 459 previousReadOnlyValue = attrs.isReadOnly(); 460 previousExecutableValue = attrs.isExecutable(); 461 previousArchiveValue = attrs.isArchive(); 462 } else { 463 previousReadOnlyValue = previousExecutableValue = previousArchiveValue = false; 464 } 465 previousDerivedValue = resource.isDerived(); 466 } 467 468 // top level group 469 Composite composite = new Composite(parent, SWT.NONE); 470 GridLayout layout = new GridLayout(); 471 layout.marginWidth = 0; 472 layout.marginHeight = 0; 473 composite.setLayout(layout); 474 GridData data = new GridData(GridData.FILL); 475 data.grabExcessHorizontalSpace = true; 476 composite.setLayoutData(data); 477 478 createBasicInfoGroup(composite, resource); 479 // Attributes are not relevant to projects 480 if (resource.getType() != IResource.PROJECT) { 481 createSeparator(composite); 482 int fsAttributes = getFileSystemAttributes(resource); 483 if (isPermissionsSupport(fsAttributes)) 484 previousPermissionsValue = fetchPermissions(resource); 485 createStateGroup(composite, resource, fsAttributes); 486 if (isPermissionsSupport(fsAttributes)) { 487 createSeparator(composite); 488 createPermissionsGroup(composite); 489 setPermissionsSelection(previousPermissionsValue); 490 } 491 } 492 //We can't save and load the preferences for closed project 493 if (resource.getProject().isOpen()) { 494 encodingEditor = new ResourceEncodingFieldEditor( 495 getFieldEditorLabel(resource), composite, resource); 496 encodingEditor.setPage(this); 497 encodingEditor.load(); 498 499 encodingEditor.setPropertyChangeListener(event -> { 500 if (event.getProperty().equals(FieldEditor.IS_VALID)) { 501 setValid(encodingEditor.isValid()); 502 } 503 }); 504 505 if (resource.getType() == IResource.PROJECT) { 506 lineDelimiterEditor = new LineDelimiterEditor(composite, resource 507 .getProject()); 508 lineDelimiterEditor.doLoad(); 509 } 510 } 511 512 Dialog.applyDialogFont(composite); 513 514 return composite; 515 } 516 fetchPermissions(IResource resource)517 private int fetchPermissions(IResource resource) { 518 IFileStore store = null; 519 try { 520 store = EFS.getStore(resource.getLocationURI()); 521 } catch (CoreException e) { 522 return 0; 523 } 524 IFileInfo info = store.fetchInfo(); 525 int permissions = 0; 526 if (info.exists()) { 527 permissions |= info.getAttribute(EFS.ATTRIBUTE_OWNER_READ) ? EFS.ATTRIBUTE_OWNER_READ 528 : 0; 529 permissions |= info.getAttribute(EFS.ATTRIBUTE_OWNER_WRITE) ? EFS.ATTRIBUTE_OWNER_WRITE 530 : 0; 531 permissions |= info.getAttribute(EFS.ATTRIBUTE_OWNER_EXECUTE) ? EFS.ATTRIBUTE_OWNER_EXECUTE 532 : 0; 533 permissions |= info.getAttribute(EFS.ATTRIBUTE_GROUP_READ) ? EFS.ATTRIBUTE_GROUP_READ 534 : 0; 535 permissions |= info.getAttribute(EFS.ATTRIBUTE_GROUP_WRITE) ? EFS.ATTRIBUTE_GROUP_WRITE 536 : 0; 537 permissions |= info.getAttribute(EFS.ATTRIBUTE_GROUP_EXECUTE) ? EFS.ATTRIBUTE_GROUP_EXECUTE 538 : 0; 539 permissions |= info.getAttribute(EFS.ATTRIBUTE_OTHER_READ) ? EFS.ATTRIBUTE_OTHER_READ 540 : 0; 541 permissions |= info.getAttribute(EFS.ATTRIBUTE_OTHER_WRITE) ? EFS.ATTRIBUTE_OTHER_WRITE 542 : 0; 543 permissions |= info.getAttribute(EFS.ATTRIBUTE_OTHER_EXECUTE) ? EFS.ATTRIBUTE_OTHER_EXECUTE 544 : 0; 545 permissions |= info.getAttribute(EFS.ATTRIBUTE_IMMUTABLE) ? EFS.ATTRIBUTE_IMMUTABLE 546 : 0; 547 } 548 return permissions; 549 } 550 getDefaulPermissions(boolean folder)551 private int getDefaulPermissions(boolean folder) { 552 int permissions = EFS.ATTRIBUTE_OWNER_READ | EFS.ATTRIBUTE_OWNER_WRITE 553 | EFS.ATTRIBUTE_GROUP_READ | EFS.ATTRIBUTE_GROUP_WRITE 554 | EFS.ATTRIBUTE_OTHER_READ; 555 if (folder) 556 permissions |= EFS.ATTRIBUTE_OWNER_EXECUTE 557 | EFS.ATTRIBUTE_GROUP_EXECUTE | EFS.ATTRIBUTE_OTHER_EXECUTE; 558 return permissions; 559 } 560 setPermissionsSelection(int permissions)561 private void setPermissionsSelection(int permissions) { 562 permissionBoxes[0].setSelection((permissions & EFS.ATTRIBUTE_OWNER_READ) != 0); 563 permissionBoxes[1].setSelection((permissions & EFS.ATTRIBUTE_OWNER_WRITE) != 0); 564 permissionBoxes[2].setSelection((permissions & EFS.ATTRIBUTE_OWNER_EXECUTE) != 0); 565 permissionBoxes[3].setSelection((permissions & EFS.ATTRIBUTE_GROUP_READ) != 0); 566 permissionBoxes[4].setSelection((permissions & EFS.ATTRIBUTE_GROUP_WRITE) != 0); 567 permissionBoxes[5].setSelection((permissions & EFS.ATTRIBUTE_GROUP_EXECUTE) != 0); 568 permissionBoxes[6].setSelection((permissions & EFS.ATTRIBUTE_OTHER_READ) != 0); 569 permissionBoxes[7].setSelection((permissions & EFS.ATTRIBUTE_OTHER_WRITE) != 0); 570 permissionBoxes[8].setSelection((permissions & EFS.ATTRIBUTE_OTHER_EXECUTE) != 0); 571 if (immutableBox != null) 572 immutableBox.setSelection((permissions & EFS.ATTRIBUTE_IMMUTABLE) != 0); 573 } 574 getPermissionsSelection()575 private int getPermissionsSelection() { 576 int permissions = 0; 577 permissions |= permissionBoxes[0].getSelection() ? EFS.ATTRIBUTE_OWNER_READ : 0; 578 permissions |= permissionBoxes[1].getSelection() ? EFS.ATTRIBUTE_OWNER_WRITE : 0; 579 permissions |= permissionBoxes[2].getSelection() ? EFS.ATTRIBUTE_OWNER_EXECUTE : 0; 580 permissions |= permissionBoxes[3].getSelection() ? EFS.ATTRIBUTE_GROUP_READ : 0; 581 permissions |= permissionBoxes[4].getSelection() ? EFS.ATTRIBUTE_GROUP_WRITE : 0; 582 permissions |= permissionBoxes[5].getSelection() ? EFS.ATTRIBUTE_GROUP_EXECUTE : 0; 583 permissions |= permissionBoxes[6].getSelection() ? EFS.ATTRIBUTE_OTHER_READ : 0; 584 permissions |= permissionBoxes[7].getSelection() ? EFS.ATTRIBUTE_OTHER_WRITE : 0; 585 permissions |= permissionBoxes[8].getSelection() ? EFS.ATTRIBUTE_OTHER_EXECUTE : 0; 586 if (immutableBox != null) 587 permissions |= immutableBox.getSelection() ? EFS.ATTRIBUTE_IMMUTABLE : 0; 588 return permissions; 589 } 590 putPermissions(IResource resource, int permissions)591 private boolean putPermissions(IResource resource, int permissions) { 592 IFileStore store = null; 593 try { 594 store = EFS.getStore(resource.getLocationURI()); 595 } catch (CoreException e) { 596 return false; 597 } 598 IFileInfo fileInfo = store.fetchInfo(); 599 if (!fileInfo.exists()) 600 return false; 601 fileInfo.setAttribute(EFS.ATTRIBUTE_OWNER_READ, (permissions & EFS.ATTRIBUTE_OWNER_READ) != 0); 602 fileInfo.setAttribute(EFS.ATTRIBUTE_OWNER_WRITE, (permissions & EFS.ATTRIBUTE_OWNER_WRITE) != 0); 603 fileInfo.setAttribute(EFS.ATTRIBUTE_OWNER_EXECUTE, (permissions & EFS.ATTRIBUTE_OWNER_EXECUTE) != 0); 604 fileInfo.setAttribute(EFS.ATTRIBUTE_GROUP_READ, (permissions & EFS.ATTRIBUTE_GROUP_READ) != 0); 605 fileInfo.setAttribute(EFS.ATTRIBUTE_GROUP_WRITE, (permissions & EFS.ATTRIBUTE_GROUP_WRITE) != 0); 606 fileInfo.setAttribute(EFS.ATTRIBUTE_GROUP_EXECUTE, (permissions & EFS.ATTRIBUTE_GROUP_EXECUTE) != 0); 607 fileInfo.setAttribute(EFS.ATTRIBUTE_OTHER_READ, (permissions & EFS.ATTRIBUTE_OTHER_READ) != 0); 608 fileInfo.setAttribute(EFS.ATTRIBUTE_OTHER_WRITE, (permissions & EFS.ATTRIBUTE_OTHER_WRITE) != 0); 609 fileInfo.setAttribute(EFS.ATTRIBUTE_OTHER_EXECUTE, (permissions & EFS.ATTRIBUTE_OTHER_EXECUTE) != 0); 610 fileInfo.setAttribute(EFS.ATTRIBUTE_IMMUTABLE, (permissions & EFS.ATTRIBUTE_IMMUTABLE) != 0); 611 try { 612 store.putInfo(fileInfo, EFS.SET_ATTRIBUTES, null); 613 } catch (CoreException e) { 614 return false; 615 } 616 return true; 617 } 618 619 /** 620 * Return the label for the encoding field editor for the resource. 621 * 622 * @param resource - 623 * the resource to edit. 624 * @return String 625 */ getFieldEditorLabel(IResource resource)626 private String getFieldEditorLabel(IResource resource) { 627 if (resource instanceof IContainer) { 628 return CONTAINER_ENCODING_TITLE; 629 } 630 return FILE_ENCODING_TITLE; 631 } 632 633 /** 634 * Create the isEditable button and it's associated label as a child of 635 * parent using the editableValue of the receiver. The Composite will be the 636 * parent of the button. 637 * 638 * @param composite 639 * the parent of the button 640 */ createEditableButton(Composite composite)641 private void createEditableButton(Composite composite) { 642 643 this.editableBox = new Button(composite, SWT.CHECK | SWT.RIGHT); 644 this.editableBox.setAlignment(SWT.LEFT); 645 this.editableBox.setText(READ_ONLY); 646 this.editableBox.setSelection(this.previousReadOnlyValue); 647 } 648 649 /** 650 * Create the isExecutable button and it's associated label as a child of 651 * parent using the editableValue of the receiver. The Composite will be the 652 * parent of the button. 653 * 654 * @param composite 655 * the parent of the button 656 */ createExecutableButton(Composite composite)657 private void createExecutableButton(Composite composite) { 658 659 this.executableBox = new Button(composite, SWT.CHECK | SWT.RIGHT); 660 this.executableBox.setAlignment(SWT.LEFT); 661 this.executableBox.setText(EXECUTABLE); 662 this.executableBox.setSelection(this.previousExecutableValue); 663 } 664 665 /** 666 * Create the isLocked button and it's associated label as a child of 667 * parent using the editableValue of the receiver. The Composite will be the 668 * parent of the button. 669 * 670 * @param composite 671 * the parent of the button 672 */ createImmutableButton(Composite composite)673 private void createImmutableButton(Composite composite) { 674 this.immutableBox = new Button(composite, SWT.CHECK | SWT.RIGHT); 675 this.immutableBox.setAlignment(SWT.LEFT); 676 this.immutableBox.setText(LOCKED); 677 this.immutableBox.setSelection((this.previousPermissionsValue & EFS.ATTRIBUTE_IMMUTABLE) != 0); 678 } 679 680 /** 681 * Create the isArchive button and it's associated label as a child of 682 * parent using the editableValue of the receiver. The Composite will be the 683 * parent of the button. 684 * 685 * @param composite 686 * the parent of the button 687 */ createArchiveButton(Composite composite)688 private void createArchiveButton(Composite composite) { 689 690 this.archiveBox = new Button(composite, SWT.CHECK | SWT.RIGHT); 691 this.archiveBox.setAlignment(SWT.LEFT); 692 this.archiveBox.setText(ARCHIVE); 693 this.archiveBox.setSelection(this.previousArchiveValue); 694 } 695 696 /** 697 * Create the derived button and it's associated label as a child of parent 698 * using the derived of the receiver. The Composite will be the parent of 699 * the button. 700 * 701 * @param composite 702 * the parent of the button 703 * @param resource 704 * the resource the information is being taken from 705 */ createDerivedButton(Composite composite, IResource resource)706 private void createDerivedButton(Composite composite, IResource resource) { 707 708 this.derivedBox = new Button(composite, SWT.CHECK | SWT.RIGHT); 709 this.derivedBox.setAlignment(SWT.LEFT); 710 if (resource.getParent().isDerived(IResource.CHECK_ANCESTORS)) 711 this.derivedBox.setText(DERIVED_HAS_DERIVED_ANCESTOR); 712 else 713 this.derivedBox.setText(DERIVED); 714 this.derivedBox.setSelection(this.previousDerivedValue); 715 } 716 717 /** 718 * Create a separator that goes across the entire page 719 * 720 * @param composite 721 * The parent of the seperator 722 */ createSeparator(Composite composite)723 private void createSeparator(Composite composite) { 724 725 Label separator = new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL); 726 GridData gridData = new GridData(); 727 gridData.horizontalAlignment = GridData.FILL; 728 gridData.grabExcessHorizontalSpace = true; 729 separator.setLayoutData(gridData); 730 } 731 732 /** 733 * Create the group that shows the read only state and the timestamp. 734 * 735 * @param parent 736 * the composite the group will be created in 737 * @param resource 738 * the resource the information is being taken from. 739 */ createStateGroup(Composite parent, IResource resource, int fsAttributes)740 private void createStateGroup(Composite parent, IResource resource, int fsAttributes) { 741 Font font = parent.getFont(); 742 743 Composite composite = new Composite(parent, SWT.NULL); 744 GridLayout layout = new GridLayout(); 745 layout.numColumns = 1; 746 layout.marginWidth = 0; 747 layout.marginHeight = 0; 748 composite.setLayout(layout); 749 GridData data = new GridData(); 750 data.horizontalAlignment = GridData.FILL; 751 composite.setLayoutData(data); 752 753 Label attributesLabel = new Label(composite, SWT.LEFT); 754 attributesLabel.setText(IDEWorkbenchMessages.ResourceInfo_attributes); 755 756 if (!resource.isVirtual()) { 757 if ((fsAttributes & EFS.ATTRIBUTE_READ_ONLY) != 0 758 && !isPermissionsSupport(fsAttributes)) 759 createEditableButton(composite); 760 if ((fsAttributes & EFS.ATTRIBUTE_EXECUTABLE) != 0 761 && !isPermissionsSupport(fsAttributes)) 762 createExecutableButton(composite); 763 if ((fsAttributes & EFS.ATTRIBUTE_ARCHIVE) != 0) 764 createArchiveButton(composite); 765 if ((fsAttributes & EFS.ATTRIBUTE_IMMUTABLE) != 0) 766 createImmutableButton(composite); 767 } 768 createDerivedButton(composite, resource); 769 // create warning for executable flag 770 if (executableBox != null && resource.getType() == IResource.FOLDER) 771 createExecutableWarning(composite, font); 772 } 773 createPermissionsGroup(Composite parent)774 private void createPermissionsGroup(Composite parent) { 775 Font font = parent.getFont(); 776 777 permissionBoxes = new Button[9]; 778 Composite composite = new Composite(parent, SWT.NULL); 779 GridLayout layout = new GridLayout(); 780 layout.numColumns = 1; 781 layout.marginWidth = 0; 782 layout.marginHeight = 0; 783 composite.setLayout(layout); 784 GridData data = new GridData(); 785 data.horizontalAlignment = GridData.FILL; 786 data.grabExcessHorizontalSpace = true; 787 composite.setLayoutData(data); 788 789 Label permissionsLabel = new Label(composite, SWT.NONE); 790 permissionsLabel.setText(IDEWorkbenchMessages.ResourceInfo_permissions); 791 792 Table table = new Table(composite, SWT.BORDER); 793 table.setHeaderVisible(true); 794 table.setLinesVisible(true); 795 for (int i = 0; i < 4; i++) { 796 new TableColumn(table, SWT.NONE).setResizable(false); 797 } 798 table.getColumn(1).setText(IDEWorkbenchMessages.ResourceInfo_read); 799 table.getColumn(2).setText(IDEWorkbenchMessages.ResourceInfo_write); 800 table.getColumn(3).setText(IDEWorkbenchMessages.ResourceInfo_execute); 801 802 table.getColumn(3).pack(); 803 int columnWidth = table.getColumn(3).getWidth(); 804 table.getColumn(0).setWidth(columnWidth); 805 table.getColumn(1).setWidth(columnWidth); 806 table.getColumn(2).setWidth(columnWidth); 807 808 TableItem ownerItem = new TableItem(table, SWT.NONE); 809 ownerItem.setText(IDEWorkbenchMessages.ResourceInfo_owner); 810 permissionBoxes[0] = createPermissionEditor(table, ownerItem, 1); 811 permissionBoxes[1] = createPermissionEditor(table, ownerItem, 2); 812 permissionBoxes[2] = createPermissionEditor(table, ownerItem, 3); 813 814 TableItem groupItem = new TableItem(table, SWT.NONE); 815 groupItem.setText(IDEWorkbenchMessages.ResourceInfo_group); 816 permissionBoxes[3] = createPermissionEditor(table, groupItem, 1); 817 permissionBoxes[4] = createPermissionEditor(table, groupItem, 2); 818 permissionBoxes[5] = createPermissionEditor(table, groupItem, 3); 819 820 TableItem otherItem = new TableItem(table, SWT.NONE); 821 otherItem.setText(IDEWorkbenchMessages.ResourceInfo_other); 822 permissionBoxes[6] = createPermissionEditor(table, otherItem, 1); 823 permissionBoxes[7] = createPermissionEditor(table, otherItem, 2); 824 permissionBoxes[8] = createPermissionEditor(table, otherItem, 3); 825 826 GridData tableData = new GridData(); 827 tableData.heightHint = table.getHeaderHeight() + 3 * table.getItemHeight(); 828 table.setLayoutData(tableData); 829 createExecutableWarning(composite, font); 830 } 831 createPermissionEditor(Table table, TableItem item, int index)832 private Button createPermissionEditor(Table table, TableItem item, int index) { 833 Button button = new Button(table, SWT.CHECK); 834 button.pack(); 835 TableEditor editor = new TableEditor(table); 836 editor.grabVertical = true; 837 editor.verticalAlignment = SWT.CENTER; 838 editor.minimumWidth = button.getSize().x; 839 editor.setEditor(button, item, index); 840 editor.getEditor(); 841 return button; 842 } 843 createExecutableWarning(Composite composite, Font font)844 private Composite createExecutableWarning(Composite composite, Font font) { 845 Composite noteComposite = createNoteComposite(font, composite, 846 IDEWorkbenchMessages.Preference_note, 847 IDEWorkbenchMessages.ResourceInfo_exWarning); 848 GridData data = new GridData(); 849 data.widthHint = convertWidthInCharsToPixels(IDEWorkbenchMessages.ResourceInfo_exWarning.length()); 850 data.grabExcessHorizontalSpace = true; 851 data.horizontalAlignment = GridData.FILL; 852 noteComposite.setLayoutData(data); 853 return noteComposite; 854 } 855 getFileSystemAttributes(IResource resource)856 private int getFileSystemAttributes(IResource resource) { 857 URI location = resource.getLocationURI(); 858 if (location == null || location.getScheme() == null) 859 return 0; 860 IFileSystem fs; 861 try { 862 fs = EFS.getFileSystem(location.getScheme()); 863 } catch (CoreException e) { 864 return 0; 865 } 866 return fs.attributes(); 867 } 868 isPermissionsSupport(int fsAttributes)869 private boolean isPermissionsSupport(int fsAttributes) { 870 int unixPermissions = EFS.ATTRIBUTE_OWNER_READ 871 | EFS.ATTRIBUTE_OWNER_WRITE | EFS.ATTRIBUTE_OWNER_EXECUTE 872 | EFS.ATTRIBUTE_GROUP_READ | EFS.ATTRIBUTE_GROUP_WRITE 873 | EFS.ATTRIBUTE_GROUP_EXECUTE | EFS.ATTRIBUTE_OTHER_READ 874 | EFS.ATTRIBUTE_OTHER_WRITE | EFS.ATTRIBUTE_OTHER_EXECUTE; 875 if ((fsAttributes & unixPermissions) == unixPermissions) 876 return true; 877 return false; 878 } 879 getContentDescription(IResource resource)880 private IContentDescription getContentDescription(IResource resource) { 881 if (resource.getType() != IResource.FILE) { 882 return null; 883 } 884 885 if (cachedContentDescription == null) { 886 try { 887 cachedContentDescription = ((IFile) resource) 888 .getContentDescription(); 889 } catch (CoreException e) { 890 // silently ignore 891 } 892 } 893 return cachedContentDescription; 894 } 895 896 /* 897 * @see PreferencePage#performDefaults() 898 */ 899 @Override performDefaults()900 protected void performDefaults() { 901 902 IResource resource = Adapters.adapt(getElement(), IResource.class); 903 904 if (resource == null) 905 return; 906 907 if (newResourceLocation != null) { 908 newResourceLocation = null; 909 910 resolvedLocationValue.setText(IDEResourceInfoUtils 911 .getResolvedLocationText(resource)); 912 913 String locationStr = TextProcessor.process(IDEResourceInfoUtils 914 .getLocationText(resource)); 915 locationValue.setText(locationStr); 916 917 if (sizeValue != null) 918 sizeValue.setText(IDEResourceInfoUtils.getSizeString(resource)); 919 } 920 921 // Nothing to update if we never made the box 922 if (this.editableBox != null) { 923 this.editableBox.setSelection(false); 924 } 925 926 // Nothing to update if we never made the box 927 if (this.executableBox != null) { 928 this.executableBox.setSelection(false); 929 } 930 931 // Nothing to update if we never made the box 932 if (this.archiveBox != null) { 933 this.archiveBox.setSelection(true); 934 } 935 936 // Nothing to update if we never made the box 937 if (this.immutableBox != null) { 938 this.immutableBox.setSelection(false); 939 } 940 941 // Nothing to update if we never made the box 942 if (this.derivedBox != null) { 943 this.derivedBox.setSelection(false); 944 } 945 946 if (permissionBoxes != null) { 947 int defaultPermissionValues = getDefaulPermissions(resource.getType() == IResource.FOLDER); 948 setPermissionsSelection(defaultPermissionValues); 949 } 950 951 if (encodingEditor != null) { 952 encodingEditor.loadDefault(); 953 } 954 955 if (lineDelimiterEditor != null) { 956 lineDelimiterEditor.loadDefault(); 957 } 958 959 } 960 getSimpleChangeName(boolean isSet, String name)961 private String getSimpleChangeName(boolean isSet, String name) { 962 String message = "\t"; //$NON-NLS-1$ 963 message += isSet ? IDEWorkbenchMessages.ResourceInfo_recursiveChangesSet 964 : IDEWorkbenchMessages.ResourceInfo_recursiveChangesUnset; 965 message += " " + name + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ 966 return message; 967 } 968 getAttributesChange(final boolean changedAttrs[], final boolean finalAttrs[])969 private IResourceChange getAttributesChange(final boolean changedAttrs[], 970 final boolean finalAttrs[]) { 971 return new IResourceChange() { 972 @Override 973 public String getMessage() { 974 String message = ""; //$NON-NLS-1$ 975 if (changedAttrs[0]) 976 message += getSimpleChangeName(finalAttrs[0], 977 IDEWorkbenchMessages.ResourceInfo_readOnly); 978 if (changedAttrs[1]) 979 message += getSimpleChangeName(finalAttrs[1], 980 IDEWorkbenchMessages.ResourceInfo_executable); 981 if (changedAttrs[2]) 982 message += getSimpleChangeName(finalAttrs[2], 983 IDEWorkbenchMessages.ResourceInfo_archive); 984 return message; 985 } 986 987 @Override 988 public void performChange(IResource resource) throws CoreException { 989 ResourceAttributes attrs = resource.getResourceAttributes(); 990 if (attrs != null) { 991 if (changedAttrs[0]) 992 attrs.setReadOnly(finalAttrs[0]); 993 if (changedAttrs[1]) 994 attrs.setExecutable(finalAttrs[1]); 995 if (changedAttrs[2]) 996 attrs.setArchive(finalAttrs[2]); 997 resource.setResourceAttributes(attrs); 998 } 999 } 1000 }; 1001 } 1002 1003 private IResourceChange getPermissionsChange(final int changedPermissions, 1004 final int finalPermissions) { 1005 return new IResourceChange() { 1006 @Override 1007 public String getMessage() { 1008 // iterated with [j][i] 1009 int permissionMasks[][] = new int[][] { 1010 { EFS.ATTRIBUTE_OWNER_READ, EFS.ATTRIBUTE_OWNER_WRITE, 1011 EFS.ATTRIBUTE_OWNER_EXECUTE }, 1012 { EFS.ATTRIBUTE_GROUP_READ, EFS.ATTRIBUTE_GROUP_WRITE, 1013 EFS.ATTRIBUTE_GROUP_EXECUTE }, 1014 { EFS.ATTRIBUTE_OTHER_READ, EFS.ATTRIBUTE_OTHER_WRITE, 1015 EFS.ATTRIBUTE_OTHER_EXECUTE } }; 1016 // iterated with [j] 1017 String groupNames[] = new String[] { 1018 IDEWorkbenchMessages.ResourceInfo_owner, 1019 IDEWorkbenchMessages.ResourceInfo_group, 1020 IDEWorkbenchMessages.ResourceInfo_other }; 1021 // iterated with [i] 1022 String permissionNames[] = new String[] { 1023 IDEWorkbenchMessages.ResourceInfo_read, 1024 IDEWorkbenchMessages.ResourceInfo_write, 1025 IDEWorkbenchMessages.ResourceInfo_execute }; 1026 1027 StringBuilder message = new StringBuilder(""); //$NON-NLS-1$ 1028 if ((changedPermissions & EFS.ATTRIBUTE_IMMUTABLE) != 0) 1029 message.append(getSimpleChangeName( 1030 (finalPermissions & EFS.ATTRIBUTE_IMMUTABLE) != 0, 1031 IDEWorkbenchMessages.ResourceInfo_locked)); 1032 1033 for (int j = 0; j < 3; j++) { 1034 for (int i = 0; i < 3; i++) { 1035 if ((changedPermissions & permissionMasks[j][i]) != 0) 1036 message.append(getSimpleChangeName( 1037 (finalPermissions & permissionMasks[j][i]) != 0, 1038 groupNames[j] + " " + permissionNames[i])); //$NON-NLS-1$ 1039 } 1040 } 1041 return message.toString(); 1042 } 1043 1044 @Override 1045 public void performChange(IResource resource) { 1046 int permissions = fetchPermissions(resource); 1047 // add permissions 1048 permissions |= changedPermissions & finalPermissions; 1049 // remove permissions 1050 permissions &= ~changedPermissions | finalPermissions; 1051 putPermissions(resource, permissions); 1052 } 1053 }; 1054 } 1055 1056 private List/*<IResource>*/ getResourcesToVisit(IResource resource) throws CoreException { 1057 // use set for fast lookup 1058 final Set/*<URI>*/ visited = new HashSet/*<URI>*/(); 1059 // use list to preserve the order of visited resources 1060 final List/*<IResource>*/ toVisit = new ArrayList/*<IResource>*/(); 1061 visited.add(resource.getLocationURI()); 1062 resource.accept(proxy -> { 1063 IResource childResource = proxy.requestResource(); 1064 URI uri = childResource.getLocationURI(); 1065 if (!visited.contains(uri)) { 1066 visited.add(uri); 1067 toVisit.add(childResource); 1068 } 1069 return true; 1070 }, IResource.NONE); 1071 return toVisit; 1072 } 1073 1074 private boolean shouldPerformRecursiveChanges(List/*<IResourceChange>*/ changes) { 1075 if (!changes.isEmpty()) { 1076 StringBuilder message = new StringBuilder(IDEWorkbenchMessages.ResourceInfo_recursiveChangesSummary) 1077 .append('\n'); 1078 for (Object change : changes) { 1079 message.append(((IResourceChange) change).getMessage()); 1080 } 1081 message.append(IDEWorkbenchMessages.ResourceInfo_recursiveChangesQuestion); 1082 1083 MessageDialog dialog = new MessageDialog(getShell(), 1084 IDEWorkbenchMessages.ResourceInfo_recursiveChangesTitle, 1085 null, message.toString(), MessageDialog.QUESTION, 1, 1086 IDialogConstants.YES_LABEL, 1087 IDialogConstants.NO_LABEL); 1088 1089 return dialog.open() == 0; 1090 } 1091 return false; 1092 } 1093 1094 private void scheduleRecursiveChangesJob(final IResource resource, final List/*<IResourceChange>*/ changes) { 1095 Job.create(IDEWorkbenchMessages.ResourceInfo_recursiveChangesJobName, monitor -> { 1096 try { 1097 List/*<IResource>*/ toVisit = getResourcesToVisit(resource); 1098 1099 // Prepare the monitor for the given amount of work 1100 SubMonitor subMonitor = SubMonitor.convert(monitor, 1101 IDEWorkbenchMessages.ResourceInfo_recursiveChangesJobName, 1102 toVisit.size()); 1103 1104 // Apply changes recursively 1105 for (Iterator/*<IResource>*/ it = toVisit.iterator(); it.hasNext();) { 1106 SubMonitor iterationMonitor = subMonitor.split(1).setWorkRemaining(changes.size()); 1107 IResource childResource = (IResource) it.next(); 1108 iterationMonitor.subTask(NLS 1109 .bind(IDEWorkbenchMessages.ResourceInfo_recursiveChangesSubTaskName, 1110 childResource.getFullPath())); 1111 for (Object change : changes) { 1112 iterationMonitor.split(1); 1113 ((IResourceChange) change) 1114 .performChange(childResource); 1115 } 1116 } 1117 } catch (CoreException e1) { 1118 IDEWorkbenchPlugin 1119 .log(IDEWorkbenchMessages.ResourceInfo_recursiveChangesError, 1120 e1.getStatus()); 1121 return e1.getStatus(); 1122 } catch (OperationCanceledException e2) { 1123 return Status.CANCEL_STATUS; 1124 } 1125 return Status.OK_STATUS; 1126 }).schedule(); 1127 } 1128 1129 /** 1130 * Apply the read only state and the encoding to the resource. 1131 */ 1132 @Override 1133 public boolean performOk() { 1134 1135 IResource resource = Adapters.adapt(getElement(), IResource.class); 1136 1137 if (resource == null) 1138 return true; 1139 1140 if (lineDelimiterEditor != null) { 1141 lineDelimiterEditor.store(); 1142 } 1143 1144 try { 1145 if (newResourceLocation != null) { 1146 if (resource.getType() == IResource.FILE) 1147 ((IFile)resource).createLink(newResourceLocation, IResource.REPLACE, 1148 new NullProgressMonitor()); 1149 if (resource.getType() == IResource.FOLDER) 1150 ((IFolder)resource).createLink(newResourceLocation, IResource.REPLACE, 1151 new NullProgressMonitor()); 1152 } 1153 1154 List/*<IResourceChange>*/ changes = new ArrayList/*<IResourceChange>*/(); 1155 1156 ResourceAttributes attrs = resource.getResourceAttributes(); 1157 if (attrs != null) { 1158 boolean finalValues[] = new boolean[] { false, false, false }; 1159 boolean changedAttrs[] = new boolean[] { false, false, false }; 1160 // Nothing to update if we never made the box 1161 if (editableBox != null 1162 && editableBox.getSelection() != previousReadOnlyValue) { 1163 attrs.setReadOnly(editableBox.getSelection()); 1164 finalValues[0] = editableBox.getSelection(); 1165 changedAttrs[0] = true; 1166 } 1167 if (executableBox != null 1168 && executableBox.getSelection() != previousExecutableValue) { 1169 attrs.setExecutable(executableBox.getSelection()); 1170 finalValues[1] = executableBox.getSelection(); 1171 changedAttrs[1] = true; 1172 } 1173 if (archiveBox != null 1174 && archiveBox.getSelection() != previousArchiveValue) { 1175 attrs.setArchive(archiveBox.getSelection()); 1176 finalValues[2] = archiveBox.getSelection(); 1177 changedAttrs[2] = true; 1178 } 1179 if (changedAttrs[0] || changedAttrs[1] || changedAttrs[2]) { 1180 resource.setResourceAttributes(attrs); 1181 attrs = resource.getResourceAttributes(); 1182 if (attrs != null) { 1183 previousReadOnlyValue = attrs.isReadOnly(); 1184 previousExecutableValue = attrs.isExecutable(); 1185 previousArchiveValue = attrs.isArchive(); 1186 if (editableBox != null) { 1187 editableBox.setSelection(attrs.isReadOnly()); 1188 } 1189 if (executableBox != null) { 1190 executableBox.setSelection(attrs.isExecutable()); 1191 } 1192 if (archiveBox != null) { 1193 archiveBox.setSelection(attrs.isArchive()); 1194 } 1195 if (resource.getType() == IResource.FOLDER) { 1196 changes.add(getAttributesChange(changedAttrs, 1197 finalValues)); 1198 } 1199 } 1200 } 1201 } 1202 1203 if (permissionBoxes != null) { 1204 int permissionValues = getPermissionsSelection(); 1205 if (previousPermissionsValue != permissionValues) { 1206 int changedPermissions = previousPermissionsValue ^ permissionValues; 1207 putPermissions(resource, permissionValues); 1208 previousPermissionsValue = fetchPermissions(resource); 1209 if (previousPermissionsValue != permissionValues) { 1210 // We failed to set some of the permissions 1211 setPermissionsSelection(previousPermissionsValue); 1212 } 1213 if (resource.getType() == IResource.FOLDER) { 1214 changes.add(getPermissionsChange(changedPermissions, 1215 permissionValues)); 1216 } 1217 } 1218 } 1219 1220 if (shouldPerformRecursiveChanges(changes)) 1221 scheduleRecursiveChangesJob(resource, changes); 1222 1223 // Nothing to update if we never made the box 1224 if (this.derivedBox != null) { 1225 boolean localDerivedValue = derivedBox.getSelection(); 1226 if (previousDerivedValue != localDerivedValue) { 1227 resource.setDerived(localDerivedValue, null); 1228 boolean isDerived = resource.isDerived(); 1229 previousDerivedValue = isDerived; 1230 derivedBox.setSelection(isDerived); 1231 } 1232 } 1233 } catch (CoreException exception) { 1234 ErrorDialog.openError(getShell(), 1235 IDEWorkbenchMessages.InternalError, exception 1236 .getLocalizedMessage(), exception.getStatus()); 1237 return false; 1238 } finally { 1239 // This must be invoked after the 'derived' property has been set, 1240 // because it may influence the place where encoding is stored. 1241 if (encodingEditor != null) { 1242 encodingEditor.store(); 1243 } 1244 } 1245 return true; 1246 } 1247 } 1248