blob: c8c02b977c1f1f473daad44eafd21f5a03880f9e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2010 Freescale Semiconductor 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:
* Serge Beauchamp (Freescale Semiconductor) - [252996] initial API and implementation
* IBM Corporation - ongoing implementation
*******************************************************************************/
package org.eclipse.ui.internal.ide.misc;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.filtermatchers.AbstractFileInfoMatcher;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.ide.StringMatcher;
/**
* A file info filter that matches different file and folder attributes.
*/
public class FileInfoAttributesMatcher extends AbstractFileInfoMatcher {
public static String ID = "org.eclipse.ui.ide.multiFilter"; //$NON-NLS-1$
public static String KEY_NAME = "name"; //$NON-NLS-1$
public static String KEY_PROPJECT_RELATIVE_PATH = "projectRelativePath"; //$NON-NLS-1$
public static String KEY_LOCATION = "location"; //$NON-NLS-1$
public static String KEY_LAST_MODIFIED = "lastModified"; //$NON-NLS-1$
public static String KEY_LENGTH = "length"; //$NON-NLS-1$
public static String KEY_CREATED = "created"; //$NON-NLS-1$
public static String KEY_IS_SYMLINK = "isSymLink"; //$NON-NLS-1$
public static String KEY_IS_READONLY = "isReadOnly"; //$NON-NLS-1$
public static String OPERATOR_NONE = "none"; //$NON-NLS-1$
public static String OPERATOR_LARGER_THAN = "largerThan"; //$NON-NLS-1$
public static String OPERATOR_SMALLER_THAN = "smallerThan"; //$NON-NLS-1$
public static String OPERATOR_EQUALS = "equals"; //$NON-NLS-1$
public static String OPERATOR_BEFORE = "before"; //$NON-NLS-1$
public static String OPERATOR_AFTER = "after"; //$NON-NLS-1$
public static String OPERATOR_WITHIN = "within"; //$NON-NLS-1$
public static String OPERATOR_MATCHES = "matches"; //$NON-NLS-1$
/**
* @param key
* @return
*/
public static String[] getOperatorsForKey(String key) {
if (key.equals(KEY_NAME) || key.equals(KEY_PROPJECT_RELATIVE_PATH) || key.equals(KEY_LOCATION))
return new String[] {OPERATOR_MATCHES};
if (key.equals(KEY_IS_SYMLINK) || key.equals(KEY_IS_READONLY))
return new String[] {OPERATOR_EQUALS};
if (key.equals(KEY_LAST_MODIFIED) || key.equals(KEY_CREATED))
return new String[] {OPERATOR_EQUALS, OPERATOR_BEFORE, OPERATOR_AFTER, OPERATOR_WITHIN};
if (key.equals(KEY_LENGTH))
return new String[] {OPERATOR_EQUALS, OPERATOR_LARGER_THAN, OPERATOR_SMALLER_THAN};
return new String[] {OPERATOR_NONE};
}
/**
* @param key
* @param operator
* @return
*/
public static Class getTypeForKey(String key, String operator) {
if (key.equals(KEY_NAME) || key.equals(KEY_PROPJECT_RELATIVE_PATH) || key.equals(KEY_LOCATION))
return String.class;
if (key.equals(KEY_IS_SYMLINK) || key.equals(KEY_IS_READONLY))
return Boolean.class;
if (key.equals(KEY_LAST_MODIFIED) || key.equals(KEY_CREATED)) {
if (operator.equals(OPERATOR_WITHIN))
return Integer.class;
return Date.class;
}
if (key.equals(KEY_LENGTH))
return Integer.class;
return String.class;
}
/**
* @return
*/
public static boolean supportCreatedKey() {
if (Platform.getOS().equals(Platform.OS_WIN32) || Platform.getOS().equals(Platform.OS_MACOSX)) {
String system = System.getProperty("java.version"); //$NON-NLS-1$
double versionNumber = 0.0;
int index = system.indexOf('.');
if (index != -1) {
versionNumber = Integer.decode(system.substring(0, index)).doubleValue();
system = system.substring(index + 1);
index = system.indexOf('.');
if (index != -1) {
versionNumber += Double.parseDouble(system.substring(0, index)) / 10.0;
}
}
return versionNumber >= 1.7;
}
return false;
}
/**
* @since 3.6
*
*/
public static class Argument {
public String key = KEY_NAME;
public String pattern = new String();
public String operator = OPERATOR_EQUALS;
public boolean caseSensitive = false;
public boolean regularExpression = false;
}
/**
* @param argument
* @return
*/
public static String encodeArguments(Argument argument) {
return VERSION_IMPLEMENTATION + DELIMITER +
argument.key + DELIMITER +
argument.operator + DELIMITER +
Boolean.toString(argument.caseSensitive) + DELIMITER +
Boolean.toString(argument.regularExpression) + DELIMITER +
argument.pattern;
}
/**
* @param argument
* @return
*/
public static Argument decodeArguments(String argument) {
Argument result = new Argument();
if (argument == null)
return result;
int index = argument.indexOf(DELIMITER);
if (index == -1)
return result;
String version = argument.substring(0, index);
argument = argument.substring(index + 1);
if (!version.equals(VERSION_IMPLEMENTATION))
return result;
index = argument.indexOf(DELIMITER);
if (index == -1)
return result;
result.key = argument.substring(0, index);
argument = argument.substring(index + 1);
index = argument.indexOf(DELIMITER);
if (index == -1)
return result;
result.operator = argument.substring(0, index);
argument = argument.substring(index + 1);
index = argument.indexOf(DELIMITER);
if (index == -1)
return result;
result.caseSensitive = Boolean.valueOf(argument.substring(0, index)).booleanValue();
argument = argument.substring(index + 1);
index = argument.indexOf(DELIMITER);
if (index == -1)
return result;
result.regularExpression = Boolean.valueOf(argument.substring(0, index)).booleanValue();
result.pattern = argument.substring(index + 1);
return result;
}
static private String DELIMITER = "-"; //$NON-NLS-1$
static private String VERSION_IMPLEMENTATION = "1.0"; //$NON-NLS-1$
/*
* return value in milliseconds since epoch(1970-01-01T00:00:00Z)
*/
private static long getFileCreationTime(String fullPath) {
/*
java.nio.file.FileSystem fs = java.nio.file.FileSystems.getDefault();
java.nio.file.FileRef fileRef = fs.getPath(file);
java.nio.file.attribute.BasicFileAttributes attributes = java.nio.file.attribute.Attributes.readBasicFileAttributes(fileRef, new java.nio.file.LinkOption[0]);
return attributes.creationTime();
*/
try {
Class fileSystems = Class.forName("java.nio.file.FileSystems"); //$NON-NLS-1$
Method getDefault = fileSystems.getMethod("getDefault"); //$NON-NLS-1$
Object fs = getDefault.invoke(null);
Class fileRef = Class.forName("java.nio.file.FileRef"); //$NON-NLS-1$
Class fileSystem = Class.forName("java.nio.file.FileSystem"); //$NON-NLS-1$
Method getPath = fileSystem.getMethod("getPath", new Class[] {String.class}); //$NON-NLS-1$
Object fileRefObj = getPath.invoke(fs, new Object[] {fullPath});
Class attributes = Class.forName("java.nio.file.attribute.Attributes"); //$NON-NLS-1$
Class linkOptions = Class.forName("java.nio.file.LinkOption"); //$NON-NLS-1$
Object linkOptionsEmptyArray = Array.newInstance(linkOptions, 0);
Method readBasicFileAttributes = attributes.getMethod("readBasicFileAttributes", new Class[] {fileRef, linkOptionsEmptyArray.getClass()}); //$NON-NLS-1$
Object attributesObj = readBasicFileAttributes.invoke(null, new Object[] {fileRefObj, linkOptionsEmptyArray});
Class basicAttributes = Class.forName("java.nio.file.attribute.BasicFileAttributes"); //$NON-NLS-1$
Method creationTime = basicAttributes.getMethod("creationTime"); //$NON-NLS-1$
Object time = creationTime.invoke(attributesObj);
Class fileTime = Class.forName("java.nio.file.attribute.FileTime"); //$NON-NLS-1$
Method toMillis = fileTime.getMethod("toMillis"); //$NON-NLS-1$
Object result = toMillis.invoke(time);
if (result instanceof Long)
return ((Long) result).longValue();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return 0;
}
MatcherCache matcher = null;
private boolean fSupportsCreatedKey;
class MatcherCache {
public MatcherCache(String arguments) {
argument = decodeArguments(arguments);
type = getTypeForKey(argument.key, argument.operator);
if (type.equals(String.class)) {
if (argument.regularExpression == false)
stringMatcher = new StringMatcher(argument.pattern, argument.caseSensitive == false, false);
else
regExPattern = Pattern.compile(argument.pattern, argument.caseSensitive ? 0:Pattern.CASE_INSENSITIVE);
}
}
Argument argument;
Class type;
StringMatcher stringMatcher = null;
Pattern regExPattern = null;
public boolean match(IContainer parent, IFileInfo fileInfo) {
if (type.equals(String.class)) {
String value = new String();
if (argument.key.equals(KEY_NAME))
value = fileInfo.getName();
if (argument.key.equals(KEY_PROPJECT_RELATIVE_PATH))
value = parent.getProjectRelativePath().append(fileInfo.getName()).toPortableString();
if (argument.key.equals(KEY_LOCATION))
value = parent.getLocation().append(fileInfo.getName()).toOSString();
if (stringMatcher != null)
return stringMatcher.match(value);
if (regExPattern != null) {
Matcher m = regExPattern.matcher(value);
return m.matches();
}
}
if (type.equals(Integer.class)) {
int amount;
try {
amount = Integer.parseInt(argument.pattern);
} catch (NumberFormatException e) {
amount = 0;
}
if (argument.key.equals(KEY_LAST_MODIFIED) || argument.key.equals(KEY_CREATED)) {
// OPERATOR_WITHIN
long time = 0;
if (argument.key.equals(KEY_LAST_MODIFIED)) {
IFileInfo info = fetchInfo(parent, fileInfo);
if (!info.exists())
return false;
time = info.getLastModified();
}
if (argument.key.equals(KEY_CREATED)) {
if (!fSupportsCreatedKey)
return false;
time = getFileCreationTime(parent.getLocation().append(fileInfo.getName()).toOSString());
}
GregorianCalendar gc = new GregorianCalendar();
gc.add(Calendar.SECOND,-amount);
Date when = gc.getTime();
Date then = new Date(time);
return then.after(when);
}
if (argument.key.equals(KEY_LENGTH)) {
IFileInfo info = fetchInfo(parent, fileInfo);
if (!info.exists())
return false;
if (argument.operator.equals(OPERATOR_EQUALS))
return info.getLength() == amount;
if (argument.operator.equals(OPERATOR_LARGER_THAN))
return info.getLength() > amount;
if (argument.operator.equals(OPERATOR_SMALLER_THAN))
return info.getLength() < amount;
}
}
if (type.equals(Date.class)) {
long parameter = Long.parseLong(argument.pattern);
if (argument.key.equals(KEY_LAST_MODIFIED) || argument.key.equals(KEY_CREATED)) {
long time = 0;
if (argument.key.equals(KEY_LAST_MODIFIED)) {
IFileInfo info = fetchInfo(parent, fileInfo);
if (!info.exists())
return false;
time = info.getLastModified();
}
if (argument.key.equals(KEY_CREATED)) {
if (!fSupportsCreatedKey)
return false;
time = getFileCreationTime(parent.getLocation().append(fileInfo.getName()).toOSString());
}
Date when = new Date(parameter);
Date then = new Date(time);
if (argument.operator.equals(OPERATOR_EQUALS))
return roundToOneDay(time) == roundToOneDay(parameter);
if (argument.operator.equals(OPERATOR_BEFORE))
return then.before(when);
if (argument.operator.equals(OPERATOR_AFTER))
return then.after(when);
}
}
if (type.equals(Boolean.class)) {
boolean parameter = Boolean.valueOf(argument.pattern).booleanValue();
if (argument.key.equals(KEY_IS_READONLY)) {
IFileInfo info = fetchInfo(parent, fileInfo);
if (!info.exists())
return false;
return info.getAttribute(EFS.ATTRIBUTE_READ_ONLY) == parameter;
}
if (argument.key.equals(KEY_IS_SYMLINK)) {
IFileInfo info = fetchInfo(parent, fileInfo);
if (!info.exists())
return false;
return info.getAttribute(EFS.ATTRIBUTE_SYMLINK) == parameter;
}
}
return false;
}
private long roundToOneDay(long parameter) {
return parameter / (1000 * 60 * 60 * 24); // 1000 ms in 1 sec, 60 sec in 1 min, 60 min in 1 hour, 24 hours in 1 day
}
private IFileInfo fetchInfo(IContainer parent, IFileInfo fileInfo) {
IFileStore fileStore;
try {
fileStore = EFS.getStore(parent.getLocationURI());
} catch (CoreException e) {
return fileInfo;
}
IFileStore store = fileStore.getChild(fileInfo.getName());
return store.fetchInfo();
}
}
/**
* Creates a new factory for this filter type.
*/
public FileInfoAttributesMatcher() {
fSupportsCreatedKey = supportCreatedKey();
}
@Override
public void initialize(IProject project, Object arguments) throws CoreException {
try {
if ((arguments instanceof String) && ((String) arguments).length() > 0)
matcher = new MatcherCache((String) arguments);
} catch (PatternSyntaxException e) {
throw new CoreException(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, Platform.PLUGIN_ERROR, e.getMessage(), e));
} catch (NumberFormatException e) {
throw new CoreException(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, Platform.PLUGIN_ERROR, e.getMessage(), e));
}
}
@Override
public boolean matches(IContainer parent, IFileInfo fileInfo) throws CoreException {
if (matcher != null) {
return matcher.match(parent, fileInfo);
}
return false;
}
}