@NotNull public static TreeMap<String, Element> load( @NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) { if (pathMacroSubstitutor != null) { pathMacroSubstitutor.expandPaths(rootElement); } StringInterner interner = intern ? new StringInterner() : null; List<Element> children = rootElement.getChildren(COMPONENT); TreeMap<String, Element> map = new TreeMap<String, Element>(); for (Element element : children) { String name = getComponentNameIfValid(element); if (name == null || !(element.getAttributes().size() > 1 || !element.getChildren().isEmpty())) { continue; } if (interner != null) { JDOMUtil.internElement(element, interner); } map.put(name, element); if (pathMacroSubstitutor instanceof TrackingPathMacroSubstitutor) { ((TrackingPathMacroSubstitutor) pathMacroSubstitutor) .addUnknownMacros(name, PathMacrosCollector.getMacroNames(element)); } // remove only after "getMacroNames" - some PathMacroFilter requires element name attribute element.removeAttribute(NAME); } return map; }
@Nullable @Override public Element getSerializedState( @NotNull Boolean storageData, Object component, @NotNull String componentName, boolean archive) { if (storageData) { return null; } Element element = new Element("component"); ModifiableRootModel model = null; AccessToken token = ReadAction.start(); try { model = ((ModuleRootManagerImpl) component).getModifiableModel(); // IDEA-137969 Eclipse integration: external remove of classpathentry is not synchronized model.clear(); try { myConverter.readClasspath(model); } catch (IOException e) { throw new RuntimeException(e); } ((RootModelImpl) model).writeExternal(element); } catch (WriteExternalException e) { LOG.error(e); } finally { try { token.finish(); } finally { if (model != null) { model.dispose(); } } } if (myPathMacroSubstitutor != null) { myPathMacroSubstitutor.expandPaths(element); myPathMacroSubstitutor.addUnknownMacros( "NewModuleRootManager", PathMacrosCollector.getMacroNames(element)); } getStorageDataRef().set(true); return element; }
public static void notifyUnknownMacros( @NotNull TrackingPathMacroSubstitutor substitutor, @NotNull final Project project, @Nullable final String componentName) { final LinkedHashSet<String> macros = new LinkedHashSet<String>(substitutor.getUnknownMacros(componentName)); if (macros.isEmpty()) { return; } UIUtil.invokeLaterIfNeeded( new Runnable() { @Override public void run() { macros.removeAll(getMacrosFromExistingNotifications(project)); if (!macros.isEmpty()) { LOG.debug( "Reporting unknown path macros " + macros + " in component " + componentName); String format = "<p><i>%s</i> %s undefined. <a href=\"define\">Fix it</a></p>"; String productName = ApplicationNamesInfo.getInstance().getProductName(); String content = String.format( format, StringUtil.join(macros, ", "), macros.size() == 1 ? "is" : "are") + "<br>Path variables are used to substitute absolute paths " + "in " + productName + " project files " + "and allow project file sharing in version control systems.<br>" + "Some of the files describing the current project settings contain unknown path variables " + "and " + productName + " cannot restore those paths."; new UnknownMacroNotification( "Load Error", "Load error: undefined path variables", content, NotificationType.ERROR, new NotificationListener() { @Override public void hyperlinkUpdate( @NotNull Notification notification, @NotNull HyperlinkEvent event) { ((ProjectEx) project).checkUnknownMacros(true); } }, macros) .notify(project); } } }); }