| /* |
| * Copyright 2017 The Bazel Authors. All rights reserved. |
| * |
| * 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.google.idea.blaze.base.settings.ui; |
| |
| import static com.google.common.base.Preconditions.checkState; |
| import static java.util.stream.Collectors.toCollection; |
| |
| import com.google.common.collect.ImmutableSet; |
| import com.google.idea.blaze.base.actions.BlazeProjectAction; |
| import com.google.idea.blaze.base.model.BlazeProjectData; |
| import com.google.idea.blaze.base.model.primitives.TargetExpression; |
| import com.google.idea.blaze.base.model.primitives.WorkspacePath; |
| import com.google.idea.blaze.base.model.primitives.WorkspaceRoot; |
| import com.google.idea.blaze.base.projectview.ProjectViewEdit; |
| import com.google.idea.blaze.base.projectview.ProjectViewManager; |
| import com.google.idea.blaze.base.projectview.ProjectViewSet; |
| import com.google.idea.blaze.base.projectview.section.ListSection; |
| import com.google.idea.blaze.base.projectview.section.ListSection.Builder; |
| import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry; |
| import com.google.idea.blaze.base.projectview.section.sections.DirectorySection; |
| import com.google.idea.blaze.base.projectview.section.sections.TargetSection; |
| import com.google.idea.blaze.base.settings.BlazeImportSettings; |
| import com.google.idea.blaze.base.settings.BlazeImportSettingsManager; |
| import com.google.idea.blaze.base.settings.BlazeUserSettings; |
| import com.google.idea.blaze.base.sync.BlazeSyncManager; |
| import com.google.idea.blaze.base.sync.BlazeSyncParams; |
| import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager; |
| import com.google.idea.blaze.base.sync.projectview.ImportRoots; |
| import com.google.idea.blaze.base.sync.projectview.RelatedWorkspacePathFinder; |
| import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver; |
| import com.google.idea.blaze.base.ui.WorkspaceFileTextField; |
| import com.intellij.icons.AllIcons; |
| import com.intellij.openapi.actionSystem.AnActionEvent; |
| import com.intellij.openapi.fileChooser.FileChooserDescriptor; |
| import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; |
| import com.intellij.openapi.fileChooser.FileTextField; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.ui.DialogWrapper; |
| import com.intellij.openapi.ui.Messages; |
| import com.intellij.openapi.ui.ValidationInfo; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.ui.components.JBLabel; |
| import com.intellij.util.ui.SwingHelper; |
| import java.awt.Component; |
| import java.awt.Dimension; |
| import java.io.File; |
| import java.util.LinkedHashSet; |
| import java.util.Set; |
| import javax.annotation.Nullable; |
| import javax.swing.Box; |
| import javax.swing.JComponent; |
| import javax.swing.JPanel; |
| import javax.swing.SwingConstants; |
| |
| final class AddDirectoryToProjectAction extends BlazeProjectAction { |
| |
| private static final String WARNING_TEXT = |
| "This will add all blaze targets below this directory to your project. This could have a " |
| + "large impact on your project build times if the directory contains a lot of code or " |
| + "expensive genrule targets."; |
| |
| @Override |
| protected void actionPerformedInBlazeProject(Project project, AnActionEvent e) { |
| BlazeProjectData blazeProjectData = |
| BlazeProjectDataManager.getInstance(project).getBlazeProjectData(); |
| if (blazeProjectData == null) { |
| return; |
| } |
| |
| new OpenBlazeWorkspaceFileActionDialog(project, blazeProjectData.workspacePathResolver).show(); |
| } |
| |
| private static class OpenBlazeWorkspaceFileActionDialog extends DialogWrapper { |
| |
| static final int PATH_FIELD_WIDTH = 40; |
| final Project project; |
| final WorkspacePathResolver workspacePathResolver; |
| final JPanel component; |
| final FileTextField fileTextField; |
| |
| OpenBlazeWorkspaceFileActionDialog( |
| Project project, WorkspacePathResolver workspacePathResolver) { |
| super(project, /* canBeParent */ false, IdeModalityType.PROJECT); |
| this.project = project; |
| this.workspacePathResolver = workspacePathResolver; |
| |
| FileChooserDescriptor descriptor = |
| FileChooserDescriptorFactory.createSingleFolderDescriptor(); |
| fileTextField = |
| WorkspaceFileTextField.create( |
| workspacePathResolver, descriptor, PATH_FIELD_WIDTH, myDisposable); |
| JBLabel directoryLabel = |
| new JBLabel("Directory:", AllIcons.Modules.SourceFolder, SwingConstants.LEFT); |
| JPanel directoryPanel = |
| SwingHelper.newHorizontalPanel( |
| Component.TOP_ALIGNMENT, directoryLabel, fileTextField.getField()); |
| |
| JBLabel warning = |
| new JBLabel( |
| "<html>" + WARNING_TEXT + "</html>", |
| AllIcons.General.BalloonWarning, |
| SwingConstants.LEFT); |
| warning.setPreferredSize(new Dimension(800, 100)); |
| component = |
| SwingHelper.newLeftAlignedVerticalPanel( |
| directoryPanel, warning, Box.createVerticalGlue()); |
| |
| setTitle("Add Directory to Project"); |
| |
| init(); |
| } |
| |
| @Nullable |
| @Override |
| protected JComponent createCenterPanel() { |
| return component; |
| } |
| |
| @Nullable |
| @Override |
| public JComponent getPreferredFocusedComponent() { |
| return fileTextField.getField(); |
| } |
| |
| @Nullable |
| @Override |
| protected ValidationInfo doValidate() { |
| VirtualFile selectedFile = fileTextField.getSelectedFile(); |
| if (selectedFile == null || !selectedFile.exists()) { |
| return new ValidationInfo("File does not exist", fileTextField.getField()); |
| } else if (!selectedFile.isDirectory()) { |
| return new ValidationInfo("File is not a directory", fileTextField.getField()); |
| } |
| |
| WorkspacePath workspacePath = |
| workspacePathResolver.getWorkspacePath(new File(selectedFile.getPath())); |
| if (workspacePath == null) { |
| return new ValidationInfo("File is not in workspace", fileTextField.getField()); |
| } |
| |
| ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet(); |
| checkState(projectViewSet != null); |
| |
| BlazeImportSettings importSettings = |
| BlazeImportSettingsManager.getInstance(project).getImportSettings(); |
| checkState(importSettings != null); |
| |
| ImportRoots importRoots = |
| ImportRoots.builder( |
| WorkspaceRoot.fromImportSettings(importSettings), importSettings.getBuildSystem()) |
| .add(projectViewSet) |
| .build(); |
| |
| if (importRoots.containsWorkspacePath(workspacePath)) { |
| return new ValidationInfo("This directory is already included in your project"); |
| } |
| |
| return null; |
| } |
| |
| @Override |
| protected void doOKAction() { |
| VirtualFile selectedFile = fileTextField.getSelectedFile(); |
| checkState(selectedFile != null); |
| WorkspacePath workspacePath = |
| workspacePathResolver.getWorkspacePath(new File(selectedFile.getPath())); |
| checkState(workspacePath != null); |
| |
| ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet(); |
| checkState(projectViewSet != null); |
| |
| Set<DirectoryEntry> existingDirectories = |
| ImmutableSet.copyOf(projectViewSet.listItems(DirectorySection.KEY)); |
| Set<TargetExpression> existingTargets = |
| ImmutableSet.copyOf(projectViewSet.listItems(TargetSection.KEY)); |
| |
| Set<WorkspacePath> pathsToAdd = new LinkedHashSet<>(); |
| pathsToAdd.add(workspacePath); |
| pathsToAdd.addAll( |
| RelatedWorkspacePathFinder.getInstance() |
| .findRelatedWorkspaceDirectories(workspacePathResolver, workspacePath)); |
| |
| Set<DirectoryEntry> newDirectories = |
| pathsToAdd |
| .stream() |
| .map(DirectoryEntry::include) |
| .filter(entry -> !existingDirectories.contains(entry)) |
| .collect(toCollection(LinkedHashSet::new)); |
| |
| Set<TargetExpression> newTargets = |
| pathsToAdd |
| .stream() |
| .map(TargetExpression::allFromPackageRecursive) |
| .filter(entry -> !existingTargets.contains(entry)) |
| .collect(toCollection(LinkedHashSet::new)); |
| |
| ProjectViewEdit edit = |
| ProjectViewEdit.editLocalProjectView( |
| project, |
| builder -> { |
| ListSection<DirectoryEntry> directories = builder.getLast(DirectorySection.KEY); |
| Builder<DirectoryEntry> directoriesUpdater = |
| ListSection.update(DirectorySection.KEY, directories); |
| newDirectories.forEach(directoriesUpdater::add); |
| builder.replace(directories, directoriesUpdater); |
| |
| ListSection<TargetExpression> targets = builder.getLast(TargetSection.KEY); |
| Builder<TargetExpression> targetsUpdater = |
| ListSection.update(TargetSection.KEY, targets); |
| newTargets.forEach(targetsUpdater::add); |
| builder.replace(targets, targetsUpdater); |
| |
| return true; |
| }); |
| |
| if (edit == null) { |
| Messages.showErrorDialog( |
| "Could not modify project view. Check for errors in your project view and try again", |
| "Error"); |
| return; |
| } |
| |
| edit.apply(); |
| |
| BlazeSyncManager.getInstance(project) |
| .requestProjectSync( |
| new BlazeSyncParams.Builder("Sync", BlazeSyncParams.SyncMode.INCREMENTAL) |
| .addProjectViewTargets(true) |
| .addWorkingSet(BlazeUserSettings.getInstance().getExpandSyncToWorkingSet()) |
| .build()); |
| |
| super.doOKAction(); |
| } |
| } |
| } |