1 /******************************************************************************* 2 * Copyright (c) 2000, 2017 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.team.internal.ui.preferences; 15 16 import java.util.ArrayList; 17 import java.util.HashSet; 18 import java.util.Iterator; 19 import java.util.List; 20 import java.util.Set; 21 22 import org.eclipse.jface.dialogs.Dialog; 23 import org.eclipse.jface.dialogs.IInputValidator; 24 import org.eclipse.jface.dialogs.InputDialog; 25 import org.eclipse.jface.dialogs.MessageDialog; 26 import org.eclipse.jface.preference.PreferencePage; 27 import org.eclipse.jface.util.PropertyChangeEvent; 28 import org.eclipse.jface.viewers.ISelection; 29 import org.eclipse.jface.viewers.IStructuredSelection; 30 import org.eclipse.jface.window.Window; 31 import org.eclipse.swt.SWT; 32 import org.eclipse.swt.layout.GridData; 33 import org.eclipse.swt.widgets.Button; 34 import org.eclipse.swt.widgets.Composite; 35 import org.eclipse.swt.widgets.Control; 36 import org.eclipse.team.core.IFileContentManager; 37 import org.eclipse.team.core.IStringMapping; 38 import org.eclipse.team.core.Team; 39 import org.eclipse.team.internal.ui.IHelpContextIds; 40 import org.eclipse.team.internal.ui.PixelConverter; 41 import org.eclipse.team.internal.ui.SWTUtils; 42 import org.eclipse.team.internal.ui.TeamUIMessages; 43 import org.eclipse.team.internal.ui.TeamUIPlugin; 44 import org.eclipse.team.internal.ui.preferences.FileTypeTable.Item; 45 import org.eclipse.team.ui.TeamUI; 46 import org.eclipse.ui.IWorkbench; 47 import org.eclipse.ui.IWorkbenchPreferencePage; 48 import org.eclipse.ui.PlatformUI; 49 /** 50 * This preference page displays all patterns which determine whether a resource 51 * is to be treated as a text file or not. The page allows the user to add or 52 * remove entries from this table, and change their values from Text to Binary. 53 */ 54 public class TextPreferencePage extends PreferencePage implements IWorkbenchPreferencePage { 55 56 private static final class ExtensionValidator implements IInputValidator { 57 @Override isValid(String newText)58 public String isValid(String newText) { 59 if (newText.trim().length() == 0) 60 return ""; //$NON-NLS-1$ 61 if (!isComplete(newText)){ 62 return TeamUIMessages.TextPreferencePage_ExtensionNotCompleted; 63 } 64 newText = strip(newText); 65 if (newText.indexOf('*') >= 0) 66 return TeamUIMessages.TextPreferencePage_2; 67 if (newText.indexOf('.') >= 0) 68 return TeamUIMessages.TextPreferencePage_3; 69 return null; 70 } 71 72 /** 73 * @param newText 74 * @return the text 75 */ strip(String newText)76 public String strip(String newText) { 77 newText= newText.trim(); 78 if (newText.startsWith("*")) //$NON-NLS-1$ 79 newText= newText.substring(1); 80 if (newText.startsWith(".")) //$NON-NLS-1$ 81 newText= newText.substring(1); 82 return newText; 83 } 84 isComplete(String text)85 public boolean isComplete(String text){ 86 //Allowed formats of extension are: 87 // extension 88 // .extension 89 // *.extension 90 if (text.equals("*") || text.equals("*.") || text.equals(".")){ //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ 91 return false; 92 } 93 return true; 94 } 95 } 96 97 private static final class FilenameValidator implements IInputValidator { 98 @Override isValid(String newText)99 public String isValid(String newText) { 100 if (newText.trim().length() == 0) 101 return ""; //$NON-NLS-1$ 102 if (newText.indexOf('*') >= 0) 103 return TeamUIMessages.TextPreferencePage_5; 104 return null; 105 } 106 } 107 108 // The input for the table viewer 109 private final List<Item> fItems; 110 111 // Widgets 112 private Button fRemoveButton; 113 private Button fChangeButton; 114 115 protected FileTypeTable fTable; 116 TextPreferencePage()117 public TextPreferencePage() { 118 fItems= new ArrayList<>(); 119 initializeItems(); 120 } 121 initializeItems()122 private void initializeItems() { 123 124 fItems.clear(); 125 126 final IFileContentManager manager= Team.getFileContentManager(); 127 128 final IStringMapping [] extensionInfoArray= manager.getExtensionMappings(); 129 final IStringMapping [] nameInfoArray= manager.getNameMappings(); 130 131 Set fPluginNames= makeSetOfStrings(manager.getDefaultNameMappings()); 132 Set fPluginExtensions= makeSetOfStrings(manager.getDefaultExtensionMappings()); 133 134 for (IStringMapping info : extensionInfoArray) { 135 final FileTypeTable.Extension extension= new FileTypeTable.Extension(info.getString(), fPluginExtensions.contains(info.getString())); 136 extension.mode= info.getType(); 137 fItems.add(extension); 138 } 139 for (IStringMapping info : nameInfoArray) { 140 final FileTypeTable.Name name= new FileTypeTable.Name(info.getString(), fPluginNames.contains(info.getString())); 141 name.mode= info.getType(); 142 fItems.add(name); 143 } 144 145 } 146 makeSetOfStrings(IStringMapping [] mappings)147 private static Set<String> makeSetOfStrings(IStringMapping [] mappings) { 148 final Set<String> set= new HashSet<>(mappings.length); 149 for (IStringMapping mapping : mappings) { 150 set.add(mapping.getString()); 151 } 152 return set; 153 } 154 155 @Override init(IWorkbench workbench)156 public void init(IWorkbench workbench) { 157 } 158 159 @Override createContents(Composite parent)160 protected Control createContents(Composite parent) { 161 162 initializeDialogUnits(parent); 163 164 final PixelConverter converter= SWTUtils.createDialogPixelConverter(parent); 165 166 final Composite composite= SWTUtils.createHVFillComposite(parent, SWTUtils.MARGINS_NONE, 2); 167 168 fTable= new FileTypeTable(composite, fItems, false); 169 170 fTable.getViewer().getControl().addListener(SWT.Selection, e -> handleSelection()); 171 172 fTable.getViewer().addDoubleClickListener(event -> { 173 final ISelection selection = event.getSelection(); 174 if (selection == null || !(selection instanceof IStructuredSelection)) { 175 return; 176 } 177 fTable.getViewer().editElement(((IStructuredSelection)selection).getFirstElement(), 1); 178 }); 179 180 final Composite buttonsComposite = new Composite(composite, SWT.NONE); 181 buttonsComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); 182 buttonsComposite.setLayout(SWTUtils.createGridLayout(1, converter, SWTUtils.MARGINS_NONE)); 183 184 final Button addExtensionButton = new Button(buttonsComposite, SWT.PUSH); 185 addExtensionButton.setText(TeamUIMessages.TextPreferencePage_add); 186 final Button addNameButton = new Button(buttonsComposite, SWT.PUSH); 187 addNameButton.setText(TeamUIMessages.TextPreferencePage_0); 188 fChangeButton = new Button(buttonsComposite, SWT.PUSH); 189 fChangeButton.setText(TeamUIMessages.TextPreferencePage_change); 190 fRemoveButton= new Button(buttonsComposite, SWT.PUSH); 191 fRemoveButton.setText(TeamUIMessages.TextPreferencePage_remove); 192 193 SWTUtils.createLabel(composite, TeamUIMessages.TextPreferencePage_1, 2); 194 195 /** 196 * Calculate and set the button size 197 */ 198 applyDialogFont(composite); 199 final int buttonWidth= SWTUtils.calculateControlSize(converter, new Button [] { addExtensionButton, addNameButton, fChangeButton, fRemoveButton }); 200 addExtensionButton.setLayoutData(SWTUtils.createGridData(buttonWidth, SWT.DEFAULT, SWT.FILL, SWT.FILL, false, false)); 201 addNameButton.setLayoutData(SWTUtils.createGridData(buttonWidth, SWT.DEFAULT, SWT.FILL, SWT.FILL, false, false)); 202 fChangeButton.setLayoutData(SWTUtils.createGridData(buttonWidth, SWT.DEFAULT, SWT.FILL, SWT.FILL, false, false)); 203 fRemoveButton.setLayoutData(SWTUtils.createGridData(buttonWidth, SWT.DEFAULT, SWT.FILL, SWT.FILL, false, false)); 204 205 addExtensionButton.addListener(SWT.Selection, e -> addExtension()); 206 addNameButton.addListener(SWT.Selection, e -> addName()); 207 208 fChangeButton.setEnabled(false); 209 fChangeButton.addListener(SWT.Selection, e -> changePattern()); 210 211 fRemoveButton.setEnabled(false); 212 fRemoveButton.addListener(SWT.Selection, e -> removePattern()); 213 214 Dialog.applyDialogFont(parent); 215 216 // set F1 help 217 PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IHelpContextIds.FILE_TYPE_PREFERENCE_PAGE); 218 219 return composite; 220 } 221 222 @Override performDefaults()223 protected void performDefaults() { 224 super.performDefaults(); 225 initializeItems(); 226 if (fTable != null) 227 fTable.getViewer().refresh(); 228 } 229 230 /** 231 * Do anything necessary because the OK button has been pressed. 232 * 233 * @return whether it is okay to close the preference page 234 */ 235 @Override performOk()236 public boolean performOk() { 237 final ArrayList<String> extensionsList= new ArrayList<>(); 238 final ArrayList<Integer> extensionsModesList= new ArrayList<>(); 239 240 final ArrayList<String> namesList= new ArrayList<>(); 241 final ArrayList<Integer> namesModesList= new ArrayList<>(); 242 243 for (Object element : fItems) { 244 final FileTypeTable.Item item= (FileTypeTable.Item) element; 245 246 if (item instanceof FileTypeTable.Extension) { 247 extensionsList.add(item.name); 248 extensionsModesList.add(Integer.valueOf(item.mode)); 249 } else if (item instanceof FileTypeTable.Name) { 250 namesList.add(item.name); 251 namesModesList.add(Integer.valueOf(item.mode)); 252 } 253 } 254 255 final String [] extensions= extensionsList.toArray(new String [extensionsList.size()]); 256 final String [] names= namesList.toArray(new String [namesList.size()]); 257 258 final int [] extensionsModes= integerListToIntArray(extensionsModesList); 259 final int [] namesModes= integerListToIntArray(namesModesList); 260 261 Team.getFileContentManager().setExtensionMappings(extensions, extensionsModes); 262 Team.getFileContentManager().setNameMappings(names, namesModes); 263 264 TeamUIPlugin.broadcastPropertyChange(new PropertyChangeEvent(this, TeamUI.GLOBAL_FILE_TYPES_CHANGED, null, null)); 265 266 return true; 267 } 268 integerListToIntArray(List integers)269 private static int [] integerListToIntArray(List integers) { 270 final int [] array= new int [integers.size()]; 271 int index= 0; 272 for (Iterator iter = integers.iterator(); iter.hasNext();) 273 array[index++]= ((Integer)iter.next()).intValue(); 274 return array; 275 } 276 277 /** 278 * Add a new item to the table with the default type of Text. 279 */ addExtension()280 void addExtension() { 281 final ExtensionValidator validator = new ExtensionValidator(); 282 final InputDialog dialog = new InputDialog(getShell(), TeamUIMessages.TextPreferencePage_enterExtensionShort, TeamUIMessages.TextPreferencePage_enterExtensionLong, null, validator); // 283 if (dialog.open() != Window.OK) 284 return; 285 286 final String extension = validator.strip(dialog.getValue()); 287 288 // Check if the item already exists 289 final Iterator it = fItems.iterator(); 290 while (it.hasNext()) { 291 final FileTypeTable.Item item= (FileTypeTable.Item)it.next(); 292 if (item instanceof FileTypeTable.Extension && item.name.equals(extension)) { 293 MessageDialog.openWarning(getShell(), TeamUIMessages.TextPreferencePage_extensionExistsShort, TeamUIMessages.TextPreferencePage_extensionExistsLong); // 294 return; 295 } 296 } 297 final FileTypeTable.Item item= new FileTypeTable.Extension(extension, false); 298 fItems.add(item); 299 fTable.getViewer().refresh(); 300 } 301 302 /** 303 * Add a new item to the table with the default type of Text. 304 */ addName()305 void addName() { 306 final InputDialog dialog = new InputDialog(getShell(), TeamUIMessages.TextPreferencePage_6, TeamUIMessages.TextPreferencePage_7, null, new FilenameValidator()); // 307 if (dialog.open() != Window.OK) 308 return; 309 310 final String name = dialog.getValue(); 311 312 // Check if the item already exists 313 final Iterator it = fItems.iterator(); 314 while (it.hasNext()) { 315 final FileTypeTable.Item item= (FileTypeTable.Item)it.next(); 316 if (item instanceof FileTypeTable.Name && item.name.equals(name)) { 317 MessageDialog.openWarning(getShell(), TeamUIMessages.TextPreferencePage_extensionExistsShort, TeamUIMessages.TextPreferencePage_extensionExistsLong); // 318 return; 319 } 320 } 321 final FileTypeTable.Item item= new FileTypeTable.Name(name, false); 322 fItems.add(item); 323 fTable.getViewer().refresh(); 324 } 325 326 /** 327 * Remove the selected items from the table 328 */ removePattern()329 void removePattern() { 330 final IStructuredSelection selection = fTable.getSelection(); 331 if (selection == null) 332 return; 333 334 for (final Iterator it = selection.iterator(); it.hasNext(); ) { 335 final FileTypeTable.Item item= (FileTypeTable.Item)it.next(); 336 if (item.contributed) 337 continue; 338 fItems.remove(item); 339 } 340 fTable.getViewer().refresh(); 341 handleSelection(); 342 } 343 /** 344 * Toggle the selected items' content types 345 */ changePattern()346 void changePattern() { 347 final IStructuredSelection selection = fTable.getSelection(); 348 if (selection == null) 349 return; 350 351 for (final Iterator it = selection.iterator(); it.hasNext(); ) { 352 final FileTypeTable.Item item= (FileTypeTable.Item)it.next(); 353 item.mode= item.mode == Team.TEXT ? Team.BINARY : Team.TEXT; 354 fTable.getViewer().refresh(item); 355 } 356 } 357 358 /** 359 * The table viewer selection has changed. Update the remove and change button enablement. 360 */ handleSelection()361 void handleSelection() { 362 final boolean empty = fTable.getSelection().isEmpty(); 363 FileTypeTable.Item selectedItem = (Item) fTable.getSelection().getFirstElement(); 364 365 fRemoveButton.setEnabled(!empty && !selectedItem.contributed); 366 fChangeButton.setEnabled(!empty); 367 } 368 } 369