/*
* 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.maddyhome.idea.copyright;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.*;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.packageDependencies.DependencyValidationManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.scope.packageSet.NamedScope;
import com.intellij.psi.search.scope.packageSet.PackageSet;
import com.intellij.util.containers.HashMap;
import com.maddyhome.idea.copyright.actions.UpdateCopyrightProcessor;
import com.maddyhome.idea.copyright.util.NewFileTracker;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import consulo.copyright.config.CopyrightFileConfig;
import consulo.copyright.config.CopyrightFileConfigManager;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
@State(name = "CopyrightManager",
storages = {
@Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/copyright/",
stateSplitter = CopyrightManager.CopyrightStateSplitter.class)
})
public class CopyrightManager extends AbstractProjectComponent implements PersistentStateComponent<Element> {
private static final Logger LOG = Logger.getInstance("#" + CopyrightManager.class.getName());
@NonNls
private static final String COPYRIGHT = "copyright";
@NonNls
private static final String MODULE2COPYRIGHT = "module2copyright";
@NonNls
private static final String ELEMENT = "element";
@NonNls
private static final String MODULE = "module";
@NonNls
private static final String DEFAULT = "default";
private final LinkedHashMap<String, String> myModule2Copyrights = new LinkedHashMap<String, String>();
private final Map<String, CopyrightProfile> myCopyrights = new HashMap<String, CopyrightProfile>();
private final CopyrightFileConfigManager myCopyrightFileConfigManager = new CopyrightFileConfigManager();
@Nullable
private CopyrightProfile myDefaultCopyright = null;
public CopyrightManager(@NotNull Project project,
@NotNull final EditorFactory editorFactory,
@NotNull final Application application,
@NotNull final FileDocumentManager fileDocumentManager,
@NotNull final ProjectRootManager projectRootManager,
@NotNull final PsiManager psiManager,
@NotNull StartupManager startupManager) {
super(project);
if (!myProject.isDefault()) {
final NewFileTracker newFileTracker = NewFileTracker.getInstance();
Disposer.register(myProject, new Disposable() {
@Override
public void dispose() {
newFileTracker.clear();
}
});
startupManager.runWhenProjectIsInitialized(new Runnable() {
@Override
public void run() {
DocumentListener listener = new DocumentAdapter() {
@Override
public void documentChanged(DocumentEvent e) {
final Document document = e.getDocument();
final VirtualFile virtualFile = fileDocumentManager.getFile(document);
if (virtualFile == null) return;
if (!newFileTracker.poll(virtualFile)) return;
if (!CopyrightUpdaters.hasExtension(virtualFile)) return;
final Module module = projectRootManager.getFileIndex().getModuleForFile(virtualFile);
if (module == null) return;
final PsiFile file = psiManager.findFile(virtualFile);
if (file == null) return;
application.invokeLater(new Runnable() {
@Override
public void run() {
if (myProject.isDisposed()) return;
if (file.isValid() && file.isWritable()) {
final CopyrightProfile opts = getCopyrightOptions(file);
if (opts != null) {
new UpdateCopyrightProcessor(myProject, module, file).run();
}
}
}
}, ModalityState.NON_MODAL, myProject.getDisposed());
}
};
editorFactory.getEventMulticaster().addDocumentListener(listener, myProject);
}
});
}
}
public static CopyrightManager getInstance(Project project) {
return project.getComponent(CopyrightManager.class);
}
@Override
@NonNls
@NotNull
public String getComponentName() {
return "CopyrightManager";
}
private void readExternal(Element element) throws InvalidDataException {
clearCopyrights();
final Element module2copyright = element.getChild(MODULE2COPYRIGHT);
if (module2copyright != null) {
for (Element o : module2copyright.getChildren(ELEMENT)) {
final String moduleName = o.getAttributeValue(MODULE);
final String copyrightName = o.getAttributeValue(COPYRIGHT);
myModule2Copyrights.put(moduleName, copyrightName);
}
}
for (Element o : element.getChildren(COPYRIGHT)) {
final CopyrightProfile copyrightProfile = new CopyrightProfile();
copyrightProfile.readExternal(o);
myCopyrights.put(copyrightProfile.getName(), copyrightProfile);
}
myDefaultCopyright = myCopyrights.get(element.getAttributeValue(DEFAULT));
myCopyrightFileConfigManager.readExternal(element);
}
private void writeExternal(Element element) throws WriteExternalException {
for (CopyrightProfile copyright : myCopyrights.values()) {
final Element copyrightElement = new Element(COPYRIGHT);
copyright.writeExternal(copyrightElement);
element.addContent(copyrightElement);
}
final Element map = new Element(MODULE2COPYRIGHT);
for (String moduleName : myModule2Copyrights.keySet()) {
final Element setting = new Element(ELEMENT);
setting.setAttribute(MODULE, moduleName);
setting.setAttribute(COPYRIGHT, myModule2Copyrights.get(moduleName));
map.addContent(setting);
}
element.addContent(map);
element.setAttribute(DEFAULT, myDefaultCopyright != null ? myDefaultCopyright.getName() : "");
myCopyrightFileConfigManager.writeExternal(element);
}
@Override
public Element getState() {
try {
final Element e = new Element("settings");
writeExternal(e);
return e;
}
catch (WriteExternalException e1) {
LOG.error(e1);
return null;
}
}
@Override
public void loadState(Element state) {
try {
readExternal(state);
}
catch (InvalidDataException e) {
LOG.error(e);
}
}
public Map<String, String> getCopyrightsMapping() {
return myModule2Copyrights;
}
@Nullable
public CopyrightProfile getDefaultCopyright() {
return myDefaultCopyright;
}
public void setDefaultCopyright(@Nullable CopyrightProfile copyright) {
myDefaultCopyright = copyright;
}
public void addCopyright(CopyrightProfile copyrightProfile) {
myCopyrights.put(copyrightProfile.getName(), copyrightProfile);
}
public void removeCopyright(CopyrightProfile copyrightProfile) {
myCopyrights.values().remove(copyrightProfile);
for (Iterator<String> it = myModule2Copyrights.keySet().iterator(); it.hasNext(); ) {
final String profileName = myModule2Copyrights.get(it.next());
if (profileName.equals(copyrightProfile.getName())) {
it.remove();
}
}
}
public void clearCopyrights() {
myDefaultCopyright = null;
myCopyrights.clear();
myModule2Copyrights.clear();
}
public void mapCopyright(String scopeName, String copyrightProfileName) {
myModule2Copyrights.put(scopeName, copyrightProfileName);
}
public void unmapCopyright(String scopeName) {
myModule2Copyrights.remove(scopeName);
}
public Collection<CopyrightProfile> getCopyrights() {
return myCopyrights.values();
}
public boolean hasAnyCopyrights() {
return myDefaultCopyright != null || !myModule2Copyrights.isEmpty();
}
@Nullable
public CopyrightProfile getCopyrightOptions(@NotNull PsiFile file) {
final VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null || myCopyrightFileConfigManager.getOptions(virtualFile.getFileType()).getFileTypeOverride() == CopyrightFileConfig.NO_COPYRIGHT) {
return null;
}
final DependencyValidationManager validationManager = DependencyValidationManager.getInstance(myProject);
for (String scopeName : myModule2Copyrights.keySet()) {
final NamedScope namedScope = validationManager.getScope(scopeName);
if (namedScope != null) {
final PackageSet packageSet = namedScope.getValue();
if (packageSet != null) {
if (packageSet.contains(file, validationManager)) {
final CopyrightProfile profile = myCopyrights.get(myModule2Copyrights.get(scopeName));
if (profile != null) {
return profile;
}
}
}
}
}
return myDefaultCopyright != null ? myDefaultCopyright : null;
}
public CopyrightFileConfigManager getCopyrightFileConfigManager() {
return myCopyrightFileConfigManager;
}
public void replaceCopyright(String displayName, CopyrightProfile copyrightProfile) {
if (myDefaultCopyright != null && Comparing.strEqual(myDefaultCopyright.getName(), displayName)) {
myDefaultCopyright = copyrightProfile;
}
myCopyrights.remove(displayName);
addCopyright(copyrightProfile);
}
static final class CopyrightStateSplitter extends MainConfigurationStateSplitter {
@NotNull
@Override
protected String getSubStateFileName(@NotNull Element element) {
for (Element option : element.getChildren("option")) {
if (option.getAttributeValue("name").equals("myName")) {
return option.getAttributeValue("value");
}
}
throw new IllegalStateException();
}
@NotNull
@Override
protected String getComponentStateFileName() {
return "profiles_settings";
}
@NotNull
@Override
protected String getSubStateTagName() {
return "copyright";
}
}
}