| /* |
| * Copyright 2000-2012 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.util; |
| |
| import com.intellij.openapi.util.SystemInfo; |
| import com.intellij.openapi.util.io.FileUtil; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.util.containers.ContainerUtil; |
| import com.intellij.util.xmlb.XmlSerializer; |
| import com.intellij.util.xmlb.annotations.Attribute; |
| import com.intellij.util.xmlb.annotations.Tag; |
| import org.jdom.Element; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.Collection; |
| import java.util.List; |
| |
| /** |
| * @author traff |
| */ |
| public class PathMappingSettings implements Cloneable { |
| @NotNull |
| private List<PathMapping> myPathMappings; |
| |
| public PathMappingSettings(@Nullable final List<PathMapping> pathMappings) { |
| myPathMappings = create(pathMappings); |
| } |
| |
| @NotNull |
| private static List<PathMapping> create(@Nullable final List<PathMapping> mappings) { |
| List<PathMapping> result = ContainerUtil.newArrayList(); |
| if (mappings != null) { |
| for (PathMapping m : mappings) { |
| if (m != null && !isEmpty(m.myLocalRoot, m.myRemoteRoot)) { |
| result.add(m); |
| } |
| } |
| } |
| return result; |
| } |
| |
| public PathMappingSettings() { |
| myPathMappings = ContainerUtil.newArrayList(); |
| } |
| |
| public List<String> convertToRemote(Collection<String> paths) { |
| List<String> result = ContainerUtil.newArrayList(); |
| for (String p: paths) { |
| result.add(convertToRemote(p)); |
| } |
| return result; |
| } |
| |
| private static class BestMappingSelector { |
| private int myBestWeight = -1; |
| private PathMapping myBest = null; |
| |
| public void consider(PathMapping mapping, int weight) { |
| if (weight > myBestWeight) { |
| myBestWeight = weight; |
| myBest = mapping; |
| } |
| } |
| |
| @Nullable |
| public PathMapping get() { |
| return myBest; |
| } |
| } |
| |
| @NotNull |
| public String convertToLocal(String remotePath) { |
| BestMappingSelector selector = new BestMappingSelector(); |
| for (PathMapping mapping : myPathMappings) { |
| if (mapping.canReplaceRemote(remotePath)) { |
| selector.consider(mapping, mapping.getRemoteLen()); |
| } |
| } |
| |
| if (selector.get() != null) { |
| //noinspection ConstantConditions |
| return selector.get().mapToLocal(remotePath); |
| } |
| |
| return remotePath; |
| } |
| |
| public String convertToRemote(String localPath) { |
| BestMappingSelector selector = new BestMappingSelector(); |
| for (PathMapping mapping : myPathMappings) { |
| if (mapping.canReplaceLocal(localPath)) { |
| selector.consider(mapping, mapping.getLocalLen()); |
| } |
| } |
| |
| if (selector.get() != null) { |
| //noinspection ConstantConditions |
| return selector.get().mapToRemote(localPath); |
| } |
| |
| return localPath; |
| } |
| |
| public void add(PathMapping mapping) { |
| if (isEmpty(mapping.myLocalRoot, mapping.myRemoteRoot)) { |
| return; |
| } |
| myPathMappings.add(mapping); |
| } |
| |
| public void addMapping(String local, String remote) { |
| PathMapping mapping = new PathMapping(local, remote); |
| if (isEmpty(mapping.myLocalRoot, mapping.myRemoteRoot)) { |
| return; |
| } |
| myPathMappings.add(mapping); |
| } |
| |
| public boolean canReplaceRemote(String remotePath) { |
| for (PathMapping mapping : myPathMappings) { |
| if (mapping.canReplaceRemote(remotePath)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public boolean canReplaceLocal(String localPath) { |
| for (PathMapping mapping : myPathMappings) { |
| if (mapping.canReplaceLocal(localPath)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private static String norm(@NotNull String path) { |
| return FileUtil.toSystemIndependentName(path); |
| } |
| |
| private static String normLocal(@NotNull String path) { |
| if (SystemInfo.isWindows) { |
| path = path.toLowerCase(); |
| } |
| |
| return norm(path); |
| } |
| |
| public boolean isUseMapping() { |
| return myPathMappings.size() > 0; |
| } |
| |
| @NotNull |
| public List<PathMapping> getPathMappings() { |
| return myPathMappings; |
| } |
| |
| public void setPathMappings(@Nullable final List<PathMapping> pathMappings) { |
| myPathMappings = create(pathMappings); |
| } |
| |
| @NotNull |
| public static String mapToLocal(String path, String remoteRoot, String localRoot) { |
| if (isEmpty(localRoot, remoteRoot)) { |
| return path; |
| } |
| path = norm(path); |
| String remotePrefix = norm(remoteRoot); |
| path = path.replace(remotePrefix, norm(localRoot)); |
| return path; |
| } |
| |
| public static boolean isEmpty(String localRoot, String remoteRoot) { |
| return StringUtil.isEmpty(localRoot) || StringUtil.isEmpty(remoteRoot); |
| } |
| |
| @Nullable |
| public static PathMappingSettings readExternal(@Nullable final Element element) { |
| if (element == null) { |
| return null; |
| } |
| |
| final Element settingsElement = element.getChild(PathMappingSettings.class.getSimpleName()); |
| if (settingsElement == null) { |
| return null; |
| } |
| |
| return XmlSerializer.deserialize(settingsElement, PathMappingSettings.class); |
| } |
| |
| public static void writeExternal(@Nullable final Element element, @Nullable final PathMappingSettings mappings) { |
| if (element == null || mappings == null || !mappings.isUseMapping()) { |
| return; |
| } |
| element.addContent(XmlSerializer.serialize(mappings)); |
| } |
| |
| public void addAll(@NotNull PathMappingSettings settings) { |
| myPathMappings.addAll(settings.getPathMappings()); |
| } |
| |
| @Tag("mapping") |
| public static class PathMapping { |
| private String myLocalRoot; |
| private String myRemoteRoot; |
| |
| public PathMapping() { |
| } |
| |
| public PathMapping(String localRoot, String remoteRoot) { |
| myLocalRoot = normalize(localRoot); |
| myRemoteRoot = normalize(remoteRoot); |
| } |
| |
| @Nullable |
| private static String normalize(@Nullable String path) { |
| if (path == null) { |
| return null; |
| } |
| else { |
| return trimSlash(FileUtil.toSystemIndependentName(path)); |
| } |
| } |
| |
| @Attribute("local-root") |
| public String getLocalRoot() { |
| return myLocalRoot; |
| } |
| |
| @Attribute("remote-root") |
| public String getRemoteRoot() { |
| return myRemoteRoot; |
| } |
| |
| public int getLocalLen() { |
| return myLocalRoot != null ? myLocalRoot.length() : -1; |
| } |
| |
| public int getRemoteLen() { |
| return myRemoteRoot != null ? myRemoteRoot.length() : -1; |
| } |
| |
| public void setLocalRoot(String localRoot) { |
| myLocalRoot = localRoot; |
| } |
| |
| public void setRemoteRoot(String remoteRoot) { |
| myRemoteRoot = remoteRoot; |
| } |
| |
| @NotNull |
| public String mapToLocal(@NotNull String path) { |
| return PathMappingSettings.mapToLocal(path, myRemoteRoot, myLocalRoot); |
| } |
| |
| public boolean canReplaceLocal(@NotNull String path) { |
| if (isEmpty()) { |
| return false; |
| } |
| |
| String localPrefix = normLocal(myLocalRoot); |
| return localPrefix.length() > 0 && normLocal(path).startsWith(localPrefix); |
| } |
| |
| public String mapToRemote(@NotNull String path) { |
| if (isEmpty()) { |
| return path; |
| } |
| |
| if (canReplaceLocal(path)) { |
| return norm(myRemoteRoot) + norm(path).substring(normLocal(myLocalRoot).length()); |
| } |
| return path; |
| } |
| |
| private boolean isEmpty() { |
| return PathMappingSettings.isEmpty(myLocalRoot, myRemoteRoot); |
| } |
| |
| private static String trimSlash(String s) { |
| return StringUtil.trimEnd(s, "/"); |
| } |
| |
| public boolean canReplaceRemote(String path) { |
| if (isEmpty()) { |
| return false; |
| } |
| |
| path = norm(path); |
| String remotePrefix = norm(myRemoteRoot); |
| return myRemoteRoot.length() > 0 && path.startsWith(remotePrefix); |
| } |
| |
| @Override |
| public PathMapping clone() { |
| return new PathMapping(myLocalRoot, myRemoteRoot); |
| } |
| } |
| } |