--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/org.symbian.tools.wrttools.previewer/src/org/symbian/tools/wrttools/previewer/utils/FileUtils.java Wed Jan 20 16:51:26 2010 -0800
@@ -0,0 +1,851 @@
+/**
+ * Copyright (c) 2009 Symbian Foundation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * This component and the accompanying materials are made available
+ * under the terms of the License "Eclipse Public License v1.0"
+ * which accompanies this distribution, and is available
+ * at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ *
+ * Initial Contributors:
+ * Symbian Foundation - initial contribution.
+ * Contributors:
+ * Description:
+ * Overview:
+ * Details:
+ * Platforms/Drives/Compatibility:
+ * Assumptions/Requirement/Pre-requisites:
+ * Failures and causes:
+ */
+package org.symbian.tools.wrttools.previewer.utils;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.swt.widgets.Shell;
+import org.osgi.framework.Bundle;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * @author eswartz
+ *
+ */
+public class FileUtils {
+
+ // special IStatus code for file modified during validateEdit
+ public static final int MODIFIED_FILES_STATUS = 1000;
+
+ /** Copy files or directories from 'from' to 'to'.
+ *
+ * Recursively descends if 'from' is a directory.
+ * Creates 'from' tail directory in 'to', e.g.:
+ * from = c:/foo/bar
+ * to = c:/temp
+ *
+ * -->
+ *
+ * c:/temp/bar
+ *
+ * @param from
+ * @param to
+ * @param filter the filename filter, or null
+ */
+ public static void copyTree(File from, File to, FileFilter filter) throws IOException {
+ File[] children;
+
+ if (!from.exists()) {
+ throw new IOException ("Source of copy \'" + from.getName() + "\' doesn't exist");
+ }
+
+ if (to.getCanonicalPath().equals(from.getCanonicalPath())) {
+ throw new IOException ("\'" + from.getName() + "\' cannot copy to itself");
+ }
+
+ if (from.isDirectory()) {
+ children = from.listFiles(filter);
+ // just like cp command, if target exist, make a new folder into
+ // the target, copy content into the target folder
+ if (to.exists()) {
+ if (to.isFile()) {
+ throw new IOException("Cannot overwrite non-directory \'" + to.getName() + "\' with directory " + from.getName());
+ }
+ // copy into new directory name grafted after the existing one
+ to = new File(to, from.getName());
+ copyTree(from, to, filter);
+ return;
+ } else {
+ // copy into new directory name
+ to.mkdir();
+ for (int i = 0; i < children.length; i++) {
+ File curto = new File(to, children[i].getName());
+
+ copyTree(children[i], curto, filter);
+ }
+ return;
+ }
+ }
+ else {
+ if (to.isDirectory()) {
+ to = new File (to, from.getName());
+ }
+ copyFile(from, to);
+ return;
+ }
+
+ }
+
+ /** Copy files or directories from 'from' to 'to'.
+ *
+ * Recursively descends if 'from' is a directory.
+ * Does not create 'from' tail directory in 'to', e.g.:
+ * from = c:/foo/bar contains a,b,c
+ * to = c:/temp
+ *
+ * -->
+ *
+ * c:/temp/a
+ * c:/temp/b
+ * c:/temp/c
+ *
+ * @param from
+ * @param to
+ * @param filter the filename filter, or null
+ */
+ public static void copyTreeNoParent(File from, File to, FileFilter filter) throws IOException {
+ File[] files;
+
+ Check.checkArg(from.isDirectory());
+
+ files = from.listFiles(filter);
+ to.mkdirs();
+
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isDirectory()) {
+ //File curto = new File(to, files[i].getName());
+ //curto.mkdirs();
+ copyTree(files[i], to, filter);
+ }
+ else {
+ File curto = new File(to, files[i].getName());
+ copyFile(files[i], curto);
+ }
+ }
+
+ }
+
+ /**
+ * Copy from an input stream to a file
+ *
+ * @param in
+ * @param to
+ * @throws IOException
+ */
+ public static void copyFile(InputStream in, File to) throws IOException {
+ FileOutputStream out = new FileOutputStream(to);
+ int len;
+ byte[] buffer = new byte[4096];
+ while ((len = in.read(buffer)) != -1) {
+ out.write(buffer, 0, len);
+ }
+ out.close();
+ in.close();
+ }
+
+ /** Copy a single file from 'from' to 'to'
+ *
+ * @param from
+ * @param to
+ * @throws IOException
+ */
+ public static void copyFile(File from, File to) throws IOException {
+ FileInputStream in = new FileInputStream(from);
+ copyFile(in, to);
+ }
+
+ /** Delete a directory tree recursively.
+ * <p>
+ * Does not delete file.
+ * @param file start point for deletion -- not itself deleted
+ */
+ public static void delTree(File file) {
+ File[] files = file.listFiles();
+ if (files != null) {
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isDirectory()) {
+ delTree(files[i]);
+ }
+ }
+ }
+ files = file.listFiles();
+ if (files != null) {
+ for (int i = 0; i < files.length; i++) {
+ files[i].delete();
+ }
+ }
+ }
+
+ public static File pluginRelativeFile(Plugin plugin, String file) throws IOException {
+ Check.checkArg(plugin);
+ Bundle bundle = plugin.getBundle();
+ if (bundle == null)
+ return null;
+ URL url = FileLocator.find(bundle, new Path("."), null); //$NON-NLS-1$
+ if (url == null)
+ return null;
+ url = FileLocator.resolve(url);
+ return new File(url.getPath(), file);
+ }
+
+ /**
+ * Convert the path to a path relative to the base, if possible.
+ * @param rootPath full path to base
+ * @param cpath full path to resource
+ * @return new path (base-relative) or null if not resolvable to base
+ */
+ static public IPath removePrefixFromPath(IPath rootPath, IPath cpath) {
+ if (matchingFirstSegments(rootPath, cpath) == rootPath.segmentCount()) {
+ IPath suffix = cpath.removeFirstSegments(rootPath.segmentCount());
+ return suffix.setDevice(null);
+ }
+ return null;
+ }
+
+ /**
+ * Convert the path to a path in the workspace, if possible.
+ * Either the path comes in as a path pointing inside the
+ * workspace, or we can find a linked resource which aliases
+ * to the same location.
+ * @param cpath full filesystem path to resource
+ * @return new path (workspace-relative) or null if not resolvable to workspace
+ */
+ static public IPath convertToWorkspacePath(IPath cpath) {
+ return convertToWorkspacePath(cpath, false);
+ }
+
+ /**
+ * Convert the path to a path in the workspace, if possible.
+ * Either the path comes in as a path pointing inside the
+ * workspace, or we can find a linked resource which aliases
+ * to the same location.
+ * @param cpath full filesystem path to resource
+ * @param makeCanonical if true, work from the canonical path if possible
+ * (recommended)
+ * @return new path (workspace-relative) or null if not resolvable to workspace
+ */
+ static public IPath convertToWorkspacePath(IPath cpath, boolean makeCanonical) {
+ return convertToWorkspacePath(cpath, makeCanonical, true);
+ }
+ /**
+ * Convert the path to a path in the workspace, if possible.
+ * Either the path comes in as a path pointing inside the
+ * workspace, or we can find a linked resource which aliases
+ * to the same location.
+ * @param cpath full filesystem path to resource
+ * @param makeCanonical if true, work from the canonical path if possible
+ * (recommended)
+ * @param resolveLinks if true, look for project paths which reference files outside
+ * the workspace via links (very slow)
+ * @return new path (workspace-relative) or null if not resolvable to workspace
+ */
+ static public IPath convertToWorkspacePath(IPath cpath, boolean makeCanonical, boolean resolveLinks) {
+ if (!Platform.isRunning() || cpath == null)
+ return null;
+
+ if (makeCanonical) {
+ try {
+ // Since we have a filesystem path, try using the filesystem
+ // and Java's smarter APIs to fix the caps early.
+ // Watch out for the device being set incorrectly, though.
+ String device = cpath.getDevice();
+ cpath = new Path(cpath.toFile().getCanonicalPath()).setDevice(device);
+ } catch (IOException e) {
+ // Something's wrong with the path; just use it as-is
+ }
+ }
+
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IFile file = root.getFileForLocation(cpath);
+ if (file != null) {
+ return file.getFullPath().setDevice(null);
+ }
+
+ if (resolveLinks) {
+ // try to see if a linked resource points to this
+ IFile[] files = root.findFilesForLocation(cpath);
+ IPath newPath = null;
+ if (files.length > 0)
+ newPath = files[0].getFullPath().setDevice(null);
+ else {
+ IContainer[] folders = root.findContainersForLocation(cpath);
+ if (folders.length > 0)
+ newPath = folders[0].getFullPath().setDevice(null);
+ }
+ return newPath;
+ }
+
+ return null;
+ }
+
+ /**
+ * Convert the full path to a full path inside the workspace, if possible.
+ * (E.g. change a linked resource to the real full path.)
+ * <p>
+ * Either the path comes in as a path pointing inside the
+ * workspace, or we can find a linked resource which aliases
+ * to the same location.
+ * @param cpath full filesystem path
+ * @return same cpath, new path, or null if not resolvable to workspace
+ */
+ static public IPath convertToWorkspaceLocation(IPath cpath) {
+ if (!Platform.isRunning())
+ return null;
+
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IPath rootPath = root.getLocation();
+ IPath newPath = convertToWorkspacePath(cpath);
+ if (newPath == null)
+ return null;
+
+ // convert to full path
+ return rootPath.append(newPath);
+ }
+
+ /**
+ * Variant of routine that works with case-insensitive matching.
+ * @see IPath#matchingFirstSegments(IPath)
+ */
+ public static int matchingFirstSegments(IPath my, IPath anotherPath) {
+ if (my == null || anotherPath == null)
+ return 0;
+ int anotherPathLen = anotherPath.segmentCount();
+ int max = Math.min(my.segmentCount(), anotherPathLen);
+ int count = 0;
+ for (int i = 0; i < max; i++) {
+ if (!my.segment(i).equalsIgnoreCase(anotherPath.segment(i))) {
+ return count;
+ }
+ count++;
+ }
+ return count;
+ }
+
+ /**
+ * Map the given file to a path in the current workspace.
+ * @param file
+ * @return the IFile for the file
+ * @deprecated this function is broken since it doesn't resolve linked resources.
+ */
+ public static IFile convertFileToIFile(IContainer container, File file) {
+ IPath path = new Path(file.getAbsolutePath());
+ IPath rootPath = container.getLocation();
+
+ // this is BUGGY! Case sensitive for some dumb reason
+ //int match = path.matchingFirstSegments(rootPath);
+ int match = matchingFirstSegments(path, rootPath);
+ Check.checkState(match >= rootPath.segmentCount());
+
+ path = path.removeFirstSegments(match);
+ IFile wsFile = container.getFile(path);
+ return wsFile;
+ }
+
+ /**
+ * Map the given file to a path in the current workspace.
+ * @param file
+ * @return the IFile for the file, or null if the file is not in the workspace
+ */
+ public static IFile convertFileToIFile(File file) {
+ IPath path = new Path(file.getAbsolutePath());
+
+ IPath wsPath = convertToWorkspacePath(path, true);
+ if (wsPath != null)
+ return ResourcesPlugin.getWorkspace().getRoot().getFile(wsPath);
+
+ return null;
+
+ /*
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IPath rootPath = root.getRawLocation();
+
+ // this is BUGGY! Case sensitive for some dumb reason
+ //int match = path.matchingFirstSegments(rootPath);
+ int match = matchingFirstSegments(path, rootPath);
+ if (match < rootPath.segmentCount())
+ return null;
+
+ path = path.removeFirstSegments(match);
+ IFile wsFile = root.getFile(path);
+
+ return wsFile;
+ */
+ }
+
+ /**
+ * Map the given file to a resource in the current workspace. This only handles
+ * files that map to known workspace resources.
+ * @param file
+ * @return the IResource for the file, or null if the file is not in the workspace or doesn't
+ * exist.
+ */
+ public static IResource convertFileToExistingResource(File file) {
+ IPath path = new Path(file.getAbsolutePath());
+
+ IPath wsPath = convertToWorkspacePath(path, true);
+ if (wsPath != null)
+ return ResourcesPlugin.getWorkspace().getRoot().findMember(wsPath);
+
+ return null;
+ }
+
+ /**
+ * Return the project for the given workspace-relative path.
+ */
+ public static IProject projectForPath(IPath path) {
+ IProject result = null;
+ if (path != null) {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ result = root.getProject(path.segment(0));
+ }
+ return result;
+ }
+
+ /**
+ * Read contents of a file into an array
+ * @param file
+ * @param encoding (null = system default)
+ * @return array of text
+ * @throws CoreException wrapping java.io.FileException
+ */
+ public static char[] readFileContents(File file, String encoding) throws CoreException {
+ Check.checkArg(file);
+ FileInputStream fis;
+ try {
+ fis = new FileInputStream(file);
+ return readInputStreamContents(fis, encoding);
+ } catch (IOException e) {
+ throw new CoreException(Logging.newStatus(UtilsPlugin.getDefault(), e));
+ }
+ }
+
+ /**
+ * Read contents of a file into an array
+ * @param is input stream
+ * @param encoding (null is system default)
+ * @return array of text
+ * @throws CoreException wrapping java.io.FileException
+ */
+ public static char[] readInputStreamContents(InputStream is, String encoding) throws CoreException {
+ Check.checkArg(is);
+
+ Reader reader;
+ try {
+ if (encoding != null)
+ reader = new InputStreamReader(is, encoding);
+ else
+ reader = new InputStreamReader(is);
+
+ return readReaderContents(reader);
+ } catch (UnsupportedEncodingException e) {
+ throw new CoreException(Logging.newStatus(UtilsPlugin.getDefault(), e));
+ }
+ }
+
+ /**
+ * Read contents of a file into an array
+ * @param file
+ * @param encoding (null = system default)
+ * @return array of text
+ * @throws CoreException wrapping java.io.FileException
+ */
+ public static char[] readReaderContents(Reader reader) throws CoreException {
+ Check.checkArg(reader);
+ try {
+ char[] buf = new char[1024];
+ StringBuffer sb = new StringBuffer();
+ int len;
+ while ((len = reader.read(buf)) > 0) {
+ sb.append(buf, 0, len);
+ }
+ reader.close();
+ return sb.toString().toCharArray();
+ } catch (UnsupportedEncodingException e) {
+ throw new CoreException(Logging.newStatus(UtilsPlugin.getDefault(), e));
+ } catch (IOException e) {
+ throw new CoreException(Logging.newStatus(UtilsPlugin.getDefault(), e));
+ }
+ }
+
+ /**
+ * Write contents of a file from an array
+ * @param file
+ * @param encoding (null = system default)
+ * @throws CoreException wrapping java.io.FileException
+ */
+ public static void writeFileContents(File file, char[] text, String encoding) throws CoreException {
+ Check.checkArg(file);
+ FileOutputStream fos;
+ try {
+ fos = new FileOutputStream(file);
+ writeOutputStreamContents(fos, text, encoding);
+ } catch (IOException e) {
+ throw new CoreException(Logging.newStatus(UtilsPlugin.getDefault(), e));
+ }
+ }
+
+ /**
+ * Write contents on array to an output stream
+ * @param os output stream
+ * @param encoding (null is system default)
+ * @return array of text
+ * @throws CoreException wrapping java.io.FileException
+ */
+ public static void writeOutputStreamContents(OutputStream os, char[] text, String encoding) throws CoreException {
+ Check.checkArg(os);
+
+ Writer writer;
+ try {
+ if (encoding != null)
+ writer = new OutputStreamWriter(os, encoding);
+ else
+ writer = new OutputStreamWriter(os);
+
+ writeWriterContents(writer, text);
+ } catch (UnsupportedEncodingException e) {
+ throw new CoreException(Logging.newStatus(UtilsPlugin.getDefault(), e));
+ }
+ }
+
+ /**
+ * Write contents of an array to a file
+ * @param file
+ * @param encoding (null = system default)
+ * @throws CoreException wrapping java.io.FileException
+ */
+ public static void writeWriterContents(Writer writer, char[] text) throws CoreException {
+ Check.checkArg(writer);
+ try {
+ try {
+ writer.write(text, 0, text.length);
+ } finally {
+ writer.close();
+ }
+ } catch (UnsupportedEncodingException e) {
+ throw new CoreException(Logging.newStatus(UtilsPlugin.getDefault(), e));
+ } catch (IOException e) {
+ throw new CoreException(Logging.newStatus(UtilsPlugin.getDefault(), e));
+ }
+ }
+
+
+ /**
+ * Returns whether pathSegment is a valid part of a path in a Carbide project.
+ * This checks for file name validity and
+ * name only contains alpha-numeric -or- hyphen -or- underscrore -or- dot characters
+ *
+ * @param pathSegment the segment (file or folder name)
+ * @return true if valid
+ */
+ public static boolean isValidCarbideProjectPathSegment(String pathSegment) {
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ int typeMask = IResource.FILE | IResource.FOLDER;
+ boolean valid = pathSegment.length() == 0 ||
+ workspace.validateName(pathSegment, typeMask).isOK();
+ if (valid) {
+ for (int i = 0; i < pathSegment.length(); i++) {
+ char c = pathSegment.charAt(i);
+ valid = Character.isLetterOrDigit(c) || (c == '-') || (c == '_');
+ if (!valid)
+ break;
+ }
+ }
+
+ return valid;
+ }
+
+ /**
+ * Resolve a workspace-relative path to correct any problems in
+ * capitalization.
+ * @param projectName
+ * @param wsPath workspace-relative path
+ * @return resolved path, as far as actual resources exist (the suffix
+ * may be unchanged if an intervening folder is missing)
+ */
+ public static IPath getCanonicalWorkspacePath(IPath wsPath) {
+ IPath resolvedPath = new Path(""); //$NON-NLS-1$
+ IContainer container = ResourcesPlugin.getWorkspace().getRoot();
+ // flag to consume the rest of the path without lookup
+ boolean failed = false;
+ for (String segment : wsPath.segments()) {
+ if (failed || container == null) {
+ resolvedPath = resolvedPath.append(segment);
+ continue;
+ }
+
+ IResource child = container.findMember(segment);
+ if (child != null) {
+ // found, so correct caps
+ resolvedPath = resolvedPath.append(segment);
+ if (child instanceof IContainer) {
+ container = (IContainer) child;
+ } else {
+ container = null;
+ }
+ } else {
+ // not found: manually search
+ boolean found = false;
+ try {
+ for (IResource member : container.members()) {
+ if (member.getName().equalsIgnoreCase(segment)) {
+ resolvedPath = resolvedPath.append(member.getName());
+ found = true;
+ if (member instanceof IContainer) {
+ container = (IContainer) member;
+ } else {
+ container = null;
+ }
+ break;
+ }
+ }
+ } catch (CoreException e) {
+ // just fail
+ }
+ if (!found) {
+ failed = true;
+ resolvedPath = resolvedPath.append(segment);
+ }
+ }
+ }
+ return resolvedPath;
+ }
+
+ /**
+ * This is an analogue to new Path(String) but avoids some bugs in
+ * the implementation when pathString is a relative path.
+ * @param pathString
+ * @return new Path
+ */
+ public static IPath createPossiblyRelativePath(String pathString) {
+ // canonicalize slashes
+ char[] pathChars = pathString.toCharArray();
+ int offset = 0;
+ for (int i = 0; i < pathChars.length; i++) {
+ if (pathChars[i] == '\\')
+ pathChars[i] = '/';
+ }
+
+ // The bug is, if "./" appears, then "../"'s after it are dropped,
+ // so get rid of "./" early. The result will still be relative.
+ while (offset + 2 <= pathChars.length) {
+ if (pathChars[offset] == '.' && pathChars[offset+1] == '/') {
+ offset += 2;
+ } else {
+ break;
+ }
+ }
+
+ return new Path(new String(pathChars, offset, pathChars.length - offset));
+ }
+
+ /**
+ * Tell if the given path refers to a parent directory (e.g.
+ * contains ".." entries)
+ * @param path
+ * @return true if resolved path contains ".."
+ */
+ public static boolean isPathInParent(IPath path) {
+ // first see if any segments are ".." at all
+ for (int i = 0; i < path.segmentCount(); i++) {
+ if (path.segment(i).equals("..")) { //$NON-NLS-1$
+ // comprehensive check, canonicalizing
+ path = new Path(path.toString());
+ if (path.segmentCount() > 0 && path.segment(0).equals("..")) { //$NON-NLS-1$
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Recurse the directory, returning files that match the given filter.
+ * The directories "." and ".." are filtered out before the filter sees them.
+ * The filter is passed files and directories, and a directory must
+ * pass the filter to be recursed.
+ * @param dir
+ * @param filter
+ * @param recordDirectories if true, accepted directories are added to the returned list;
+ * otherwise, directories are not added to the file list.
+ * @return array of matching files , never null
+ */
+ public static File[] listFilesInTree(File dir, FileFilter filter, boolean recordDirectories) {
+ List<File> files = new ArrayList<File>();
+ listFilesInTreeHelper(files, dir, filter, recordDirectories);
+ return (File[]) files.toArray(new File[files.size()]);
+ }
+
+ private static void listFilesInTreeHelper(List<File> files, File dir, FileFilter filter, boolean recordDirectories) {
+ if (recordDirectories)
+ files.add(dir);
+
+ File[] allEntries = dir.listFiles();
+ if (allEntries == null)
+ return;
+
+ for (File fileOrDir : allEntries) {
+ if (fileOrDir.getName().equals(".") || fileOrDir.getName().equals("..")) { //$NON-NLS-1$ //$NON-NLS-2$
+ // ignore
+ } else if (fileOrDir.isDirectory()) {
+ if (filter.accept(fileOrDir)) {
+ listFilesInTreeHelper(files, fileOrDir, filter, recordDirectories);
+ }
+ } else if (filter.accept(fileOrDir)) {
+ files.add(fileOrDir);
+ }
+ }
+ }
+
+ public static URL getParentPathURL(URL url) throws CoreException {
+ URL result;
+ try {
+ String string = url.toString();
+ int loc = string.lastIndexOf('/');
+ result = new URL(string.substring(0, loc + 1));
+ } catch (Exception e) {
+ throw new CoreException(Logging.newStatus(UtilsPlugin.getDefault(), e));
+ }
+
+ return result;
+ }
+
+ /**
+ * Wrapper around {@link FileUtils#validateEdit(IFile[], Shell)}
+ * taking a single file. If a modified files multistatus is generated
+ * the single entry for the single file is retrieved and returned.
+ */
+ public static IStatus validateEdit(IFile file, Shell context) {
+ IStatus status = validateEdit(new IFile[] {file}, context);
+ if (!status.isOK()) {
+ if (status.isMultiStatus()) {
+ IStatus[] children = status.getChildren();
+ if (children != null && children.length == 1 &&
+ children[0].getSeverity() == IStatus.WARNING &&
+ children[0].getCode() == MODIFIED_FILES_STATUS) {
+ status = children[0];
+ }
+ }
+ }
+ return status;
+ }
+
+ /**
+ * Wrapper around {@link IWorkspace#validateEdit(IFile[], Object)}
+ * Checks if any of the files have been modified by the validate
+ * operations. If so a MultiStatus is returned with WARNING severity.
+ * The code for the multistatus and each child is MODIFIED_FILES_STATUS
+ * and for each child the message fields is the full workspace
+ * path to the modified file.
+ * @param files
+ * @param context a Shell if UI interaction is allowed
+ * @return OK status, non-OK status from validateEdit, or a
+ * MultiStatus with one child for each modified file.
+ */
+ public static IStatus validateEdit(IFile[] files, Shell context) {
+ List<IFile> readOnly = new ArrayList<IFile>();
+ Map<IFile, Long> timeStamps = new HashMap<IFile, Long>();
+ for (IFile file : files) {
+ if (file.isReadOnly()) {
+ readOnly.add(file);
+ timeStamps.put(file, file.getModificationStamp());
+ }
+ }
+
+ if (readOnly.isEmpty()) {
+ return Status.OK_STATUS;
+ }
+
+ IStatus status = ResourcesPlugin.getWorkspace().validateEdit(
+ readOnly.toArray(new IFile[readOnly.size()]), context);
+ if (!status.isOK())
+ return status;
+
+ List<IFile> modified = new ArrayList<IFile>();
+ for (Map.Entry<IFile, Long> entry : timeStamps.entrySet()) {
+ Long newTimeStamp = entry.getKey().getModificationStamp();
+ if (!newTimeStamp.equals(entry.getValue())) {
+ modified.add(entry.getKey());
+ }
+ }
+
+ if (modified.size() > 0) {
+ String pluginID = UtilsPlugin.getDefault().getBundle().getSymbolicName();
+ MultiStatus ms = new MultiStatus(pluginID, MODIFIED_FILES_STATUS, "modified files", null);
+ for (IFile file : modified) {
+ String path = file.getFullPath().toString();
+ ms.add(new Status(IStatus.WARNING, pluginID, MODIFIED_FILES_STATUS, path, null));
+ }
+ status = ms;
+ }
+
+ return status;
+ }
+
+ /**
+ * Get the directory used for temporary files.
+ * @return absolute directory for temporary files, which may be the current directory
+ */
+ public static File getTemporaryDirectory() {
+ File dir = new File(System.getProperty("java.io.tmpdir", //$NON-NLS-1$
+ System.getProperty("user.dir", "."))); //$NON-NLS-1$ //$NON-NLS-2$
+ try {
+ return dir.getCanonicalFile();
+ } catch (IOException e) {
+ return dir;
+ }
+ }
+
+ /**
+ * Get the path in a form amenable to comparing with another path.
+ * On Win32 hosts, this lowercases the path. On other hosts, the path is unmodified.
+ * @param path incoming path or <code>null</code>
+ * @return path converted to comparison-friendly format, or <code>null</code>
+ */
+ public static IPath getComparablePath(IPath path) {
+ if (path == null)
+ return null;
+
+ if (Platform.getOS().equals(Platform.OS_WIN32)) {
+ return new Path(path.toOSString().toLowerCase());
+ }
+
+ return path;
+ }
+
+ /**
+ * Get the file extension from path, guaranteed not to return null
+ * @param path IPath
+ * @return String non-null
+ */
+ public static String getSafeFileExtension(IPath path) {
+ String fileExtension = ""; //$NON-NLS-1$
+ if (path != null) {
+ String temp = path.getFileExtension();
+ if (temp != null)
+ fileExtension = temp;
+ }
+
+ return fileExtension;
+ }
+
+ /**
+ * Uses java.io semantics to test existence, because eclipse resources are always case-sensitive,
+ * regardless of the file system.
+ * @param resource {@link IResource}
+ * @return <code>boolean</code>
+ */
+ public static boolean exists(IResource resource) {
+ return resource.getLocation().toFile().exists();
+ }
+}