notifications for unknown macros

This commit is contained in:
Alexey Pegov
2009-10-06 17:04:03 +04:00
parent 2b7e3c2ac9
commit 5a0f59add8
39 changed files with 383 additions and 190 deletions
@@ -131,7 +131,7 @@ public class GenerationOptionsImpl extends GenerationOptions {
if (myMacroReplacementMap.size() == 0) {
return path; // optimization
}
return myMacroReplacementMap.substitute(path, SystemInfo.isFileSystemCaseSensitive, null);
return myMacroReplacementMap.substitute(path, SystemInfo.isFileSystemCaseSensitive);
}
public String getPropertyRefForUrl(String url) {
@@ -40,7 +40,6 @@ import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Set;
/**
@@ -87,13 +86,8 @@ public class ExistingModuleLoader extends ModuleBuilder {
usedMacros.remove("$" + PathMacrosImpl.MODULE_DIR_MACRO_NAME + "$");
usedMacros.removeAll(definedMacros);
final HashMap<String, String> map = new HashMap<String, String>();
for (String v : usedMacros) {
map.put(v, null);
}
if (usedMacros.size() > 0) {
final boolean ok = ProjectMacrosUtil.showMacrosConfigurationDialog(current, map);
final boolean ok = ProjectMacrosUtil.showMacrosConfigurationDialog(current, usedMacros);
if (!ok) {
return false;
}
@@ -122,7 +122,7 @@ public abstract class ModuleTestCase extends IdeaTestCase {
final ProjectImpl project = (ProjectImpl)myProject;
project.setOptimiseTestLoadSpeed(false);
final ModuleRootManagerImpl moduleRootManager = (ModuleRootManagerImpl)ModuleRootManager.getInstance(module);
module.getStateStore().initComponent(moduleRootManager);
module.getStateStore().initComponent(moduleRootManager, false);
project.setOptimiseTestLoadSpeed(true);
}
@@ -116,7 +116,7 @@ public class ConversionContextImpl implements ConversionContext {
List<File> files = new ArrayList<File>();
for (Element module : JDomConvertingUtil.getChildren(modules, ModuleManagerImpl.ELEMENT_MODULE)) {
String filePath = module.getAttributeValue(ModuleManagerImpl.ATTRIBUTE_FILEPATH);
filePath = macros.substitute(filePath, true, null);
filePath = macros.substitute(filePath, true);
files.add(new File(FileUtil.toSystemDependentName(filePath)));
}
return files.toArray(new File[files.size()]);
@@ -1,14 +1,20 @@
package com.intellij.openapi.components.impl.stores;
import com.intellij.notification.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.components.PathMacroSubstitutor;
import com.intellij.openapi.components.StateStorage;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.components.impl.ComponentManagerImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleTypeManager;
import com.intellij.openapi.module.impl.ModuleImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ex.ProjectEx;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import org.jdom.Attribute;
@@ -17,12 +23,10 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.event.HyperlinkEvent;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.*;
public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IModuleStore {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.ModuleStoreImpl");
@@ -45,7 +49,32 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM
return storage;
}
@Override
public String initComponent(@NotNull Object component, boolean service) {
final String componentName = super.initComponent(component, service);
if (!ApplicationManager.getApplication().isHeadlessEnvironment() && !ApplicationManager.getApplication().isUnitTestMode()) {
if (service && componentName != null) {
final TrackingPathMacroSubstitutor substitutor = getStateStorageManager().getMacroSubstitutor();
if (substitutor != null) {
final Collection<String> macros = substitutor.getUnknownMacros(componentName);
if (!macros.isEmpty()) {
Notifications.Bus.notify(new Notification("Load Error", "Error loading component",
String.format("<p>Undefined Path Variables: <i>%s</i>. <a href=\"\">Fix it!</a></p>",
StringUtil.join(macros, ", ")), NotificationType.ERROR,
new NotificationListener() {
public void hyperlinkUpdate(@NotNull Notification notification,
@NotNull HyperlinkEvent event) {
myModule.checkUnknownMacros(myModule.getProject(), notification);
}
}), NotificationDisplayType.STICKY_BALLOON, myModule.getProject());
}
}
}
}
return componentName;
}
@Override
public void load() throws IOException, StateStorage.StateStorageException {
@@ -54,8 +83,29 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM
final ModuleFileData storageData = getMainStorageData();
final String moduleTypeId = storageData.myOptions.get(ModuleImpl.ELEMENT_TYPE);
myModule.setModuleType(ModuleTypeManager.getInstance().findByID(moduleTypeId));
}
if (ApplicationManager.getApplication().isHeadlessEnvironment() || ApplicationManager.getApplication().isUnitTestMode()) return;
final TrackingPathMacroSubstitutor substitutor = getStateStorageManager().getMacroSubstitutor();
if (substitutor != null) {
final Collection<String> macros = substitutor.getUnknownMacros(null);
if (!macros.isEmpty()) {
final Project project = myModule.getProject();
StartupManager.getInstance(project).runWhenProjectIsInitialized(new Runnable() {
public void run() {
Notifications.Bus.notify(new Notification("Load Error", String.format("Error loading module '%s':", myModule.getName()),
String.format(
"<p>Undefined Path Variable(s): <i>%s</i>. <a href=\"\">Fix it!</a></p>",
StringUtil.join(macros, ", ")), NotificationType.ERROR, new NotificationListener() {
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
myModule.checkUnknownMacros(myModule.getProject(), notification);
}
}), NotificationDisplayType.STICKY_BALLOON, project);
}
});
}
}
}
public ModuleFileData getMainStorageData() throws StateStorage.StateStorageException {
return (ModuleFileData)super.getMainStorageData();
@@ -21,19 +21,19 @@ public class ProjectWithModulesStoreImpl extends ProjectStoreImpl {
super(project);
}
protected void reinitComponents(final Set<String> componentNames) {
super.reinitComponents(componentNames);
public void reinitComponents(final Set<String> componentNames, final boolean reloadData) {
super.reinitComponents(componentNames, reloadData);
for (Module module : getPersistentModules()) {
((ComponentStoreImpl)((ModuleImpl)module).getStateStore()).reinitComponents(componentNames);
((ModuleImpl)module).getStateStore().reinitComponents(componentNames, reloadData);
}
}
protected boolean isReloadPossible(final Set<String> componentNames) {
public boolean isReloadPossible(final Set<String> componentNames) {
if (!super.isReloadPossible(componentNames)) return false;
for (Module module : getPersistentModules()) {
if (!((ComponentStoreImpl)((ModuleImpl)module).getStateStore()).isReloadPossible(componentNames)) return false;
if (!((ModuleImpl)module).getStateStore().isReloadPossible(componentNames)) return false;
}
return true;
@@ -106,11 +106,8 @@ public class ClasspathStorage implements StateStorage {
model.dispose();
}
}
final HashMap<String, String> map = new HashMap<String, String>();
for (String v : macros) {
map.put(v, null);
}
final boolean macrosOk = ProjectMacrosUtil.checkMacros(module.getProject(), map);
final boolean macrosOk = ProjectMacrosUtil.checkMacros(module.getProject(), macros);
PathMacroManager.getInstance(module).expandPaths(element);
ModuleRootManagerImpl.ModuleRootManagerState moduleRootManagerState = new ModuleRootManagerImpl.ModuleRootManagerState();
moduleRootManagerState.readExternal(element);
@@ -128,7 +125,7 @@ public class ClasspathStorage implements StateStorage {
}
}
public boolean hasState(final Object component, final String componentName, final Class<?> aClass)
public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData)
throws StateStorageException {
return true;
}
@@ -33,7 +33,7 @@ public interface StateStorage {
@Nullable
<T> T getState(final Object component, final String componentName, Class<T> stateClass, @Nullable T mergeInto) throws StateStorageException;
boolean hasState(final Object component, final String componentName, final Class<?> aClass) throws StateStorageException;
boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException;
@NotNull
ExternalizationSession startExternalization();
@@ -32,7 +32,7 @@ public interface StorageAnnotationsDefaultValues {
throw new UnsupportedOperationException("Method getState is not supported in " + getClass());
}
public boolean hasState(final Object component, final String componentName, final Class<?> aClass) throws StateStorageException {
public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException {
throw new UnsupportedOperationException("Method hasState not implemented in " + getClass());
}
@@ -26,11 +26,11 @@ public class PathMacrosCollector extends PathMacroMap {
public static Set<String> getMacroNames(Element root) {
final PathMacrosCollector collector = new PathMacrosCollector();
collector.substitute(root, true, null);
collector.substitute(root, true);
return new HashSet<String>(collector.myMacroMap.keySet());
}
public String substitute(String text, boolean caseSensitive, final Set<String> usedMacros) {
public String substitute(String text, boolean caseSensitive) {
myMatcher.reset(text);
while (myMatcher.find()) {
final String macroName = myMatcher.group(1);
@@ -51,10 +51,10 @@ public class ReplacePathToMacroMap extends PathMacroMap {
}
}
public String substitute(String text, boolean caseSensitive, final Set<String> usedMacros) {
public String substitute(String text, boolean caseSensitive) {
for (final String path : getPathIndex()) {
final String macro = get(path);
text = replacePathMacro(text, path, macro, caseSensitive, usedMacros);
text = replacePathMacro(text, path, macro, caseSensitive);
}
return text;
}
@@ -62,8 +62,7 @@ public class ReplacePathToMacroMap extends PathMacroMap {
private static String replacePathMacro(String text,
String path,
final String macro,
boolean caseSensitive,
final Set<String> usedMacros) {
boolean caseSensitive) {
if (text.length() < path.length() || path.length() == 0) {
return text;
}
@@ -93,7 +92,6 @@ public class ReplacePathToMacroMap extends PathMacroMap {
newText.append(macro);
newText.append(text.substring(endOfOccurence));
logUsage(macro, usedMacros);
return newText.toString();
}
@@ -103,10 +101,10 @@ public class ReplacePathToMacroMap extends PathMacroMap {
}
@Override
public String substituteRecursively(String text, final boolean caseSensitive, final Set<String> usedMacros) {
public String substituteRecursively(String text, final boolean caseSensitive) {
for (final String path : getPathIndex()) {
final String macro = get(path);
text = replacePathMacroRecursively(text, path, macro, caseSensitive, usedMacros);
text = replacePathMacroRecursively(text, path, macro, caseSensitive);
}
return text;
}
@@ -114,8 +112,7 @@ public class ReplacePathToMacroMap extends PathMacroMap {
private static String replacePathMacroRecursively(String text,
String path,
final String macro,
boolean caseSensitive,
final Set<String> usedMacros) {
boolean caseSensitive) {
if (text.length() < path.length()) {
return text;
}
@@ -151,7 +148,6 @@ public class ReplacePathToMacroMap extends PathMacroMap {
else {
newText.append(text.substring(i, occurrenceOfPath));
newText.append(macro);
logUsage(macro, usedMacros);
i = occurrenceOfPath + path.length();
}
}
@@ -162,31 +158,6 @@ public class ReplacePathToMacroMap extends PathMacroMap {
}
}
private static void logUsage(String macroReplacement, final Set<String> usedMacros) {
if (usedMacros == null) return;
int idx = 0;
for (String protocol : PROTOCOLS) {
if (StringUtil.startsWithConcatenationOf(macroReplacement, protocol, "://")) {
idx = protocol.length() + 3;
}
else if (StringUtil.startsWithConcatenationOf(macroReplacement, protocol, ":/")) {
idx = protocol.length() + 2;
}
else if (StringUtil.startsWithConcatenationOf(macroReplacement, protocol, ":")) {
idx = protocol.length() + 1;
}
}
macroReplacement = macroReplacement.substring(idx);
if (macroReplacement.length() >= 2 && macroReplacement.startsWith("$") && macroReplacement.endsWith("$")) {
macroReplacement = macroReplacement.substring(1, macroReplacement.length() - 1);
}
usedMacros.add(macroReplacement);
}
public List<String> getPathIndex() {
if (myPathsIndex == null || myPathsIndex.size() != size()) {
@@ -7,7 +7,7 @@ import com.intellij.openapi.options.ConfigurationException;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Map;
import java.util.Collection;
/**
* @author dsl
@@ -24,7 +24,7 @@ public class PathMacroListEditor {
this(null);
}
public PathMacroListEditor(Map<String, String> undefinedMacroNames) {
public PathMacroListEditor(final Collection<String> undefinedMacroNames) {
myPathMacroTable = undefinedMacroNames != null ? new PathMacroTable(undefinedMacroNames) : new PathMacroTable();
myScrollPane.setViewportView(myPathMacroTable);
myAddButton.addActionListener(new ActionListener() {
@@ -33,13 +33,13 @@ public class PathMacroTable extends Table {
}
};
private final Map<String, String> myUndefinedMacroNames;
private final Collection<String> myUndefinedMacroNames;
public PathMacroTable() {
this(null);
}
public PathMacroTable(Map<String, String> undefinedMacroNames) {
public PathMacroTable(final Collection<String> undefinedMacroNames) {
myUndefinedMacroNames = undefinedMacroNames;
setModel(myTableModel);
TableColumn column = getColumnModel().getColumn(NAME_COLUMN);
@@ -147,7 +147,7 @@ public class PathMacroTable extends Table {
}
if (myUndefinedMacroNames != null) {
for (String undefinedMacroName : myUndefinedMacroNames.keySet()) {
for (String undefinedMacroName : myUndefinedMacroNames) {
macros.add(new Pair<String, String>(undefinedMacroName, ""));
}
}
@@ -7,7 +7,6 @@ package com.intellij.openapi.components;
import com.intellij.openapi.util.text.StringUtil;
import java.util.Map;
import java.util.Set;
/**
* @author Eugene Zhuravlev
@@ -19,7 +18,7 @@ public class ExpandMacroToPathMap extends PathMacroMap {
put("$" + macroName + "$", quotePath(path));
}
public String substitute(String text, boolean caseSensitive, final Set<String> usedMacros) {
public String substitute(String text, boolean caseSensitive) {
for (Map.Entry<String, String> entry : entries()) {
// when replacing macros with actual paths the replace utility may be used as always 'case-sensitive'
// for case-insensitive file systems there will be no unnecesary toLowerCase() transforms.
@@ -9,7 +9,6 @@ import org.jdom.Attribute;
import org.jdom.Comment;
import org.jdom.Element;
import org.jdom.Text;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.LinkedHashMap;
@@ -41,34 +40,22 @@ public abstract class PathMacroMap {
myMacroMap.put(fromText, toText);
}
@SuppressWarnings({"WeakerAccess"})
public abstract String substitute(String text, boolean caseSensitive, @Nullable final Set<String> usedMacros);
public abstract String substitute(String text, boolean caseSensitive);
public final void substitute(Element e, boolean caseSensitive, @Nullable final Set<String> usedMacros) {
substitute(e, caseSensitive, usedMacros, false);
public final void substitute(Element e, boolean caseSensitive) {
substitute(e, caseSensitive, false);
}
public final void substitute(Element e, boolean caseSensitive, @Nullable final Set<String> usedMacros, final boolean recursively) {
public final void substitute(Element e, boolean caseSensitive, final boolean recursively) {
List content = e.getContent();
for (Object child : content) {
if (child instanceof Element) {
Element element = (Element)child;
//mike
//dirty hack: do not substitute macroses in path macroses declarations.
//I can't find a way to disable macro saving in one component (yet).
if (element.getName().equals("macro") &&
element.getAttributes().size() == 2 &&
element.getAttributeValue("name") != null &&
element.getAttributeValue("value") != null &&
element.getChildren().isEmpty()) continue;
substitute(element, caseSensitive, usedMacros, recursively);
substitute(element, caseSensitive, recursively);
}
else if (child instanceof Text) {
Text t = (Text)child;
t.setText(recursively ? substituteRecursively(t.getText(), caseSensitive, usedMacros) : substitute(t.getText(), caseSensitive, usedMacros));
t.setText(recursively ? substituteRecursively(t.getText(), caseSensitive) : substitute(t.getText(), caseSensitive));
}
else if (child instanceof Comment) {
/*do not substitute in comments
@@ -84,12 +71,15 @@ public abstract class PathMacroMap {
List attributes = e.getAttributes();
for (final Object attribute1 : attributes) {
Attribute attribute = (Attribute)attribute1;
attribute.setValue(recursively? substituteRecursively(attribute.getValue(), caseSensitive, usedMacros) : substitute(attribute.getValue(), caseSensitive, usedMacros));
final String value = recursively
? substituteRecursively(attribute.getValue(), caseSensitive)
: substitute(attribute.getValue(), caseSensitive);
attribute.setValue(value);
}
}
public String substituteRecursively(String text, boolean caseSensitive, Set<String> usedMacros) {
return substitute(text, caseSensitive, usedMacros);
public String substituteRecursively(String text, boolean caseSensitive) {
return substitute(text, caseSensitive);
}
public int size() {
@@ -1,9 +1,14 @@
package com.intellij.openapi.components;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Set;
public interface TrackingPathMacroSubstitutor extends PathMacroSubstitutor {
Set<String> getUsedMacros();
Collection<String> getUnknownMacros(@Nullable String componentName);
Collection<String> getComponents(final Collection<String> macros);
void addUnknownMacros(String componentName, Collection<String> unknownMacros);
void invalidateUnknownMacros(Set<String> macros);
void reset();
void reset(Set<String> usedMacros);
}
@@ -1,9 +1,12 @@
package com.intellij.openapi.components.ex;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.notification.Notification;
import com.intellij.openapi.components.ComponentConfig;
import com.intellij.openapi.components.ComponentManager;
import com.intellij.openapi.components.impl.stores.IComponentStore;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
@@ -25,4 +28,6 @@ public interface ComponentManagerEx extends ComponentManager {
void registerComponent(ComponentConfig config, IdeaPluginDescriptor pluginDescriptor);
IComponentStore getComponentStore();
void checkUnknownMacros(@NotNull Project project, @NotNull Notification notification);
}
@@ -7,12 +7,11 @@ import com.intellij.openapi.components.ExpandMacroToPathMap;
import com.intellij.openapi.components.PathMacroManager;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.util.containers.FactoryMap;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
public class BasePathMacroManager extends PathMacroManager {
private PathMacrosImpl myPathMacros;
@@ -49,28 +48,28 @@ public class BasePathMacroManager extends PathMacroManager {
}
public TrackingPathMacroSubstitutor createTrackingSubstitutor() {
return new MyTrackingPathMacroSubstitutor(new HashSet<String>());
return new MyTrackingPathMacroSubstitutor();
}
public String expandPath(final String path) {
return getExpandMacroMap().substitute(path, SystemInfo.isFileSystemCaseSensitive, null);
return getExpandMacroMap().substitute(path, SystemInfo.isFileSystemCaseSensitive);
}
public String collapsePath(final String path) {
return getReplacePathMap().substitute(path, SystemInfo.isFileSystemCaseSensitive, null);
return getReplacePathMap().substitute(path, SystemInfo.isFileSystemCaseSensitive);
}
public void collapsePathsRecursively(final Element element) {
getReplacePathMap().substitute(element, SystemInfo.isFileSystemCaseSensitive, null, true);
getReplacePathMap().substitute(element, SystemInfo.isFileSystemCaseSensitive, true);
}
public void expandPaths(final Element element) {
getExpandMacroMap().substitute(element, SystemInfo.isFileSystemCaseSensitive, null);
getExpandMacroMap().substitute(element, SystemInfo.isFileSystemCaseSensitive);
}
public void collapsePaths(final Element element) {
getReplacePathMap().substitute(element, SystemInfo.isFileSystemCaseSensitive, null);
getReplacePathMap().substitute(element, SystemInfo.isFileSystemCaseSensitive);
}
public PathMacrosImpl getPathMacros() {
@@ -88,43 +87,87 @@ public class BasePathMacroManager extends PathMacroManager {
}
private class MyTrackingPathMacroSubstitutor implements TrackingPathMacroSubstitutor {
private final Set<String> myUsedMacros;
private final Map<String, Set<String>> myMacroToComponentNames = new FactoryMap<String, Set<String>>() {
@Override
protected Set<String> create(String key) {
return new HashSet<String>();
}
};
public MyTrackingPathMacroSubstitutor(final Set<String> usedMacros) {
myUsedMacros = usedMacros;
}
private final Map<String, Set<String>> myComponentNameToMacros = new FactoryMap<String, Set<String>>() {
@Override
protected Set<String> create(String key) {
return new HashSet<String>();
}
};
public Set<String> getUsedMacros() {
return Collections.unmodifiableSet(myUsedMacros);
public MyTrackingPathMacroSubstitutor() {
}
public void reset() {
myUsedMacros.clear();
myMacroToComponentNames.clear();
myComponentNameToMacros.clear();
}
public String expandPath(final String path) {
return getExpandMacroMap().substitute(path, SystemInfo.isFileSystemCaseSensitive, myUsedMacros);
return getExpandMacroMap().substitute(path, SystemInfo.isFileSystemCaseSensitive);
}
public String collapsePath(final String path) {
return getReplacePathMap().substitute(path, SystemInfo.isFileSystemCaseSensitive, myUsedMacros);
return getReplacePathMap().substitute(path, SystemInfo.isFileSystemCaseSensitive);
}
public void expandPaths(final Element element) {
getExpandMacroMap().substitute(element, SystemInfo.isFileSystemCaseSensitive, myUsedMacros);
getExpandMacroMap().substitute(element, SystemInfo.isFileSystemCaseSensitive);
}
public void collapsePaths(final Element element) {
getReplacePathMap().substitute(element, SystemInfo.isFileSystemCaseSensitive, myUsedMacros);
}
public void reset(final Set<String> usedMacros) {
reset();
myUsedMacros.addAll(usedMacros);
getReplacePathMap().substitute(element, SystemInfo.isFileSystemCaseSensitive);
}
public int hashCode() {
return getExpandMacroMap().hashCode();
}
public void invalidateUnknownMacros(final Set<String> macros) {
for (final String macro : macros) {
final Set<String> components = myMacroToComponentNames.get(macro);
for (final String component : components) {
myComponentNameToMacros.remove(component);
}
myMacroToComponentNames.remove(macro);
}
}
public Collection<String> getComponents(final Collection<String> macros) {
final Set<String> result = new HashSet<String>();
for (String macro : myMacroToComponentNames.keySet()) {
if (macros.contains(macro)) {
result.addAll(myMacroToComponentNames.get(macro));
}
}
return result;
}
public Collection<String> getUnknownMacros(final String componentName) {
if (componentName == null) {
return Collections.unmodifiableSet(myMacroToComponentNames.keySet());
} else {
return Collections.unmodifiableSet(myComponentNameToMacros.get(componentName));
}
}
public void addUnknownMacros(final String componentName, final Collection<String> unknownMacros) {
if (unknownMacros.isEmpty()) return;
for (String unknownMacro : unknownMacros) {
final Set<String> stringList = myMacroToComponentNames.get(unknownMacro);
stringList.add(componentName);
}
myComponentNameToMacros.get(componentName).addAll(unknownMacros);
}
}
}
@@ -2,19 +2,22 @@ package com.intellij.openapi.components.impl;
import com.intellij.diagnostic.PluginException;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.notification.Notification;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathMacros;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
import com.intellij.openapi.components.BaseComponent;
import com.intellij.openapi.components.ComponentConfig;
import com.intellij.openapi.components.ComponentManager;
import com.intellij.openapi.components.StateStorage;
import com.intellij.openapi.components.*;
import com.intellij.openapi.components.ex.ComponentManagerEx;
import com.intellij.openapi.components.impl.stores.IComponentStore;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.project.impl.ProjectMacrosUtil;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.util.ArrayUtil;
@@ -34,9 +37,7 @@ import org.picocontainer.defaults.ConstructorInjectionComponentAdapter;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* @author mike
@@ -217,7 +218,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
}
try {
getStateStore().initComponent(component);
getStateStore().initComponent(component, false);
if (component instanceof BaseComponent) {
((BaseComponent)component).initComponent();
}
@@ -233,6 +234,46 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements
}
}
public void checkUnknownMacros(@NotNull final Project project, @NotNull final Notification notification) {
final IComponentStore stateStore = getStateStore();
final TrackingPathMacroSubstitutor substitutor = stateStore.getStateStorageManager().getMacroSubstitutor();
if (substitutor != null) {
final Collection<String> macros = substitutor.getUnknownMacros(null);
if (!macros.isEmpty()) {
if (ProjectMacrosUtil.checkMacros(project, new HashSet<String>(macros))) {
final PathMacros pathMacros = PathMacros.getInstance();
boolean expire = true;
final Set<String> macros2invalidate = new HashSet<String>(macros);
for (Iterator it = macros2invalidate.iterator(); it.hasNext();) {
final String macro = (String)it.next();
if (null == pathMacros.getValue(macro)) {
it.remove();
expire = false;
}
}
final Set<String> components = new HashSet<String>(substitutor.getComponents(macros2invalidate));
if (stateStore.isReloadPossible(components)) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
stateStore.reinitComponents(components, true);
}
});
substitutor.invalidateUnknownMacros(macros2invalidate);
if (expire) notification.expire();
}
else {
if (Messages.showYesNoDialog(project, "Component could not be reloaded. Reload project?", "Configuration changed",
Messages.getQuestionIcon()) == 0) {
ProjectManagerEx.getInstanceEx().reloadProject(project);
}
}
}
}
}
}
protected void handleInitComponentError(final Throwable ex, final boolean fatal, final String componentClassName) {
LOG.error(ex);
}
@@ -116,12 +116,14 @@ public class ServiceManagerImpl implements BaseComponent {
});
}
private Object initializeInstance(final PicoContainer container) {
protected Object initializeInstance(final PicoContainer container) {
final Object serviceInstance = getDelegate().getComponentInstance(container);
if (serviceInstance instanceof Disposable) {
Disposer.register(myComponentManager, (Disposable)serviceInstance);
}
myComponentManager.getComponentStore().initComponent(serviceInstance);
myComponentManager.getComponentStore().initComponent(serviceInstance, true);
return serviceInstance;
}
@@ -120,7 +120,7 @@ class ApplicationStoreImpl extends ComponentStoreImpl implements IApplicationSto
try {
doReload(changedFiles, componentNames);
reinitComponents(componentNames);
reinitComponents(componentNames, false);
}
finally {
myApplication.getMessageBus().syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateFinished();
@@ -98,7 +98,7 @@ abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl {
}
public BaseStorageData getMainStorageData() throws StateStorage.StateStorageException {
return (BaseStorageData) getMainStorage().getStorageData();
return (BaseStorageData) getMainStorage().getStorageData(false);
}
@Override
@@ -47,25 +47,26 @@ abstract class ComponentStoreImpl implements IComponentStore {
throw new UnsupportedOperationException("Method getDefaultsStorage is not supported in " + getClass());
}
public void initComponent(@NotNull final Object component) {
public String initComponent(@NotNull final Object component, final boolean service) {
boolean isSerializable = component instanceof JDOMExternalizable ||
component instanceof PersistentStateComponent ||
component instanceof SettingsSavingComponent;
if (!isSerializable) return;
if (!isSerializable) return null;
if (component instanceof SettingsSavingComponent) {
SettingsSavingComponent settingsSavingComponent = (SettingsSavingComponent)component;
mySettingsSavingComponents.add(settingsSavingComponent);
}
final String[] componentName = {null};
final Runnable r = new Runnable() {
public void run() {
if (component instanceof PersistentStateComponent) {
initPersistentComponent((PersistentStateComponent<?>)component);
componentName[0] = initPersistentComponent((PersistentStateComponent<?>)component, false);
}
else if (component instanceof JDOMExternalizable) {
initJdomExternalizable((JDOMExternalizable)component);
componentName[0] = initJdomExternalizable((JDOMExternalizable)component);
}
}
};
@@ -77,6 +78,8 @@ abstract class ComponentStoreImpl implements IComponentStore {
else {
applicationEx.runReadAction(r);
}
return componentName[0];
}
public boolean isSaving() {
@@ -146,22 +149,23 @@ abstract class ComponentStoreImpl implements IComponentStore {
session.setStateInOldStorage(component, componentName, component);
}
void initJdomExternalizable(@NotNull JDOMExternalizable component) {
@Nullable
String initJdomExternalizable(@NotNull JDOMExternalizable component) {
final String componentName = getComponentName(component);
myComponents.put(componentName, component);
if (optimizeTestLoading()) return;
if (optimizeTestLoading()) return componentName;
loadJdomDefaults(component, componentName);
Element element = null;
StateStorage stateStorage = getOldStorage(component, componentName, StateStorageOperation.READ);
if (stateStorage == null) return;
if (stateStorage == null) return null;
element = getJdomState(component, componentName, stateStorage);
if (element == null) return;
if (element == null) return null;
try {
if (LOG.isDebugEnabled()) {
@@ -172,6 +176,8 @@ abstract class ComponentStoreImpl implements IComponentStore {
catch (InvalidDataException e) {
throw new InvalidComponentDataException(e);
}
return componentName;
}
private static String getComponentName(@NotNull final JDOMExternalizable component) {
@@ -216,7 +222,7 @@ abstract class ComponentStoreImpl implements IComponentStore {
return defaultsStorage.getState(component, componentName, Element.class, null);
}
private <T> void initPersistentComponent(@NotNull final PersistentStateComponent<T> component) {
private <T> String initPersistentComponent(@NotNull final PersistentStateComponent<T> component, final boolean reloadData) {
final String name = getComponentName(component);
RoamingType roamingTypeFromComponent = getRoamingType(component);
@@ -226,7 +232,7 @@ abstract class ComponentStoreImpl implements IComponentStore {
}
myComponents.put(name, component);
if (optimizeTestLoading()) return;
if (optimizeTestLoading()) return name;
Class<T> stateClass = getComponentStateClass(component);
@@ -242,13 +248,15 @@ abstract class ComponentStoreImpl implements IComponentStore {
for (Storage storageSpec : storageSpecs) {
StateStorage stateStorage = getStateStorage(storageSpec);
if (stateStorage == null || !stateStorage.hasState(component, name, stateClass)) continue;
if (stateStorage == null || !stateStorage.hasState(component, name, stateClass, reloadData)) continue;
state = stateStorage.getState(component, name, stateClass, state);
}
if (state != null) {
component.loadState(state);
}
return name;
}
private static RoamingType getRoamingType(final PersistentStateComponent component) {
@@ -455,7 +463,7 @@ abstract class ComponentStoreImpl implements IComponentStore {
}
protected boolean isReloadPossible(final Set<String> componentNames) {
public boolean isReloadPossible(final Set<String> componentNames) {
for (String componentName : componentNames) {
final Object component = myComponents.get(componentName);
@@ -470,11 +478,11 @@ abstract class ComponentStoreImpl implements IComponentStore {
return true;
}
protected void reinitComponents(final Set<String> componentNames) {
public void reinitComponents(final Set<String> componentNames, final boolean reloadData) {
for (String componentName : componentNames) {
final PersistentStateComponent component = (PersistentStateComponent)myComponents.get(componentName);
if (component != null) {
initPersistentComponent(component);
initPersistentComponent(component, reloadData);
}
}
}
@@ -94,6 +94,11 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
throw new UnsupportedOperationException("Method addMacro not implemented in " + getClass());
}
@Nullable
public TrackingPathMacroSubstitutor getMacroSubstitutor() {
return null;
}
@Nullable
public StateStorage getStateStorage(@NotNull Storage storageSpec) throws StateStorage.StateStorageException {
return storage;
@@ -54,7 +54,7 @@ class DefaultsStateStorage implements StateStorage {
return DefaultStateSerializer.deserializeState(getState(component, componentName), stateClass, mergeInto);
}
public boolean hasState(final Object component, final String componentName, final Class<?> aClass) throws StateStorageException {
public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException {
final URL url = DecodeDefaultsUtil.getDefaults(component, componentName);
return url != null;
}
@@ -1,5 +1,6 @@
package com.intellij.openapi.components.impl.stores;
import com.intellij.application.options.PathMacrosCollector;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.StateSplitter;
@@ -146,6 +147,9 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
if (myPathMacroSubstitutor != null) {
myPathMacroSubstitutor.expandPaths(element);
final Set<String> unknownMacros = PathMacrosCollector.getMacroNames(element);
myPathMacroSubstitutor.addUnknownMacros(componentName, unknownMacros);
}
storageData.put(componentName, file, element, true);
@@ -162,7 +166,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
}
public boolean hasState(final Object component, final String componentName, final Class<?> aClass) throws StateStorageException {
public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException {
if (!myDir.exists()) return false;
return true;
}
@@ -432,13 +436,10 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
}
private class MyExternalizationSession implements ExternalizationSession {
private final TrackingPathMacroSubstitutor myPathMacroSubstitutor;
private final MyStorageData myStorageData;
private MyExternalizationSession(final TrackingPathMacroSubstitutor pathMacroSubstitutor, final MyStorageData storageData) {
myStorageData = storageData;
myPathMacroSubstitutor = pathMacroSubstitutor;
myPathMacroSubstitutor.reset();
}
public void setState(final Object component, final String componentName, final Object state, final Storage storageSpec)
@@ -12,7 +12,12 @@ import java.util.List;
import java.util.Set;
public interface IComponentStore {
void initComponent(Object component);
@Nullable
String initComponent(Object component, boolean service);
void reinitComponents(Set<String> componentNames, boolean reloadData);
boolean isReloadPossible(Set<String> componentNames);
void load() throws IOException, StateStorage.StateStorageException;
boolean isSaving();
@@ -51,7 +51,7 @@ class ProjectStateStorageManager extends StateStorageManagerImpl {
StateStorage storage = getFileStateStorage(name);
if (operation == StateStorageOperation.READ && storage != null && workspace && !storage.hasState(component, componentName, Element.class)) {
if (operation == StateStorageOperation.READ && storage != null && workspace && !storage.hasState(component, componentName, Element.class, false)) {
name = "$" + ProjectStoreImpl.PROJECT_FILE_MACRO + "$";
}
@@ -3,9 +3,11 @@ package com.intellij.openapi.components.impl.stores;
import com.intellij.CommonBundle;
import com.intellij.ide.highlighter.ProjectFileType;
import com.intellij.ide.highlighter.WorkspaceFileType;
import com.intellij.notification.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.components.*;
import com.intellij.openapi.components.ex.ComponentManagerEx;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.project.Project;
@@ -19,6 +21,7 @@ import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VfsUtil;
@@ -32,12 +35,14 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.event.HyperlinkEvent;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -137,6 +142,33 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
return myProject.isOptimiseTestLoadSpeed();
}
@Override
public String initComponent(@NotNull Object component, boolean service) {
final String componentName = super.initComponent(component, service);
if (!ApplicationManager.getApplication().isHeadlessEnvironment() && !ApplicationManager.getApplication().isUnitTestMode()) {
if (service && componentName != null && myProject.isInitialized()) {
final TrackingPathMacroSubstitutor substitutor = getStateStorageManager().getMacroSubstitutor();
if (substitutor != null) {
final Collection<String> macros = substitutor.getUnknownMacros(componentName);
if (!macros.isEmpty()) {
Notifications.Bus.notify(new Notification("Load Error", "Error loading component",
String.format("<p>Undefined Path Variables: <i>%s</i>. <a href=\"\">Fix it!</a></p>",
StringUtil.join(macros, ", ")), NotificationType.ERROR,
new NotificationListener() {
public void hyperlinkUpdate(@NotNull Notification notification,
@NotNull HyperlinkEvent event) {
((ComponentManagerEx)myProject).checkUnknownMacros(myProject, notification);
}
}), NotificationDisplayType.STICKY_BALLOON, myProject);
}
}
}
}
return componentName;
}
public void setProjectFilePath(final String filePath) {
if (filePath == null) {
return;
@@ -595,7 +627,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
try {
doReload(changedFiles, componentNames);
reinitComponents(componentNames);
reinitComponents(componentNames, false);
}
finally {
myProject.getMessageBus().syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateFinished();
@@ -1,9 +1,6 @@
package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.components.RoamingType;
import com.intellij.openapi.components.StateStorage;
import com.intellij.openapi.components.StateStorageOperation;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.*;
import com.intellij.openapi.options.StreamProvider;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
@@ -20,6 +17,8 @@ import java.util.Set;
*/
public interface StateStorageManager {
void addMacro(String macro, String expansion);
@Nullable
TrackingPathMacroSubstitutor getMacroSubstitutor();
@Nullable
StateStorage getStateStorage(@NotNull Storage storageSpec) throws StateStorage.StateStorageException;
@@ -59,6 +59,11 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
}
}
@SuppressWarnings({"unchecked"})
public TrackingPathMacroSubstitutor getMacroSubstitutor() {
return myPathMacroSubstitutor;
}
public synchronized void addMacro(String macro, String expansion) {
myMacros.put("$" + macro + "$", expansion);
}
@@ -1,5 +1,6 @@
package com.intellij.openapi.components.impl.stores;
import com.intellij.application.options.PathMacrosCollector;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
@@ -102,7 +103,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
@Nullable
public synchronized Element getState(final String componentName) throws StateStorageException {
final StorageData storageData = getStorageData();
final StorageData storageData = getStorageData(false);
final Element state = storageData.getState(componentName);
@@ -117,8 +118,8 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
return state;
}
public boolean hasState(final Object component, final String componentName, final Class<?> aClass) throws StateStorageException {
final StorageData storageData = getStorageData();
public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException {
final StorageData storageData = getStorageData(reloadData);
return storageData.hasState(componentName);
}
@@ -129,8 +130,8 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
@NotNull
protected StorageData getStorageData() throws StateStorageException {
if (myLoadedData != null) return myLoadedData;
protected StorageData getStorageData(final boolean reloadData) throws StateStorageException {
if (myLoadedData != null && !reloadData) return myLoadedData;
myLoadedData = loadData(true, myListener);
@@ -178,7 +179,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
protected void loadState(final StorageData result, final Element element) throws StateStorageException {
// TODO: notification should be created here
if (myPathMacroSubstitutor != null) {
myPathMacroSubstitutor.expandPaths(element);
}
@@ -187,6 +187,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
try {
result.load(element);
result.checkUnknownMacros(myPathMacroSubstitutor);
}
catch (IOException e) {
throw new StateStorageException(e);
@@ -211,7 +212,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
@NotNull
public ExternalizationSession startExternalization() {
try {
final ExternalizationSession session = new MyExternalizationSession(getStorageData().clone(), myListener);
final ExternalizationSession session = new MyExternalizationSession(getStorageData(false).clone(), myListener);
mySession = session;
return session;
@@ -305,17 +306,13 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
protected Document getDocument(StorageData data) {
final Element element = data.save();
if (myPathMacroSubstitutor != null) {
Set<String> usedMacros = myPathMacroSubstitutor.getUsedMacros();
try {
myPathMacroSubstitutor.reset();
myPathMacroSubstitutor.collapsePaths(element);
}
finally {
myPathMacroSubstitutor.reset(usedMacros);
} finally {
myPathMacroSubstitutor.reset();
}
}
@@ -463,7 +460,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
myDocumentToSave = new Document(element);
if (myPathMacroSubstitutor != null) {
myPathMacroSubstitutor.reset();
myPathMacroSubstitutor.collapsePaths(element);
}
@@ -697,6 +693,15 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
public boolean hasState(final String componentName) {
return myComponentStates.containsKey(componentName);
}
public void checkUnknownMacros(TrackingPathMacroSubstitutor pathMacroSubstitutor) {
for (String componentName : myComponentStates.keySet()) {
final Set<String> unknownMacros = PathMacrosCollector.getMacroNames(myComponentStates.get(componentName));
if (!unknownMacros.isEmpty()) {
pathMacroSubstitutor.addUnknownMacros(componentName, unknownMacros);
}
}
}
}
public void resetData(){
@@ -25,11 +25,11 @@ public class ProjectMacrosUtil {
private ProjectMacrosUtil() {
}
public static boolean showMacrosConfigurationDialog(Project project, final Map<String, String> undefinedMacros) {
public static boolean showMacrosConfigurationDialog(Project project, final Collection<String> undefinedMacros) {
final String text = ProjectBundle.message("project.load.undefined.path.variables.message");
final Application application = ApplicationManager.getApplication();
if (application.isHeadlessEnvironment() || application.isUnitTestMode()) {
throw new RuntimeException(text + ": " + StringUtil.join(undefinedMacros.keySet(), ", "));
throw new RuntimeException(text + ": " + StringUtil.join(undefinedMacros, ", "));
}
final UndefinedMacrosConfigurable configurable =
new UndefinedMacrosConfigurable(text, undefinedMacros);
@@ -47,13 +47,13 @@ public class ProjectMacrosUtil {
return editor.isOK();
}
public static boolean checkMacros(final Project project, final Map<String, String> usedMacros) {
public static boolean checkMacros(final Project project, final Set<String> usedMacros) {
final Set<String> defined = getDefinedMacros();
usedMacros.keySet().removeAll(defined);
usedMacros.removeAll(defined);
// try to lookup values in System properties
@NonNls final String pathMacroSystemPrefix = "path.macro.";
for (Iterator it = usedMacros.keySet().iterator(); it.hasNext();) {
for (Iterator it = usedMacros.iterator(); it.hasNext();) {
final String macro = (String)it.next();
final String value = System.getProperty(pathMacroSystemPrefix + macro, null);
if (value != null) {
@@ -4,6 +4,7 @@ import com.intellij.ide.AppLifecycleListener;
import com.intellij.ide.highlighter.WorkspaceFileType;
import com.intellij.ide.impl.ProjectUtil;
import com.intellij.ide.startup.impl.StartupManagerImpl;
import com.intellij.notification.*;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
@@ -13,6 +14,8 @@ import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.application.impl.ApplicationImpl;
import com.intellij.openapi.components.ExportableApplicationComponent;
import com.intellij.openapi.components.StateStorage;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.components.ex.ComponentManagerEx;
import com.intellij.openapi.components.impl.stores.IComponentStore;
import com.intellij.openapi.components.impl.stores.IProjectStore;
import com.intellij.openapi.components.impl.stores.XmlElementStorage;
@@ -31,6 +34,7 @@ import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileEvent;
@@ -51,6 +55,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import javax.swing.event.HyperlinkEvent;
import java.io.File;
import java.io.IOException;
import java.util.*;
@@ -376,6 +381,30 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
startupManager.runPostStartupActivities();
if (!ApplicationManager.getApplication().isHeadlessEnvironment() && !ApplicationManager.getApplication().isUnitTestMode()) {
// should be invoked last
StartupManager.getInstance(project).runWhenProjectIsInitialized(new Runnable() {
public void run() {
final TrackingPathMacroSubstitutor macroSubstitutor =
((ProjectEx)project).getStateStore().getStateStorageManager().getMacroSubstitutor();
if (macroSubstitutor != null) {
final Collection<String> macros = macroSubstitutor.getUnknownMacros(null);
if (!macros.isEmpty()) {
Notifications.Bus.notify(new Notification("Load Error", "Error loading project",
String.format("<p>Undefined Path Variables: %s. <a href=\"\">Fix it!</a></p>",
StringUtil.join(macros, ", ")), NotificationType.ERROR,
new NotificationListener() {
public void hyperlinkUpdate(@NotNull Notification notification,
@NotNull HyperlinkEvent event) {
((ComponentManagerEx)project).checkUnknownMacros(project, notification);
}
}), NotificationDisplayType.STICKY_BALLOON, project);
}
}
}
});
}
return true;
}
@@ -14,7 +14,7 @@ import com.intellij.ui.IdeBorderFactory;
import javax.swing.*;
import java.awt.*;
import java.util.Map;
import java.util.Collection;
/**
* @author Eugene Zhuravlev
@@ -23,9 +23,9 @@ import java.util.Map;
public class UndefinedMacrosConfigurable implements Configurable{
private PathMacroListEditor myEditor;
private final String myText;
private final Map<String, String> myUndefinedMacroNames;
private final Collection<String> myUndefinedMacroNames;
public UndefinedMacrosConfigurable(String text, Map<String, String> undefinedMacroNames) {
public UndefinedMacrosConfigurable(String text, Collection<String> undefinedMacroNames) {
myText = text;
myUndefinedMacroNames = undefinedMacroNames;
}
@@ -1,6 +1,7 @@
package com.intellij.mock;
import com.intellij.application.options.ReplacePathToMacroMap;
import com.intellij.notification.Notification;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ExpandMacroToPathMap;
import com.intellij.openapi.components.ServiceManager;
@@ -23,6 +24,9 @@ public class MockProject extends MockComponentManager implements ProjectEx {
return false;
}
public void checkMacros(Notification notification, @Nullable String componentName) {
}
@NotNull
public PomModel getModel() {
return ServiceManager.getService(this, PomModel.class);
@@ -33,6 +33,14 @@ public class MockProjectStore implements IProjectStore {
throw new UnsupportedOperationException("Method setProjectFilePath is not yet implemented in " + getClass().getName());
}
public void reinitComponents(Set<String> componentNames, boolean reloadData) {
throw new UnsupportedOperationException("Method reinitComponents is not yet implemented in " + getClass().getName());
}
public boolean isReloadPossible(Set<String> componentNames) {
throw new UnsupportedOperationException("Method isReloadPossible is not yet implemented in " + getClass().getName());
}
@Nullable
public VirtualFile getProjectBaseDir() {
throw new UnsupportedOperationException("Method getProjectBaseDir is not yet implemented in " + getClass().getName());
@@ -95,7 +103,7 @@ public class MockProjectStore implements IProjectStore {
throw new UnsupportedOperationException("Method initStore is not yet implemented in " + getClass().getName());
}
public void initComponent(Object component) {
public String initComponent(Object component, final boolean service) {
throw new UnsupportedOperationException("Method initComponent is not yet implemented in " + getClass().getName());
}
@@ -155,12 +155,7 @@ public class EclipseImportBuilder extends ProjectImportBuilder<String> implement
return false;
}
final HashMap<String, String> map = new HashMap<String, String>();
for (String v : variables) {
map.put(v, null);
}
if (!ProjectMacrosUtil.checkMacros(dstProject, map)) {
if (!ProjectMacrosUtil.checkMacros(dstProject, variables)) {
return false;
}
@@ -292,7 +292,7 @@ public class ExternalResourceManagerImpl extends ExternalResourceManagerEx imple
public void readExternal(Element element) throws InvalidDataException {
final ExpandMacroToPathMap macroExpands = new ExpandMacroToPathMap();
myPathMacros.addMacroExpands(macroExpands);
macroExpands.substitute(element, SystemInfo.isFileSystemCaseSensitive, null);
macroExpands.substitute(element, SystemInfo.isFileSystemCaseSensitive);
myModificationCount++;
for (final Object o1 : element.getChildren(RESOURCE_ELEMENT)) {
@@ -329,7 +329,7 @@ public class ExternalResourceManagerImpl extends ExternalResourceManagerEx imple
final ReplacePathToMacroMap macroReplacements = new ReplacePathToMacroMap();
PathMacrosImpl.getInstanceEx().addMacroReplacements(macroReplacements);
macroReplacements.substitute(element, SystemInfo.isFileSystemCaseSensitive, null);
macroReplacements.substitute(element, SystemInfo.isFileSystemCaseSensitive);
}
public void addExternalResourceListener(ExternalResourceListener listener) {