blob: bdbe32db040b2b6a32375a2e9f68b2b68d3ba23b [file] [log] [blame]
/*
* Copyright 2000-2014 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.ui;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonShortcuts;
import com.intellij.openapi.actionSystem.CustomShortcutSet;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.InputValidator;
import com.intellij.openapi.ui.MasterDetailsComponent;
import com.intellij.openapi.ui.MasterDetailsStateService;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.IconUtil;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.HashMap;
import com.maddyhome.idea.copyright.CopyrightManager;
import com.maddyhome.idea.copyright.CopyrightProfile;
import com.maddyhome.idea.copyright.options.ExternalOptionHelper;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.tree.TreePath;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
public class CopyrightProfilesPanel extends MasterDetailsComponent implements SearchableConfigurable {
private final Project myProject;
private final CopyrightManager myManager;
private final AtomicBoolean myInitialized = new AtomicBoolean(false);
private Runnable myUpdate;
public CopyrightProfilesPanel(Project project) {
myProject = project;
myManager = CopyrightManager.getInstance(project);
initTree();
}
public void setUpdate(Runnable update) {
myUpdate = update;
}
@Override
protected MasterDetailsStateService getStateService() {
return MasterDetailsStateService.getInstance(myProject);
}
@Override
protected String getComponentStateKey() {
return "Copyright.UI";
}
@Override
protected void processRemovedItems() {
Map<String, CopyrightProfile> profiles = getAllProfiles();
final List<CopyrightProfile> deleted = new ArrayList<CopyrightProfile>();
for (CopyrightProfile profile : myManager.getCopyrights()) {
if (!profiles.containsValue(profile)) {
deleted.add(profile);
}
}
for (CopyrightProfile profile : deleted) {
myManager.removeCopyright(profile);
}
}
@Override
protected boolean wasObjectStored(Object o) {
return myManager.getCopyrights().contains((CopyrightProfile)o);
}
@Override
@Nls
public String getDisplayName() {
return "Copyright Profiles";
}
@Override
@NotNull
@NonNls
public String getHelpTopic() {
return "copyright.profiles";
}
protected void reloadAvailableProfiles() {
if (myUpdate != null) {
myUpdate.run();
}
}
@Override
public void apply() throws ConfigurationException {
final Set<String> profiles = new HashSet<String>();
for (int i = 0; i < myRoot.getChildCount(); i++) {
MyNode node = (MyNode)myRoot.getChildAt(i);
final String profileName = ((CopyrightConfigurable)node.getConfigurable()).getEditableObject().getName();
if (profiles.contains(profileName)) {
selectNodeInTree(profileName);
throw new ConfigurationException("Duplicate copyright profile name: \'" + profileName + "\'");
}
profiles.add(profileName);
}
super.apply();
}
public Map<String, CopyrightProfile> getAllProfiles() {
final Map<String, CopyrightProfile> profiles = new HashMap<String, CopyrightProfile>();
if (!myInitialized.get()) {
for (CopyrightProfile profile : myManager.getCopyrights()) {
profiles.put(profile.getName(), profile);
}
}
else {
for (int i = 0; i < myRoot.getChildCount(); i++) {
MyNode node = (MyNode)myRoot.getChildAt(i);
final CopyrightProfile copyrightProfile = ((CopyrightConfigurable)node.getConfigurable()).getEditableObject();
profiles.put(copyrightProfile.getName(), copyrightProfile);
}
}
return profiles;
}
@Override
public void disposeUIResources() {
super.disposeUIResources();
myInitialized.set(false);
}
@Override
@Nullable
protected ArrayList<AnAction> createActions(boolean fromPopup) {
ArrayList<AnAction> result = new ArrayList<AnAction>();
result.add(new AnAction("Add", "Add", IconUtil.getAddIcon()) {
{
registerCustomShortcutSet(CommonShortcuts.INSERT, myTree);
}
@Override
public void actionPerformed(AnActionEvent event) {
final String name = askForProfileName("Create Copyright Profile", "");
if (name == null) return;
final CopyrightProfile copyrightProfile = new CopyrightProfile(name);
addProfileNode(copyrightProfile);
}
});
result.add(new MyDeleteAction());
result.add(new AnAction("Copy", "Copy", PlatformIcons.COPY_ICON) {
{
registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_MASK)), myTree);
}
@Override
public void actionPerformed(AnActionEvent event) {
final String profileName = askForProfileName("Copy Copyright Profile", "");
if (profileName == null) return;
final CopyrightProfile clone = new CopyrightProfile();
clone.copyFrom((CopyrightProfile)getSelectedObject());
clone.setName(profileName);
addProfileNode(clone);
}
@Override
public void update(AnActionEvent event) {
super.update(event);
event.getPresentation().setEnabled(getSelectedObject() != null);
}
});
result.add(new AnAction("Import", "Import", PlatformIcons.IMPORT_ICON) {
@Override
public void actionPerformed(AnActionEvent event) {
FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor()
.withFileFilter(new Condition<VirtualFile>() {
@Override
public boolean value(VirtualFile file) {
return file.getFileType() == StdFileTypes.IDEA_MODULE || file.getFileType() == StdFileTypes.XML;
}
})
.withTitle("Choose file containing copyright notice");
FileChooser.chooseFile(descriptor, myProject, null, new Consumer<VirtualFile>() {
@Override
public void consume(VirtualFile file) {
final List<CopyrightProfile> profiles = ExternalOptionHelper.loadOptions(VfsUtilCore.virtualToIoFile(file));
if (profiles == null) return;
if (!profiles.isEmpty()) {
if (profiles.size() == 1) {
importProfile(profiles.get(0));
}
else {
JBPopupFactory.getInstance()
.createListPopup(new BaseListPopupStep<CopyrightProfile>("Choose profile to import", profiles) {
@Override
public PopupStep onChosen(final CopyrightProfile selectedValue, boolean finalChoice) {
return doFinalStep(new Runnable() {
@Override
public void run() {
importProfile(selectedValue);
}
});
}
@NotNull
@Override
public String getTextFor(CopyrightProfile value) {
return value.getName();
}
})
.showUnderneathOf(myNorthPanel);
}
}
else {
Messages.showWarningDialog(myProject, "The selected file does not contain any copyright settings.", "Import Failure");
}
}
});
}
private void importProfile(CopyrightProfile copyrightProfile) {
final String profileName = askForProfileName("Import copyright profile", copyrightProfile.getName());
if (profileName == null) return;
copyrightProfile.setName(profileName);
addProfileNode(copyrightProfile);
Messages.showInfoMessage(myProject, "The copyright settings have been successfully imported.", "Import Complete");
}
});
return result;
}
@Nullable
private String askForProfileName(String title, String initialName) {
return Messages.showInputDialog("New copyright profile name:", title, Messages.getQuestionIcon(), initialName, new InputValidator() {
@Override
public boolean checkInput(String s) {
return !getAllProfiles().containsKey(s) && s.length() > 0;
}
@Override
public boolean canClose(String s) {
return checkInput(s);
}
});
}
private void addProfileNode(CopyrightProfile copyrightProfile) {
final CopyrightConfigurable copyrightConfigurable = new CopyrightConfigurable(myProject, copyrightProfile, TREE_UPDATER);
copyrightConfigurable.setModified(true);
final MyNode node = new MyNode(copyrightConfigurable);
addNode(node, myRoot);
selectNodeInTree(node);
reloadAvailableProfiles();
}
@Override
protected void removePaths(TreePath... paths) {
super.removePaths(paths);
reloadAvailableProfiles();
}
private void reloadTree() {
myRoot.removeAllChildren();
Collection<CopyrightProfile> collection = myManager.getCopyrights();
for (CopyrightProfile profile : collection) {
CopyrightProfile clone = new CopyrightProfile();
clone.copyFrom(profile);
addNode(new MyNode(new CopyrightConfigurable(myProject, clone, TREE_UPDATER)), myRoot);
}
myInitialized.set(true);
}
@Override
public void reset() {
reloadTree();
super.reset();
}
@Override
protected String getEmptySelectionString() {
return "Select a profile to view or edit its details here";
}
public void addItemsChangeListener(final Runnable runnable) {
addItemsChangeListener(new ItemsChangeListener() {
@Override
public void itemChanged(@Nullable Object deletedItem) {
SwingUtilities.invokeLater(runnable);
}
@Override
public void itemsExternallyChanged() {
SwingUtilities.invokeLater(runnable);
}
});
}
@Override
@NotNull
public String getId() {
return getHelpTopic();
}
@Override
public Runnable enableSearch(String option) {
return null;
}
}