1 /******************************************************************************* 2 * Copyright (c) 2000, 2018 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 *******************************************************************************/ 14 package org.eclipse.ui.internal.editors.text; 15 16 import java.util.ArrayList; 17 import java.util.Arrays; 18 import java.util.HashSet; 19 import java.util.Hashtable; 20 import java.util.Iterator; 21 import java.util.List; 22 import java.util.Map; 23 24 import org.eclipse.swt.SWT; 25 import org.eclipse.swt.custom.BusyIndicator; 26 import org.eclipse.swt.events.SelectionAdapter; 27 import org.eclipse.swt.events.SelectionEvent; 28 import org.eclipse.swt.events.SelectionListener; 29 import org.eclipse.swt.graphics.Font; 30 import org.eclipse.swt.layout.GridData; 31 import org.eclipse.swt.widgets.Button; 32 import org.eclipse.swt.widgets.Composite; 33 import org.eclipse.swt.widgets.Control; 34 import org.eclipse.swt.widgets.Label; 35 import org.eclipse.swt.widgets.Shell; 36 37 import org.eclipse.core.runtime.CoreException; 38 39 import org.eclipse.core.resources.IContainer; 40 import org.eclipse.core.resources.IResource; 41 import org.eclipse.core.resources.IWorkspaceRoot; 42 import org.eclipse.core.resources.ResourcesPlugin; 43 44 import org.eclipse.jface.dialogs.Dialog; 45 import org.eclipse.jface.dialogs.IDialogConstants; 46 import org.eclipse.jface.layout.GridLayoutFactory; 47 import org.eclipse.jface.viewers.ITreeContentProvider; 48 49 import org.eclipse.ui.dialogs.TypeFilteringDialog; 50 import org.eclipse.ui.model.WorkbenchContentProvider; 51 import org.eclipse.ui.model.WorkbenchLabelProvider; 52 53 54 /** 55 * Dialog for selecting resources. 56 * 57 * @since 3.1 58 */ 59 class SelectResourcesDialog extends Dialog { 60 61 interface IFilter { accept(IResource resource)62 boolean accept(IResource resource); 63 } 64 65 private SelectResourcesBlock fResourceGroup; 66 private List<Object> fAcceptedFileTypes = new ArrayList<>(); 67 private IResource[] fInput; 68 private String fTitle; 69 private String fInstruction; 70 private Label fCountIndication; 71 private IFilter fAcceptableLocationsFilter; 72 73 SelectResourcesDialog(Shell parentShell, String title, String instruction, IFilter acceptableLocationsFilter)74 public SelectResourcesDialog(Shell parentShell, String title, String instruction, IFilter acceptableLocationsFilter) { 75 super(parentShell); 76 fTitle= title; 77 fInstruction= instruction; 78 fAcceptableLocationsFilter= acceptableLocationsFilter; 79 } 80 81 @Override isResizable()82 protected boolean isResizable() { 83 return true; 84 } 85 setInput(IResource[] input)86 public void setInput(IResource[] input) { 87 fInput= input; 88 } 89 refresh()90 public void refresh() { 91 fResourceGroup.refresh(); 92 setSelection(fInput, fAcceptableLocationsFilter); 93 } 94 getSelectedResources()95 public IResource[] getSelectedResources() { 96 List<Object> items= fResourceGroup.getAllCheckedListItems(); 97 return items.toArray(new IResource[items.size()]); 98 } 99 100 @Override configureShell(Shell newShell)101 protected void configureShell(Shell newShell) { 102 super.configureShell(newShell); 103 104 if (fTitle != null) 105 newShell.setText(fTitle); 106 } 107 108 @Override createDialogArea(Composite parent)109 protected Control createDialogArea(Composite parent) { 110 Composite composite= (Composite) super.createDialogArea(parent); 111 Label label= new Label(composite, SWT.LEFT); 112 label.setText(fInstruction); 113 label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 114 115 fResourceGroup= new SelectResourcesBlock(composite, ResourcesPlugin.getWorkspace().getRoot(), getResourceProvider(IResource.FOLDER | IResource.PROJECT), WorkbenchLabelProvider.getDecoratingWorkbenchLabelProvider(), getResourceProvider(IResource.FILE), WorkbenchLabelProvider.getDecoratingWorkbenchLabelProvider(), SWT.NONE, useHeightHint(parent)); 116 fResourceGroup.addCheckStateListener(event -> updateSelectionCount()); 117 118 fCountIndication= new Label(composite, SWT.LEFT); 119 fCountIndication.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 120 121 createSelectionButtonGroup(composite); 122 123 setInitialSelection(); 124 return composite; 125 } 126 useHeightHint(Composite parent)127 private boolean useHeightHint(Composite parent) { 128 int fontHeight= (parent.getFont().getFontData())[0].getHeight(); 129 int displayHeight= parent.getDisplay().getClientArea().height; 130 return (displayHeight / fontHeight) > 50; 131 } 132 getResourceProvider(final int resourceType)133 private ITreeContentProvider getResourceProvider(final int resourceType) { 134 return new WorkbenchContentProvider() { 135 @Override 136 public Object[] getChildren(Object o) { 137 if (o instanceof IWorkspaceRoot) { 138 HashSet<IResource> projects= new HashSet<>(); 139 for (IResource f : fInput) { 140 IResource project = f.getProject(); 141 if ((project.getType() & resourceType) > 0) 142 projects.add(project); 143 } 144 return projects.toArray(); 145 } 146 147 if (o instanceof IContainer) { 148 IResource[] members = null; 149 try { 150 members = ((IContainer) o).members(); 151 } catch (CoreException e) { 152 //just return an empty set of children 153 return new Object[0]; 154 } 155 156 //filter out the desired resource types 157 ArrayList<IResource> results = new ArrayList<>(); 158 for (IResource member : members) { 159 //And the test bits with the resource types to see if they are what we want 160 if ((member.getType() & resourceType) > 0 && (resourceType != IResource.FILE || fAcceptableLocationsFilter == null || fAcceptableLocationsFilter.accept(member))) { 161 results.add(member); 162 } 163 } 164 return results.toArray(); 165 } 166 167 //input element case 168 if (o instanceof ArrayList) 169 return ((ArrayList<?>) o).toArray(); 170 171 return new Object[0]; 172 } 173 }; 174 } 175 176 protected Composite createSelectionButtonGroup(Composite parent) { 177 178 Font font= parent.getFont(); 179 180 // top level group 181 Composite buttonComposite= new Composite(parent, SWT.NONE); 182 buttonComposite.setFont(parent.getFont()); 183 184 buttonComposite.setLayout(GridLayoutFactory.fillDefaults().numColumns(0).equalWidth(true).create()); 185 186 Button selectButton= createButton(buttonComposite, IDialogConstants.SELECT_ALL_ID, TextEditorMessages.SelectResourcesDialog_selectAll, false); 187 188 SelectionListener listener= new SelectionAdapter() { 189 @Override 190 public void widgetSelected(SelectionEvent e) { 191 fResourceGroup.setAllSelections(true); 192 updateSelectionCount(); 193 } 194 }; 195 selectButton.addSelectionListener(listener); 196 selectButton.setFont(font); 197 setButtonLayoutData(selectButton); 198 199 Button deselectButton= createButton(buttonComposite, IDialogConstants.DESELECT_ALL_ID, TextEditorMessages.SelectResourcesDialog_deselectAll, false); 200 201 listener= new SelectionAdapter() { 202 @Override 203 public void widgetSelected(SelectionEvent e) { 204 fResourceGroup.setAllSelections(false); 205 updateSelectionCount(); 206 } 207 }; 208 deselectButton.addSelectionListener(listener); 209 deselectButton.setFont(font); 210 setButtonLayoutData(deselectButton); 211 212 // types edit button 213 Button selectTypesButton= createButton(buttonComposite, IDialogConstants.SELECT_TYPES_ID, TextEditorMessages.SelectResourcesDialog_filterSelection, false); 214 215 listener= new SelectionAdapter() { 216 @Override 217 public void widgetSelected(SelectionEvent e) { 218 handleSelectFileTypes(); 219 } 220 }; 221 selectTypesButton.addSelectionListener(listener); 222 selectTypesButton.setFont(font); 223 setButtonLayoutData(selectTypesButton); 224 225 return buttonComposite; 226 } 227 228 protected void handleSelectFileTypes() { 229 Object[] acceptedFileTypes= queryFileTypes(); 230 if (acceptedFileTypes != null) { 231 fAcceptedFileTypes= Arrays.asList(acceptedFileTypes); 232 filterSelection(); 233 } 234 } 235 236 protected Object[] queryFileTypes() { 237 TypeFilteringDialog dialog= new TypeFilteringDialog(getShell(), fAcceptedFileTypes); 238 dialog.open(); 239 return dialog.getResult(); 240 } 241 242 private void filterSelection() { 243 244 final IFilter filter= this::hasAcceptedFileType; 245 246 List<Object> list= fResourceGroup.getAllWhiteCheckedItems(); 247 final IResource[] resources= list.toArray(new IResource[list.size()]); 248 249 Runnable runnable= () -> setSelection(resources, filter); 250 251 BusyIndicator.showWhile(getShell().getDisplay(), runnable); 252 } 253 254 protected boolean hasAcceptedFileType(IResource resource) { 255 if (fAcceptedFileTypes == null) 256 return true; 257 258 String resourceName= resource.getName(); 259 int separatorIndex= resourceName.lastIndexOf("."); //$NON-NLS-1$ 260 if (separatorIndex == -1) 261 return false; 262 263 String extension= resourceName.substring(separatorIndex + 1); 264 265 Iterator<Object> e= fAcceptedFileTypes.iterator(); 266 while (e.hasNext()) { 267 if (extension.equalsIgnoreCase((String) e.next())) 268 return true; 269 } 270 271 return false; 272 } 273 274 protected void setInitialSelection() { 275 setSelection(fInput, fAcceptableLocationsFilter); 276 selectAndReveal(fInput[0]); 277 } 278 279 protected void setSelection(IResource[] input, IFilter filter) { 280 Map<IContainer, List<Object>> selectionMap= new Hashtable<>(); 281 for (IResource resource : input) { 282 if ((resource.getType() & IResource.FILE) > 0) { 283 if (filter.accept(resource)) { 284 List<Object> files= null; 285 IContainer parent= resource.getParent(); 286 if (selectionMap.containsKey(parent)) 287 files= selectionMap.get(parent); 288 else 289 files= new ArrayList<>(); 290 291 files.add(resource); 292 selectionMap.put(parent, files); 293 } 294 } else 295 setSelection(selectionMap, (IContainer) resource, filter); 296 } 297 fResourceGroup.updateSelections(selectionMap); 298 updateSelectionCount(); 299 } 300 301 private void setSelection(Map<IContainer, List<Object>> selectionMap, IContainer parent, IFilter filter) { 302 try { 303 304 IResource[] resources= parent.members(); 305 List<Object> selections= new ArrayList<>(); 306 307 for (IResource resource : resources) { 308 if ((resource.getType() & IResource.FILE) > 0) { 309 if (filter.accept(resource)) 310 selections.add(resource); 311 } else { 312 setSelection(selectionMap, (IContainer) resource, filter); 313 } 314 } 315 316 if (!selections.isEmpty()) 317 selectionMap.put(parent, selections); 318 319 } catch (CoreException x) { 320 //Just return if we can't get any info 321 return; 322 } 323 } 324 325 private void selectAndReveal(IResource resource) { 326 IContainer container= null; 327 if ((IResource.FILE & resource.getType()) > 0) 328 container= resource.getParent(); 329 else 330 container= (IContainer) resource; 331 fResourceGroup.selectAndReveal(container); 332 } 333 334 private void updateSelectionCount() { 335 List<Object> listItems= fResourceGroup.getAllCheckedListItems(); 336 int checkedFiles= listItems.size(); 337 StringBuilder buffer= new StringBuilder(); 338 switch (checkedFiles) { 339 case 0: 340 buffer.append(TextEditorMessages.SelectResourcesDialog_noFilesSelected); 341 break; 342 case 1: 343 buffer.append(TextEditorMessages.SelectResourcesDialog_oneFileSelected); 344 break; 345 default: 346 buffer.append(NLSUtility.format(TextEditorMessages.SelectResourcesDialog_nFilesSelected, Integer.valueOf(checkedFiles))); 347 } 348 fCountIndication.setText(buffer.toString()); 349 350 Button okButton= getButton(IDialogConstants.OK_ID); 351 if (okButton != null) 352 okButton.setEnabled(checkedFiles > 0); 353 } 354 } 355