blob: f003c48de2e971b6a96723d790881a155168c822 [file] [log] [blame]
/*
* Copyright (C) 2013 The Android Open Source Project
*
* 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.android.tools.idea.actions;
import com.android.tools.idea.gradle.parser.BuildFileKey;
import com.android.tools.idea.gradle.parser.Dependency;
import com.android.tools.idea.gradle.parser.GradleBuildFile;
import com.android.tools.idea.gradle.parser.GradleSettingsFile;
import com.android.tools.idea.gradle.project.GradleProjectImporter;
import com.android.tools.idea.gradle.util.Projects;
import com.intellij.ide.projectView.actions.MarkLibraryRootAction;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.libraries.ui.OrderRoot;
import com.intellij.openapi.roots.libraries.ui.impl.RootDetectionUtil;
import com.intellij.application.options.ModulesComboBox;
import com.intellij.openapi.roots.ui.configuration.libraryEditor.DefaultLibraryRootsComponentDescriptor;
import com.intellij.openapi.roots.ui.configuration.libraryEditor.LibraryNameAndLevelPanel;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.SortedListModel;
import com.intellij.util.ui.FormBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* Replaces the {@linkplain MarkLibraryRootAction} for Android-Gradle projects. This action, given an input of a number of
* {@linkplain VirtualFile} instances, examines them to see if they are jarfiles and could be added to a library as a dependency.
* If so, the action displays a dialog allowing the user to choose a module to add the jars to, and updates the module's build.gradle.
* <p>
* For non-Android-Gradle projects, this action delegates to MarkLibraryRootAction.
*/
public class CreateLibraryFromFilesAction extends AnAction {
AnAction myDelegate = new MarkLibraryRootAction();
public CreateLibraryFromFilesAction() {
super("Add As Library...");
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
final Project project = getEventProject(e);
if (project == null) return;
if (!Projects.requiresAndroidModel(project)) {
myDelegate.actionPerformed(e);
return;
}
final List<VirtualFile> jars = getRoots(e);
if (jars.isEmpty()) {
return;
}
final List<OrderRoot> roots = RootDetectionUtil.detectRoots(jars, null, project, new DefaultLibraryRootsComponentDescriptor());
new CreateGradleLibraryFromFilesDialog(project, roots).show();
}
@Override
public void update(@NotNull AnActionEvent e) {
final Project project = getEventProject(e);
boolean visible = false;
if (project != null && ModuleManager.getInstance(project).getModules().length > 0) {
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
for (VirtualFile root : getRoots(e)) {
if (!root.isInLocalFileSystem() && FileUtilRt.extensionEquals(root.getName(), "jar") && !fileIndex.isInLibraryClasses(root)) {
visible = true;
break;
}
}
}
Presentation presentation = e.getPresentation();
presentation.setVisible(visible);
presentation.setEnabled(visible);
}
@NotNull
private static List<VirtualFile> getRoots(@NotNull AnActionEvent e) {
final Project project = getEventProject(e);
final VirtualFile[] files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY);
if (project == null || files == null || files.length == 0) {
return Collections.emptyList();
}
List<VirtualFile> roots = new ArrayList<VirtualFile>();
for (VirtualFile file : files) {
VirtualFile root = JarFileSystem.getInstance().getJarRootForLocalFile(file);
if (root != null) {
roots.add(root);
}
}
return roots;
}
private static class CreateGradleLibraryFromFilesDialog extends DialogWrapper {
public static final String COMMAND_TITLE = "Create Library";
private final ModulesComboBox myModulesComboBox;
private final Project myProject;
private final JPanel myPanel;
private final List<OrderRoot> myRoots;
private GradleSettingsFile mySettingsFile;
public CreateGradleLibraryFromFilesDialog(@NotNull Project project, @NotNull List<OrderRoot> roots) {
super(project, true);
setTitle(COMMAND_TITLE);
myProject = project;
myRoots = roots;
mySettingsFile = GradleSettingsFile.get(myProject);
final FormBuilder builder = LibraryNameAndLevelPanel.createFormBuilder();
myModulesComboBox = new ModulesComboBox();
myModulesComboBox.fillModules(myProject);
myModulesComboBox.setSelectedModule(findModule(roots));
for (Iterator iter = ((SortedListModel)myModulesComboBox.getModel()).iterator(); iter.hasNext(); ) {
Module module = (Module)iter.next();
String path = GradleSettingsFile.getModuleGradlePath(module);
if (path == null || !mySettingsFile.hasBuildFile(path)) {
iter.remove();
}
}
builder.addLabeledComponent("&Add to module:", myModulesComboBox);
myPanel = builder.getPanel();
init();
}
@Nullable
private Module findModule(List<OrderRoot> roots) {
for (OrderRoot root : roots) {
Module module = null;
final VirtualFile local = JarFileSystem.getInstance().getVirtualFileForJar(root.getFile());
if (local != null) {
module = ModuleUtilCore.findModuleForFile(local, myProject);
}
if (module == null) {
module = ModuleUtilCore.findModuleForFile(root.getFile(), myProject);
}
if (module != null) {
return module;
}
}
return null;
}
@Override
protected void doOKAction() {
AccessToken token = WriteAction.start();
try {
final Module module = myModulesComboBox.getSelectedModule();
if (module == null) { return; }
String moduleGradlePath = GradleSettingsFile.getModuleGradlePath(module);
if (moduleGradlePath == null) { return; }
final GradleBuildFile buildFile = mySettingsFile.getModuleBuildFile(moduleGradlePath);
List<Dependency> value = (List<Dependency>)buildFile.getValue(BuildFileKey.DEPENDENCIES);
final List<Dependency> dependencies = value != null ? value : new ArrayList<Dependency>();
boolean added = false;
for (OrderRoot root : myRoots) {
VirtualFile parent = buildFile.getFile().getParent();
final VirtualFile local = JarFileSystem.getInstance().getVirtualFileForJar(root.getFile());
if (local != null) {
String path = VfsUtilCore.getRelativePath(local, parent, '/');
if (path == null) {
path = local.getPath();
}
Dependency newDependency = new Dependency(Dependency.Scope.COMPILE, Dependency.Type.FILES, path);
if (!dependencies.contains(newDependency)) {
dependencies.add((newDependency));
added = true;
}
}
if (added) {
new WriteCommandAction<Void>(myProject, COMMAND_TITLE, buildFile.getPsiFile()) {
@Override
protected void run(@NotNull Result<Void> result) throws Throwable {
buildFile.setValue(BuildFileKey.DEPENDENCIES, dependencies);
}
}.execute();
}
}
}
finally {
token.finish();
}
GradleProjectImporter.getInstance().requestProjectSync(myProject, null);
super.doOKAction();
}
@Override
protected JComponent createCenterPanel() {
return myPanel;
}
}
}