| /******************************************************************************* |
| * Copyright (c) 2000, 2017 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.compare.internal; |
| |
| import java.io.BufferedReader; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.UnsupportedEncodingException; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.MissingResourceException; |
| import java.util.ResourceBundle; |
| |
| import org.eclipse.compare.CompareConfiguration; |
| import org.eclipse.compare.CompareUI; |
| import org.eclipse.compare.ICompareFilter; |
| import org.eclipse.compare.IEncodedStreamContentAccessor; |
| import org.eclipse.compare.ISharedDocumentAdapter; |
| import org.eclipse.compare.IStreamContentAccessor; |
| import org.eclipse.compare.ITypedElement; |
| import org.eclipse.compare.SharedDocumentAdapter; |
| import org.eclipse.compare.contentmergeviewer.IDocumentRange; |
| import org.eclipse.compare.internal.core.patch.HunkResult; |
| import org.eclipse.compare.internal.patch.PatchMessages; |
| import org.eclipse.compare.patch.IHunk; |
| import org.eclipse.compare.structuremergeviewer.DiffNode; |
| import org.eclipse.compare.structuremergeviewer.ICompareInput; |
| import org.eclipse.core.resources.IEncodedStorage; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.ResourceAttributes; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.resources.mapping.ResourceMapping; |
| import org.eclipse.core.resources.mapping.ResourceMappingContext; |
| import org.eclipse.core.resources.mapping.ResourceTraversal; |
| import org.eclipse.core.runtime.Adapters; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.SafeRunner; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubMonitor; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.dialogs.ErrorDialog; |
| import org.eclipse.jface.operation.IRunnableContext; |
| import org.eclipse.jface.resource.ImageDescriptor; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IRegion; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.swt.custom.BusyIndicator; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Widget; |
| import org.eclipse.ui.IActionBars; |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IViewPart; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.IWorkbenchPartSite; |
| import org.eclipse.ui.IWorkbenchSite; |
| import org.eclipse.ui.progress.IWorkbenchSiteProgressService; |
| import org.eclipse.ui.texteditor.IDocumentProvider; |
| |
| import com.ibm.icu.text.MessageFormat; |
| |
| /** |
| * Convenience and utility methods. |
| */ |
| public class Utilities { |
| private static final IPath ICONS_PATH= new Path("$nl$/icons/full/"); //$NON-NLS-1$ |
| |
| public static IWorkbenchPartSite findSite(Control c) { |
| while (c != null && !c.isDisposed()) { |
| Object data= c.getData(); |
| if (data instanceof IWorkbenchPart) |
| return ((IWorkbenchPart) data).getSite(); |
| c= c.getParent(); |
| } |
| return null; |
| } |
| |
| public static IActionBars findActionBars(Control c) { |
| while (c != null && !c.isDisposed()) { |
| Object data= c.getData(); |
| if (data instanceof CompareEditor) |
| return ((CompareEditor) data).getActionBars(); |
| |
| // PR 1GDVZV7: ITPVCM:WIN98 - CTRL + C does not work in Java source compare |
| if (data instanceof IViewPart) |
| return ((IViewPart) data).getViewSite().getActionBars(); |
| // end PR 1GDVZV7 |
| |
| c= c.getParent(); |
| } |
| return null; |
| } |
| |
| public static void setEnableComposite(Composite composite, boolean enable) { |
| Control[] children= composite.getChildren(); |
| for (int i= 0; i < children.length; i++) |
| children[i].setEnabled(enable); |
| } |
| |
| public static boolean getBoolean(CompareConfiguration cc, String key, boolean dflt) { |
| if (cc != null) { |
| Object value= cc.getProperty(key); |
| if (value instanceof Boolean) |
| return ((Boolean) value).booleanValue(); |
| } |
| return dflt; |
| } |
| |
| /** |
| * Returns the active compare filters for the compare configuration |
| * |
| * @param cc |
| * @return the active compare filters |
| */ |
| public static ICompareFilter[] getCompareFilters(CompareConfiguration cc) { |
| if (cc != null) { |
| Object value = cc.getProperty(ChangeCompareFilterPropertyAction.COMPARE_FILTERS); |
| if (value instanceof Map) { |
| @SuppressWarnings("unchecked") |
| Map<String, ICompareFilter[]> filtersMap = (Map<String, ICompareFilter[]>) value; |
| return filtersMap.values().toArray(new ICompareFilter[filtersMap.size()]); |
| } |
| } |
| return new ICompareFilter[0]; |
| } |
| |
| public static void firePropertyChange(ListenerList<IPropertyChangeListener> listenerList, Object source, String property, Object old, Object newValue) { |
| PropertyChangeEvent event= new PropertyChangeEvent(source, property, old, newValue); |
| firePropertyChange(listenerList, event); |
| } |
| |
| public static void firePropertyChange(final ListenerList<IPropertyChangeListener> listenerList, final PropertyChangeEvent event) { |
| if (listenerList == null || listenerList.isEmpty()) |
| return; |
| // Legacy listeners may expect to get notified in the UI thread |
| Runnable runnable = () -> { |
| for (IPropertyChangeListener listener : listenerList) { |
| SafeRunner.run(() -> listener.propertyChange(event)); |
| } |
| }; |
| if (Display.getCurrent() == null) { |
| Display.getDefault().syncExec(runnable); |
| } else { |
| runnable.run(); |
| } |
| } |
| |
| public static boolean okToUse(Widget widget) { |
| return widget != null && !widget.isDisposed(); |
| } |
| |
| private static ArrayList<IResource> internalGetResources(ISelection selection, Class<? extends IResource> type) { |
| ArrayList<IResource> tmp= new ArrayList<>(); |
| if (selection instanceof IStructuredSelection) { |
| Object[] s= ((IStructuredSelection) selection).toArray(); |
| |
| for (int i= 0; i < s.length; i++) { |
| IResource resource= null; |
| Object o= s[i]; |
| if (type.isInstance(o)) { |
| resource= (IResource) o; |
| } else if (o instanceof ResourceMapping) { |
| try { |
| ResourceTraversal[] travs= ((ResourceMapping)o).getTraversals(ResourceMappingContext.LOCAL_CONTEXT, null); |
| if (travs != null) { |
| for (int k= 0; k < travs.length; k++) { |
| IResource[] resources= travs[k].getResources(); |
| for (int j= 0; j < resources.length; j++) { |
| if (type.isInstance(resources[j]) && resources[j].isAccessible()) |
| tmp.add(resources[j]); |
| } |
| } |
| } |
| } catch (CoreException ex) { |
| CompareUIPlugin.log(ex); |
| } |
| } else if (o instanceof IAdaptable) { |
| IAdaptable a= (IAdaptable) o; |
| Object adapter= a.getAdapter(IResource.class); |
| if (type.isInstance(adapter)) |
| resource= (IResource) adapter; |
| } |
| |
| if (resource != null && resource.isAccessible()) |
| tmp.add(resource); |
| } |
| } |
| return tmp; |
| } |
| |
| /* |
| * Convenience method: extract all accessible <code>IResources</code> from given selection. |
| * Never returns null. |
| */ |
| public static IResource[] getResources(ISelection selection) { |
| ArrayList<IResource> tmp= internalGetResources(selection, IResource.class); |
| return tmp.toArray(new IResource[tmp.size()]); |
| } |
| |
| /* |
| * Convenience method: extract all accessible <code>IFiles</code> from given selection. |
| * Never returns null. |
| */ |
| public static IFile[] getFiles(ISelection selection) { |
| ArrayList<IResource> tmp= internalGetResources(selection, IFile.class); |
| return tmp.toArray(new IFile[tmp.size()]); |
| } |
| |
| public static byte[] readBytes(InputStream in) { |
| ByteArrayOutputStream bos= new ByteArrayOutputStream(); |
| try { |
| while (true) { |
| int c= in.read(); |
| if (c == -1) |
| break; |
| bos.write(c); |
| } |
| |
| } catch (IOException ex) { |
| return null; |
| |
| } finally { |
| Utilities.close(in); |
| try { |
| bos.close(); |
| } catch (IOException x) { |
| // silently ignored |
| } |
| } |
| |
| return bos.toByteArray(); |
| } |
| |
| public static IPath getIconPath(Display display) { |
| return ICONS_PATH; |
| } |
| |
| /* |
| * Initializes the given Action from a ResourceBundle. |
| */ |
| public static void initAction(IAction a, ResourceBundle bundle, String prefix) { |
| String labelKey= "label"; //$NON-NLS-1$ |
| String tooltipKey= "tooltip"; //$NON-NLS-1$ |
| String imageKey= "image"; //$NON-NLS-1$ |
| String descriptionKey= "description"; //$NON-NLS-1$ |
| |
| if (prefix != null && prefix.length() > 0) { |
| labelKey= prefix + labelKey; |
| tooltipKey= prefix + tooltipKey; |
| imageKey= prefix + imageKey; |
| descriptionKey= prefix + descriptionKey; |
| } |
| |
| a.setText(getString(bundle, labelKey, labelKey)); |
| a.setToolTipText(getString(bundle, tooltipKey, null)); |
| a.setDescription(getString(bundle, descriptionKey, null)); |
| |
| String relPath= getString(bundle, imageKey, null); |
| if (relPath != null && relPath.trim().length() > 0) { |
| String dPath; |
| String ePath; |
| |
| if (relPath.indexOf("/") >= 0) { //$NON-NLS-1$ |
| String path= relPath.substring(1); |
| dPath= 'd' + path; |
| ePath= 'e' + path; |
| } else { |
| dPath= "dlcl16/" + relPath; //$NON-NLS-1$ |
| ePath= "elcl16/" + relPath; //$NON-NLS-1$ |
| } |
| |
| ImageDescriptor id= CompareUIPlugin.getImageDescriptor(dPath); // we set the disabled image first (see PR 1GDDE87) |
| if (id != null) |
| a.setDisabledImageDescriptor(id); |
| id= CompareUIPlugin.getImageDescriptor(ePath); |
| if (id != null) { |
| a.setImageDescriptor(id); |
| a.setHoverImageDescriptor(id); |
| } |
| } |
| } |
| |
| public static void initToggleAction(IAction a, ResourceBundle bundle, String prefix, boolean checked) { |
| String tooltip= null; |
| if (checked) { |
| tooltip= getString(bundle, prefix + "tooltip.checked", null); //$NON-NLS-1$ |
| } else { |
| tooltip= getString(bundle, prefix + "tooltip.unchecked", null); //$NON-NLS-1$ |
| } |
| if (tooltip == null) |
| tooltip= getString(bundle, prefix + "tooltip", null); //$NON-NLS-1$ |
| |
| if (tooltip != null) |
| a.setToolTipText(tooltip); |
| |
| String description= null; |
| if (checked) { |
| description= getString(bundle, prefix + "description.checked", null); //$NON-NLS-1$ |
| } else { |
| description= getString(bundle, prefix + "description.unchecked", null); //$NON-NLS-1$ |
| } |
| if (description == null) |
| description= getString(bundle, prefix + "description", null); //$NON-NLS-1$ |
| |
| if (description != null) |
| a.setDescription(description); |
| } |
| |
| public static String getString(ResourceBundle bundle, String key, String dfltValue) { |
| if (bundle != null) { |
| try { |
| return bundle.getString(key); |
| } catch (MissingResourceException x) { |
| // fall through |
| } |
| } |
| return dfltValue; |
| } |
| |
| public static String getFormattedString(ResourceBundle bundle, String key, String arg) { |
| if (bundle != null) { |
| try { |
| return MessageFormat.format(bundle.getString(key), arg); |
| } catch (MissingResourceException x) { |
| CompareUIPlugin.log(x); |
| } |
| } |
| return "!" + key + "!"; //$NON-NLS-2$ //$NON-NLS-1$ |
| } |
| |
| public static String getString(String key) { |
| try { |
| return CompareUI.getResourceBundle().getString(key); |
| } catch (MissingResourceException e) { |
| return "!" + key + "!"; //$NON-NLS-2$ //$NON-NLS-1$ |
| } |
| } |
| |
| public static String getFormattedString(String key, String arg) { |
| try { |
| return MessageFormat.format(CompareUI.getResourceBundle().getString(key), arg); |
| } catch (MissingResourceException e) { |
| return "!" + key + "!"; //$NON-NLS-2$ //$NON-NLS-1$ |
| } |
| } |
| |
| public static String getFormattedString(String key, String arg0, String arg1) { |
| try { |
| return MessageFormat.format(CompareUI.getResourceBundle().getString(key), arg0, arg1); |
| } catch (MissingResourceException e) { |
| return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$ |
| } |
| } |
| |
| public static String getString(ResourceBundle bundle, String key) { |
| return getString(bundle, key, key); |
| } |
| |
| public static int getInteger(ResourceBundle bundle, String key, int dfltValue) { |
| if (bundle != null) { |
| try { |
| String s= bundle.getString(key); |
| if (s != null) |
| return Integer.parseInt(s); |
| } catch (NumberFormatException x) { |
| CompareUIPlugin.log(x); |
| } catch (MissingResourceException x) { |
| // Silently ignore Exception |
| } |
| } |
| return dfltValue; |
| } |
| |
| /** |
| * Answers <code>true</code> if the given selection contains resources that don't |
| * have overlapping paths and <code>false</code> otherwise. |
| */ |
| /* |
| public static boolean isSelectionNonOverlapping() throws TeamException { |
| IResource[] resources = getSelectedResources(); |
| // allow operation for non-overlapping resource selections |
| if(resources.length>0) { |
| List validPaths = new ArrayList(2); |
| for (int i = 0; i < resources.length; i++) { |
| IResource resource = resources[i]; |
| |
| // only allow cvs resources to be selected |
| if(RepositoryProvider.getProvider(resource.getProject(), CVSProviderPlugin.getTypeId()) == null) { |
| return false; |
| } |
| |
| // check if this resource overlaps other selections |
| IPath resourceFullPath = resource.getFullPath(); |
| if(!validPaths.isEmpty()) { |
| for (Iterator it = validPaths.iterator(); it.hasNext();) { |
| IPath path = (IPath) it.next(); |
| if(path.isPrefixOf(resourceFullPath) || |
| resourceFullPath.isPrefixOf(path)) { |
| return false; |
| } |
| } |
| } |
| validPaths.add(resourceFullPath); |
| |
| // ensure that resources are managed |
| ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource); |
| if(cvsResource.isFolder()) { |
| if( ! ((ICVSFolder)cvsResource).isCVSFolder()) return false; |
| } else { |
| if( ! cvsResource.isManaged()) return false; |
| } |
| } |
| return true; |
| } |
| return false; |
| } |
| */ |
| |
| /* validate edit utilities */ |
| |
| /** |
| * Status constant indicating that an validateEdit call has changed the |
| * content of a file on disk. |
| */ |
| private static final int VALIDATE_EDIT_PROBLEM= 10004; |
| |
| /** |
| * Constant used to indicate that tests are being run. |
| */ |
| public static boolean RUNNING_TESTS = false; |
| |
| /** |
| * Constant used while testing the indicate that changes should be flushed |
| * when the compare input changes and a viewer is dirty. |
| */ |
| public static boolean TESTING_FLUSH_ON_COMPARE_INPUT_CHANGE = false; |
| |
| /* |
| * Makes the given resources committable. Committable means that all |
| * resources are writeable and that the content of the resources hasn't |
| * changed by calling <code>validateEdit</code> for a given file on |
| * <tt>IWorkspace</tt>. |
| * |
| * @param resources the resources to be checked |
| * @param shell the Shell passed to <code>validateEdit</code> as a context |
| * @return returns <code>true</code> if all resources are committable, <code>false</code> otherwise |
| * |
| * @see org.eclipse.core.resources.IWorkspace#validateEdit(org.eclipse.core.resources.IFile[], java.lang.Object) |
| */ |
| public static boolean validateResource(IResource resource, Shell shell, String title) { |
| return validateResources(new IResource[] { resource }, shell, title); |
| } |
| |
| /* |
| * Makes the given resources committable. Committable means that all |
| * resources are writeable and that the content of the resources hasn't |
| * changed by calling <code>validateEdit</code> for a given file on |
| * <tt>IWorkspace</tt>. |
| * |
| * @param resources the resources to be checked |
| * @param shell the Shell passed to <code>validateEdit</code> as a context |
| * @return returns <code>true</code> if all resources are committable, <code>false</code> otherwise |
| * |
| * @see org.eclipse.core.resources.IWorkspace#validateEdit(org.eclipse.core.resources.IFile[], java.lang.Object) |
| */ |
| public static boolean validateResources(List<IResource> resources, Shell shell, String title) { |
| IResource r[]= resources.toArray(new IResource[resources.size()]); |
| return validateResources(r, shell, title); |
| } |
| |
| /* |
| * Makes the given resources committable. Committable means that all |
| * resources are writeable and that the content of the resources hasn't |
| * changed by calling <code>validateEdit</code> for a given file on |
| * <tt>IWorkspace</tt>. |
| * |
| * @param resources the resources to be checked |
| * @param shell the Shell passed to <code>validateEdit</code> as a context |
| * @return returns <code>true</code> if all resources are committable, <code>false</code> otherwise |
| * |
| * @see org.eclipse.core.resources.IWorkspace#validateEdit(org.eclipse.core.resources.IFile[], java.lang.Object) |
| */ |
| public static boolean validateResources(IResource[] resources, Shell shell, String title) { |
| // get all readonly files |
| List<IResource> readOnlyFiles= getReadonlyFiles(resources); |
| if (readOnlyFiles.size() == 0) |
| return true; |
| |
| // get timestamps of readonly files before validateEdit |
| Map<IFile, Long> oldTimeStamps= createModificationStampMap(readOnlyFiles); |
| |
| IFile[] files= readOnlyFiles.toArray(new IFile[readOnlyFiles.size()]); |
| IStatus status= ResourcesPlugin.getWorkspace().validateEdit(files, shell); |
| if (!status.isOK()) { |
| String message= getString("ValidateEdit.error.unable_to_perform"); //$NON-NLS-1$ |
| displayError(shell, title, status, message); |
| return false; |
| } |
| |
| IStatus modified= null; |
| Map<IFile, Long> newTimeStamps= createModificationStampMap(readOnlyFiles); |
| for (Map.Entry<IFile, Long> entry : newTimeStamps.entrySet()) { |
| IFile file = entry.getKey(); |
| Long newTimeStamp = entry.getValue(); |
| if (file.isReadOnly()) { |
| IStatus error = new Status(IStatus.ERROR, |
| CompareUIPlugin.getPluginId(), |
| VALIDATE_EDIT_PROBLEM, |
| getFormattedString("ValidateEdit.error.stillReadonly", file.getFullPath().toString()), //$NON-NLS-1$ |
| null); |
| modified= addStatus(modified, error); |
| } else if (!oldTimeStamps.get(file).equals(newTimeStamp)) { |
| IStatus error = new Status(IStatus.ERROR, |
| CompareUIPlugin.getPluginId(), |
| VALIDATE_EDIT_PROBLEM, |
| getFormattedString("ValidateEdit.error.fileModified", file.getFullPath().toString()), //$NON-NLS-1$ |
| null); |
| modified= addStatus(modified, error); |
| } |
| } |
| if (modified != null) { |
| String message= getString("ValidateEdit.error.unable_to_perform"); //$NON-NLS-1$ |
| displayError(shell, title, modified, message); |
| return false; |
| } |
| return true; |
| } |
| |
| private static void displayError(final Shell shell, final String title, final IStatus status, final String message) { |
| if (Display.getCurrent() != null) { |
| ErrorDialog.openError(shell, title, message, status); |
| } else { |
| Display.getDefault().syncExec(() -> ErrorDialog.openError(shell, title, message, status)); |
| } |
| } |
| |
| private static List<IResource> getReadonlyFiles(IResource[] resources) { |
| List<IResource> readOnlyFiles= new ArrayList<>(); |
| for (IResource resource : resources) { |
| ResourceAttributes resourceAttributes= resource.getResourceAttributes(); |
| if (resource.getType() == IResource.FILE && resourceAttributes != null && resourceAttributes.isReadOnly()) |
| readOnlyFiles.add(resource); |
| } |
| return readOnlyFiles; |
| } |
| |
| private static Map<IFile, Long> createModificationStampMap(List<IResource> files) { |
| Map<IFile, Long> map= new HashMap<IFile, Long>(); |
| for (IResource file : files) { |
| map.put((IFile) file, file.getModificationStamp()); |
| } |
| return map; |
| } |
| |
| private static IStatus addStatus(IStatus status, IStatus entry) { |
| if (status == null) |
| return entry; |
| |
| if (status.isMultiStatus()) { |
| ((MultiStatus)status).add(entry); |
| return status; |
| } |
| |
| MultiStatus result= new MultiStatus(CompareUIPlugin.getPluginId(), |
| VALIDATE_EDIT_PROBLEM, |
| getString("ValidateEdit.error.unable_to_perform"), null); //$NON-NLS-1$ |
| result.add(status); |
| result.add(entry); |
| return result; |
| } |
| |
| // encoding |
| |
| public static String readString(IStreamContentAccessor sca, String encoding) throws CoreException { |
| String s = null; |
| try { |
| try { |
| s= Utilities.readString(sca.getContents(), encoding); |
| } catch (UnsupportedEncodingException e) { |
| if (!encoding.equals(ResourcesPlugin.getEncoding())) { |
| s = Utilities.readString(sca.getContents(), ResourcesPlugin.getEncoding()); |
| } |
| } |
| } catch (IOException e) { |
| throw new CoreException(new Status(IStatus.ERROR, CompareUIPlugin.PLUGIN_ID, 0, e.getMessage(), e)); |
| } |
| return s; |
| } |
| |
| /* |
| * Returns null if an error occurred. |
| */ |
| public static String readString(InputStream is, String encoding) throws IOException { |
| return readString(is, encoding, -1, null); |
| } |
| |
| public static String readString(InputStream is, String encoding, int length, IProgressMonitor monitor) throws IOException { |
| SubMonitor progress = SubMonitor.convert(monitor); |
| progress.setWorkRemaining(length); |
| if (is == null) |
| return null; |
| BufferedReader reader= null; |
| try { |
| StringBuilder buffer= new StringBuilder(); |
| char[] part= new char[2048]; |
| int read= 0; |
| reader= new BufferedReader(new InputStreamReader(is, encoding)); |
| while ((read= reader.read(part)) != -1) { |
| buffer.append(part, 0, read); |
| progress.worked(2048); |
| if (progress.isCanceled()) |
| throw new OperationCanceledException(); |
| } |
| |
| return buffer.toString(); |
| } finally { |
| if (reader != null) { |
| try { |
| reader.close(); |
| } catch (IOException ex) { |
| // silently ignored |
| } |
| } |
| } |
| } |
| |
| public static String getCharset(Object resource) { |
| if (resource instanceof IEncodedStorage) { |
| try { |
| return ((IEncodedStorage)resource).getCharset(); |
| } catch (CoreException ex) { |
| CompareUIPlugin.log(ex); |
| } |
| } |
| return ResourcesPlugin.getEncoding(); |
| } |
| |
| public static byte[] getBytes(String s, String encoding) { |
| byte[] bytes= null; |
| if (s != null) { |
| try { |
| bytes= s.getBytes(encoding); |
| } catch (UnsupportedEncodingException e) { |
| bytes= s.getBytes(); |
| } |
| } |
| return bytes; |
| } |
| |
| public static String readString(IStreamContentAccessor sa) throws CoreException { |
| String encoding= null; |
| if (sa instanceof IEncodedStreamContentAccessor) |
| encoding= ((IEncodedStreamContentAccessor)sa).getCharset(); |
| if (encoding == null) |
| encoding= ResourcesPlugin.getEncoding(); |
| return Utilities.readString(sa, encoding); |
| } |
| |
| public static void close(InputStream is) { |
| if (is != null) { |
| try { |
| is.close(); |
| } catch (IOException ex) { |
| // silently ignored |
| } |
| } |
| } |
| |
| public static IResource getFirstResource(ISelection selection) { |
| IResource[] resources = getResources(selection); |
| if (resources.length > 0) |
| return resources[0]; |
| return null; |
| } |
| |
| public static ITypedElement getLeg(char type, Object input) { |
| if (input instanceof ICompareInput) { |
| switch (type) { |
| case MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR: |
| return ((ICompareInput)input).getAncestor(); |
| case MergeViewerContentProvider.LEFT_CONTRIBUTOR: |
| return ((ICompareInput)input).getLeft(); |
| case MergeViewerContentProvider.RIGHT_CONTRIBUTOR: |
| return ((ICompareInput)input).getRight(); |
| default: |
| break; |
| } |
| } |
| return null; |
| } |
| |
| public static IDocument getDocument(char type, Object element, boolean isUsingDefaultContentProvider, boolean canHaveSharedDocument) { |
| ITypedElement te= getLeg(type, element); |
| if (te == null) |
| return null; |
| if (te instanceof IDocument) |
| return (IDocument) te; |
| if (te instanceof IDocumentRange) |
| return ((IDocumentRange) te).getDocument(); |
| |
| if (isUsingDefaultContentProvider && canHaveSharedDocument) { |
| ISharedDocumentAdapter sda = Adapters.adapt(te, ISharedDocumentAdapter.class); |
| if (sda != null) { |
| IEditorInput input= sda.getDocumentKey(te); |
| if (input != null) { |
| IDocumentProvider provider = SharedDocumentAdapter.getDocumentProvider(input); |
| if (provider != null) |
| return provider.getDocument(input); |
| } |
| } |
| } |
| |
| if (te instanceof IStreamContentAccessor) |
| return DocumentManager.get(te); |
| |
| return null; |
| } |
| |
| /** |
| * Return whether either the left or right sides of the given input |
| * represents a hunk. A hunk is a portion of a file. |
| * @param input the compare input |
| * @return whether the left or right side of the input represents a hunk |
| */ |
| public static boolean isHunk(Object input) { |
| if (input != null && input instanceof DiffNode){ |
| ITypedElement right = ((DiffNode) input).getRight(); |
| if (Adapters.adapt(right, IHunk.class) != null) |
| return true; |
| ITypedElement left = ((DiffNode) input).getLeft(); |
| if (Adapters.adapt(left, IHunk.class) != null) |
| return true; |
| } |
| return false; |
| } |
| |
| public static boolean isHunkOk(Object input) { |
| if (input != null && input instanceof DiffNode){ |
| ITypedElement right = ((DiffNode) input).getRight(); |
| HunkResult element = Adapters.adapt(right, HunkResult.class); |
| if (element != null) { |
| return element.isOK(); |
| } |
| ITypedElement left = ((DiffNode) input).getLeft(); |
| element = Adapters.adapt(left, HunkResult.class); |
| if (element != null) |
| return element.isOK(); |
| } |
| return false; |
| } |
| |
| public static void schedule(Job job, IWorkbenchSite site) { |
| if (site != null) { |
| IWorkbenchSiteProgressService siteProgress = site.getAdapter(IWorkbenchSiteProgressService.class); |
| if (siteProgress != null) { |
| siteProgress.schedule(job, 0, true /* use half-busy cursor */); |
| return; |
| } |
| } |
| job.schedule(); |
| } |
| |
| public static void runInUIThread(final Runnable runnable) { |
| if (Display.getCurrent() != null) { |
| BusyIndicator.showWhile(Display.getCurrent(), runnable); |
| } else { |
| Display.getDefault().syncExec(() -> BusyIndicator.showWhile(Display.getCurrent(), runnable)); |
| } |
| } |
| |
| /** |
| * @param connection a connection for which the timeout is set |
| * @param timeout an int that specifies the connect timeout value in milliseconds |
| * @return whether the timeout has been successfully set |
| */ |
| public static boolean setReadTimeout(URLConnection connection, int timeout) { |
| Method[] methods = connection.getClass().getMethods(); |
| for (int i = 0; i < methods.length; i++) { |
| if (methods[i].getName().equals("setReadTimeout")) { //$NON-NLS-1$ |
| try { |
| methods[i].invoke(connection, new Object[] {Integer.valueOf(timeout)}); |
| return true; |
| } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) { |
| // ignore |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Loads content of file under <code>url</code> displaying progress on given |
| * context. |
| * |
| * @param url |
| * @param context |
| * @return the content of file under given URL, or <code>null</code> if URL |
| * could not be loaded |
| * @throws InvocationTargetException |
| * thrown on errors while URL loading |
| * @throws OperationCanceledException |
| * @throws InterruptedException |
| */ |
| public static String getURLContents(final URL url, IRunnableContext context) |
| throws InvocationTargetException, OperationCanceledException, |
| InterruptedException { |
| final String[] result = new String[1]; |
| context.run(true, true, monitor -> { |
| SubMonitor progress = SubMonitor.convert(monitor, |
| PatchMessages.InputPatchPage_URLConnecting, 100); |
| try { |
| URLConnection connection = url.openConnection(); |
| progress.worked(10); |
| if (monitor.isCanceled()) |
| throw new OperationCanceledException(); |
| setReadTimeout(connection, 60 * 1000); |
| progress.setTaskName(PatchMessages.InputPatchPage_URLFetchingContent); |
| String enc = connection.getContentEncoding(); |
| if (enc == null) |
| enc = ResourcesPlugin.getEncoding(); |
| result[0] = Utilities.readString( |
| connection.getInputStream(), enc, |
| connection.getContentLength(), |
| progress.newChild(90)); |
| } catch (IOException e) { |
| throw new InvocationTargetException(e); |
| } |
| }); |
| return result[0]; |
| } |
| |
| /** |
| * Applies the compare filters to the lines of text taken from the specified |
| * contributors |
| * |
| * @param thisLine |
| * @param thisContributor |
| * @param otherLine |
| * @param otherContributor |
| * @param filters |
| * may be null |
| * @return returns the result of applying the filters to the line from the |
| * contributor |
| */ |
| public static String applyCompareFilters(String thisLine, |
| char thisContributor, String otherLine, char otherContributor, |
| ICompareFilter[] filters) { |
| IRegion[][] ignoredRegions = new IRegion[filters.length][]; |
| |
| HashMap<String, Comparable<?>> input = new HashMap<>(4); |
| input.put(ICompareFilter.THIS_LINE, thisLine); |
| input.put(ICompareFilter.THIS_CONTRIBUTOR, thisContributor); |
| input.put(ICompareFilter.OTHER_LINE, otherLine); |
| input.put(ICompareFilter.OTHER_CONTRIBUTOR, otherContributor); |
| for (int i = 0; i < filters.length; i++) { |
| ignoredRegions[i] = filters[i].getFilteredRegions(input); |
| } |
| |
| boolean[] ignored = new boolean[thisLine.length()]; |
| for (int j = 0; j < ignoredRegions.length; j++) { |
| if (ignoredRegions[j] != null) { |
| for (int k = 0; k < ignoredRegions[j].length; k++) { |
| if (ignoredRegions[j][k] != null) { |
| for (int l = 0; l < ignoredRegions[j][k].getLength(); l++) { |
| ignored[ignoredRegions[j][k].getOffset() + l] = true; |
| } |
| } |
| } |
| } |
| } |
| StringBuilder buffer = new StringBuilder(thisLine.length()); |
| for (int i = 0; i < ignored.length; i++) { |
| if (!ignored[i]) { |
| buffer.append(thisLine.charAt(i)); |
| } |
| } |
| return buffer.toString(); |
| } |
| } |