IDEA-108938 External system: Provide ability to detach linked external project

Corresponding action is added to the external system tool window. Recent tasks, regular tasks and (sub-)project nodes are removed as well
This commit is contained in:
Denis.Zhdanov
2013-06-13 23:38:46 +04:00
parent 62839c713e
commit df6c5fa120
22 changed files with 461 additions and 89 deletions
@@ -17,6 +17,7 @@ package com.intellij.externalSystem;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.model.Key;
import com.intellij.openapi.externalSystem.model.ProjectKeys;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.AbstractExternalEntityData;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
@@ -33,9 +34,9 @@ import java.util.regex.Pattern;
* @since 4/12/13 12:27 PM
*/
public class JavaProjectData extends AbstractExternalEntityData {
@NotNull public static final Key<JavaProjectData> KEY = Key.create(JavaProjectData.class);
@NotNull public static final Key<JavaProjectData> KEY = Key.create(JavaProjectData.class, ProjectKeys.PROJECT.getProcessingWeight() + 1);
private static final Logger LOG = Logger.getInstance("#" + JavaProjectData.class.getName());
private static final long serialVersionUID = 1L;
@@ -47,7 +48,7 @@ public class JavaProjectData extends AbstractExternalEntityData {
@NotNull private JavaSdkVersion myJdkVersion = DEFAULT_JDK_VERSION;
@NotNull private LanguageLevel myLanguageLevel = DEFAULT_LANGUAGE_LEVEL;
@NotNull private String myCompileOutputPath;
@NotNull private String myCompileOutputPath;
public JavaProjectData(@NotNull ProjectSystemId owner, @NotNull String compileOutputPath) {
super(owner);
@@ -31,8 +31,8 @@ tool.window.title.tasks=tasks
# Action.
action.refresh.all.projects.text=Refresh all {0} projects
action.refresh.all.projects.description=Force refresh all linked {0} projects
action.task.run.text=Run
action.task.run.description=Run selected task
action.detach.external.project.text=Detach
action.detach.external.project.description=Detach selected external project
# Notification
notification.project.refresh.fail.description={0} ''{1}'' project refresh failed:\n{2}
@@ -31,19 +31,45 @@ import java.io.Serializable;
* @since 4/12/13 11:49 AM
* @param <T> data class
*/
public class Key<T> implements Serializable {
@SuppressWarnings("UnusedDeclaration")
public class Key<T> implements Serializable, Comparable<Key<?>> {
private static final long serialVersionUID = 1L;
@NotNull private final String myDataClass;
private final int myProcessingWeight;
public Key(@NotNull String dataClass) {
/**
* Creates new <code>Key</code> object.
*
* @param dataClass class of the payload data which will be associated with the current key
* @param processingWeight there is a possible case that when a {@link DataNode} object has children of more than on type (children
* with more than one different {@link Key} we might want to process one type of children before another.
* That's why we need a way to define that processing order. This parameter serves exactly for that -
* lower value means that key's payload should be processed <b>before</b> payload of the key with a greater
* value
*/
public Key(@NotNull String dataClass, int processingWeight) {
myDataClass = dataClass;
myProcessingWeight = processingWeight;
}
@NotNull
public static <T> Key<T> create(@NotNull Class<T> dataClass) {
return new Key<T>(dataClass.getName());
public static <T> Key<T> create(@NotNull Class<T> dataClass, int processingWeight) {
return new Key<T>(dataClass.getName(), processingWeight);
}
/**
* There is a possible case that when a {@link DataNode} object has children of more than on type (children with more than
* one different {@link Key} we might want to process one type of children before another. That's why we need a way to define
* that processing order. This property serves exactly for that - lower value means that key's payload should be processed
* <b>before</b> payload of the key with a greater value.
*
* @return processing weight for data associated with the current key
*/
public int getProcessingWeight() {
return myProcessingWeight;
}
@Override
@@ -63,6 +89,11 @@ public class Key<T> implements Serializable {
return true;
}
@Override
public int compareTo(@NotNull Key<?> that) {
return myProcessingWeight - that.myProcessingWeight;
}
@Override
public String toString() {
int i = myDataClass.lastIndexOf('.');
@@ -27,14 +27,14 @@ import org.jetbrains.annotations.NotNull;
*/
public class ProjectKeys {
@NotNull public static final Key<ProjectData> PROJECT = Key.create(ProjectData.class);
@NotNull public static final Key<ModuleData> MODULE = Key.create(ModuleData.class);
@NotNull public static final Key<LibraryData> LIBRARY = Key.create(LibraryData.class);
@NotNull public static final Key<ContentRootData> CONTENT_ROOT = Key.create(ContentRootData.class);
@NotNull public static final Key<ModuleDependencyData> MODULE_DEPENDENCY = Key.create(ModuleDependencyData.class);
@NotNull public static final Key<LibraryDependencyData> LIBRARY_DEPENDENCY = Key.create(LibraryDependencyData.class);
@NotNull public static final Key<ProjectData> PROJECT = Key.create(ProjectData.class, 50);
@NotNull public static final Key<ModuleData> MODULE = Key.create(ModuleData.class, 70);
@NotNull public static final Key<LibraryData> LIBRARY = Key.create(LibraryData.class, 90);
@NotNull public static final Key<ContentRootData> CONTENT_ROOT = Key.create(ContentRootData.class, 110);
@NotNull public static final Key<ModuleDependencyData> MODULE_DEPENDENCY = Key.create(ModuleDependencyData.class, 130);
@NotNull public static final Key<LibraryDependencyData> LIBRARY_DEPENDENCY = Key.create(LibraryDependencyData.class, 150);
@NotNull public static final Key<TaskData> TASK = Key.create(TaskData.class);
@NotNull public static final Key<TaskData> TASK = Key.create(TaskData.class, 250);
private ProjectKeys() {
}
@@ -15,9 +15,12 @@
*/
package com.intellij.openapi.externalSystem.settings;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo;
import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo;
import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo;
import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.project.Project;
import com.intellij.util.SystemProperties;
import com.intellij.util.containers.ContainerUtilRt;
import org.jetbrains.annotations.NotNull;
@@ -58,6 +61,48 @@ public abstract class AbstractExternalSystemLocalSettings {
ContainerUtilRt.<String, Collection<ExternalTaskPojo>>newHashMap()
);
@NotNull private final ProjectSystemId myExternalSystemId;
@NotNull private final Project myProject;
protected AbstractExternalSystemLocalSettings(@NotNull ProjectSystemId externalSystemId, @NotNull Project project) {
myExternalSystemId = externalSystemId;
myProject = project;
}
/**
* Asks current settings to drop all information related to external project which root config is located at the given path.
*
* @param linkedProjectPathsToForget target root external project's path
*/
public void forgetExternalProject(@NotNull Set<String> linkedProjectPathsToForget) {
Map<ExternalProjectPojo, Collection<ExternalProjectPojo>> projects = myAvailableProjects.get();
for (Iterator<Map.Entry<ExternalProjectPojo, Collection<ExternalProjectPojo>>> it = projects.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<ExternalProjectPojo, Collection<ExternalProjectPojo>> entry = it.next();
if (linkedProjectPathsToForget.contains(entry.getKey().getPath())) {
it.remove();
}
}
for (Iterator<Map.Entry<String, Collection<ExternalTaskPojo>>> it = myAvailableTasks.get().entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String, Collection<ExternalTaskPojo>> entry = it.next();
if (linkedProjectPathsToForget.contains(entry.getKey())
|| linkedProjectPathsToForget.contains(ExternalSystemApiUtil.getRootProjectPath(entry.getKey(), myExternalSystemId, myProject)))
{
it.remove();
}
}
for (Iterator<ExternalTaskExecutionInfo> it = myRecentTasks.get().iterator(); it.hasNext(); ) {
ExternalTaskExecutionInfo taskInfo = it.next();
String path = taskInfo.getSettings().getExternalProjectPath();
if (linkedProjectPathsToForget.contains(path) ||
linkedProjectPathsToForget.contains(ExternalSystemApiUtil.getRootProjectPath(path, myExternalSystemId, myProject)))
{
it.remove();
}
}
}
@SuppressWarnings("UnusedDeclaration")
@NotNull
public Map<String, Boolean> getExpandStates() { // Necessary for the serialization.
@@ -55,6 +55,24 @@ public abstract class AbstractExternalSystemSettings<S extends ExternalProjectSe
return myLinkedProjectsSettings.get(linkedProjectPath);
}
/**
* Un-links given external project from the current ide project.
*
* @param linkedProjectPath path of external project to be unlinked
* @return <code>true</code> if there was an external project with the given config path linked to the current
* ide project;
* <code>false</code> otherwise
*/
public boolean unlinkExternalProject(@NotNull String linkedProjectPath) {
S removed = myLinkedProjectsSettings.remove(linkedProjectPath);
if (removed == null) {
return false;
}
getPublisher().onProjectsUnlinked(Collections.singleton(linkedProjectPath));
return true;
}
public void setLinkedProjectsSettings(@NotNull Collection<S> settings) {
List<S> added = ContainerUtilRt.newArrayList();
Map<String, S> removed = ContainerUtilRt.newHashMap(myLinkedProjectsSettings);
@@ -18,6 +18,7 @@ package com.intellij.openapi.externalSystem.settings;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Set;
/**
* Defines callback for external system settings change.
@@ -31,7 +32,7 @@ public interface ExternalSystemSettingsListener<S extends ExternalProjectSetting
void onProjectsLinked(@NotNull Collection<S> settings);
void onProjectsUnlinked(@NotNull Collection<String> linkedProjectPaths);
void onProjectsUnlinked(@NotNull Set<String> linkedProjectPaths);
void onUseAutoImportChange(boolean currentValue, @NotNull String linkedProjectPath);
@@ -0,0 +1,48 @@
/*
* Copyright 2000-2013 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.intellij.openapi.externalSystem.settings;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Set;
/**
* @author Denis Zhdanov
* @since 6/13/13 7:37 PM
*/
public class ExternalSystemSettingsListenerAdapter<S extends ExternalProjectSettings> implements ExternalSystemSettingsListener<S> {
@Override
public void onProjectsLinked(@NotNull Collection<S> settings) {
}
@Override
public void onProjectsUnlinked(@NotNull Set<String> linkedProjectPaths) {
}
@Override
public void onUseAutoImportChange(boolean currentValue, @NotNull String linkedProjectPath) {
}
@Override
public void onBulkChangeStart() {
}
@Override
public void onBulkChangeEnd() {
}
}
@@ -19,11 +19,13 @@ import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.ExternalSystemAutoImportAware;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.Key;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
@@ -53,7 +55,8 @@ import java.util.regex.Pattern;
*/
public class ExternalSystemApiUtil {
private static final Logger LOG = Logger.getInstance("#" + ExternalSystemApiUtil.class.getName());
private static final Logger LOG =
Logger.getInstance("#" + ExternalSystemApiUtil.class.getName());
private static final String LAST_USED_PROJECT_PATH_PREFIX = "LAST_EXTERNAL_PROJECT_PATH_";
@NotNull public static final String PATH_SEPARATOR = "/";
@@ -74,6 +77,7 @@ public class ExternalSystemApiUtil {
};
@NotNull public static final Comparator<Object> ORDER_AWARE_COMPARATOR = new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
int order1 = getOrder(o1);
@@ -100,6 +104,20 @@ public class ExternalSystemApiUtil {
}
};
@NotNull private static final Function<DataNode<?>, Key<?>> GROUPER = new Function<DataNode<?>, Key<?>>() {
@Override
public Key<?> fun(DataNode<?> node) {
return node.getKey();
}
};
@NotNull private static final Comparator<Object> COMPARABLE_GLUE = new Comparator<Object>() {
@SuppressWarnings("unchecked")
@Override
public int compare(Object o1, Object o2) {
return ((Comparable)o1).compareTo(o2);
}
};
private ExternalSystemApiUtil() {
}
@@ -192,18 +210,7 @@ public class ExternalSystemApiUtil {
@NotNull
public static Map<Key<?>, List<DataNode<?>>> group(@NotNull Collection<DataNode<?>> nodes) {
if (nodes.isEmpty()) {
return Collections.emptyMap();
}
Map<Key<?>, List<DataNode<?>>> result = ContainerUtilRt.newHashMap();
for (DataNode<?> node : nodes) {
List<DataNode<?>> n = result.get(node.getKey());
if (n == null) {
result.put(node.getKey(), n = ContainerUtilRt.newArrayList());
}
n.add(node);
}
return result;
return groupBy(nodes, GROUPER);
}
@NotNull
@@ -236,9 +243,19 @@ public class ExternalSystemApiUtil {
}
grouped.add(data);
}
if (!result.isEmpty() && result.keySet().iterator().next() instanceof Comparable) {
List<K> ordered = ContainerUtilRt.newArrayList(result.keySet());
Collections.sort(ordered, COMPARABLE_GLUE);
Map<K, List<V>> orderedResult = ContainerUtilRt.newLinkedHashMap();
for (K k : ordered) {
orderedResult.put(k, result.get(k));
}
return orderedResult;
}
return result;
}
@SuppressWarnings("unchecked")
@NotNull
public static <T> Collection<DataNode<T>> getChildren(@NotNull DataNode<?> node, @NotNull Key<T> key) {
@@ -388,4 +405,32 @@ public class ExternalSystemApiUtil {
buffer.insert(0, rootProjectDir.getName());
return buffer.toString();
}
/**
* There is a possible case that external project linked to an ide project is a multi-project, i.e. contains more than one
* module.
* <p/>
* This method tries to find root project's config path assuming that given path points to a sub-project's config path.
*
* @param externalProjectPath external sub-project's config path
* @param externalSystemId target external system
* @param project target ide project
* @return root external project's path if given path is considered to point to a known sub-project's config;
* <code>null</code> if it's not possible to find a root project's config path on the basis of the
* given path
*/
@Nullable
public static String getRootProjectPath(@NotNull String externalProjectPath,
@NotNull ProjectSystemId externalSystemId,
@NotNull Project project)
{
ExternalSystemManager<?, ?, ?, ?, ?> manager = getManager(externalSystemId);
if (manager == null) {
return null;
}
if (manager instanceof ExternalSystemAutoImportAware) {
return ((ExternalSystemAutoImportAware)manager).getAffectedExternalProjectPath(externalProjectPath, project);
}
return null;
}
}
@@ -0,0 +1,132 @@
/*
* Copyright 2000-2013 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.intellij.openapi.externalSystem.action;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo;
import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemRecentTasksList;
import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemTasksTreeModel;
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings;
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings;
import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Collections;
/**
* @author Denis Zhdanov
* @since 6/13/13 5:42 PM
*/
public class DetachExternalProjectAction extends AnAction implements DumbAware {
public DetachExternalProjectAction() {
getTemplatePresentation().setText(ExternalSystemBundle.message("action.detach.external.project.text"));
getTemplatePresentation().setDescription(ExternalSystemBundle.message("action.detach.external.project.description"));
}
@Override
public void update(AnActionEvent e) {
MyInfo info = getProcessingInfo(e.getDataContext());
if (info.icon != null) {
e.getPresentation().setIcon(info.icon);
}
e.getPresentation().setVisible(info.externalProject != null);
}
@Override
public void actionPerformed(AnActionEvent e) {
MyInfo info = getProcessingInfo(e.getDataContext());
if (info.settings == null || info.localSettings == null || info.externalProject == null) {
return;
}
ExternalSystemTasksTreeModel allTasksModel = ExternalSystemDataKeys.ALL_TASKS_MODEL.getData(e.getDataContext());
if (allTasksModel != null) {
allTasksModel.pruneNodes(info.externalProject);
}
ExternalSystemRecentTasksList recentTasksList = ExternalSystemDataKeys.RECENT_TASKS_LIST.getData(e.getDataContext());
if (recentTasksList != null) {
recentTasksList.getModel().forgetTasksFrom(info.externalProject.getPath());
}
info.localSettings.forgetExternalProject(Collections.singleton(info.externalProject.getPath()));
info.settings.unlinkExternalProject(info.externalProject.getPath());
}
@NotNull
private static MyInfo getProcessingInfo(@NotNull DataContext context) {
ExternalProjectPojo externalProject = ExternalSystemDataKeys.SELECTED_PROJECT.getData(context);
if (externalProject == null) {
return MyInfo.EMPTY;
}
ProjectSystemId externalSystemId = ExternalSystemDataKeys.EXTERNAL_SYSTEM_ID.getData(context);
if (externalSystemId == null) {
return MyInfo.EMPTY;
}
Project ideProject = PlatformDataKeys.PROJECT.getData(context);
if (ideProject == null) {
return MyInfo.EMPTY;
}
ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(externalSystemId);
assert manager != null;
AbstractExternalSystemSettings<?, ?> settings = manager.getSettingsProvider().fun(ideProject);
ExternalProjectSettings externalProjectSettings = settings.getLinkedProjectSettings(externalProject.getPath());
AbstractExternalSystemLocalSettings localSettings = manager.getLocalSettingsProvider().fun(ideProject);
Icon icon = ExternalSystemUiUtil.getUiAware(externalSystemId).getProjectIcon();
return new MyInfo(externalProjectSettings == null ? null : settings,
localSettings == null ? null : localSettings,
externalProjectSettings == null ? null : externalProject,
icon);
}
private static class MyInfo {
public static final MyInfo EMPTY = new MyInfo(null, null, null, null);
@Nullable public final AbstractExternalSystemSettings<?, ?> settings;
@Nullable public final AbstractExternalSystemLocalSettings localSettings;
@Nullable public final ExternalProjectPojo externalProject;
@Nullable public final Icon icon;
MyInfo(@Nullable AbstractExternalSystemSettings<?, ?> settings,
@Nullable AbstractExternalSystemLocalSettings localSettings,
@Nullable ExternalProjectPojo externalProject,
@Nullable Icon icon)
{
this.settings = settings;
this.localSettings = localSettings;
this.externalProject = externalProject;
this.icon = icon;
}
}
}
@@ -18,6 +18,7 @@ package com.intellij.openapi.externalSystem.model;
import com.intellij.notification.NotificationGroup;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo;
import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo;
import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemRecentTasksList;
import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemTasksTreeModel;
import org.jetbrains.annotations.NotNull;
@@ -32,6 +33,7 @@ public class ExternalSystemDataKeys {
@NotNull public static final DataKey<NotificationGroup> NOTIFICATION_GROUP = DataKey.create("external.system.notification");
@NotNull public static final DataKey<ExternalSystemTasksTreeModel> ALL_TASKS_MODEL = DataKey.create("external.system.all.tasks.model");
@NotNull public static final DataKey<ExternalTaskPojo> SELECTED_TASK = DataKey.create("external.system.selected.task");
@NotNull public static final DataKey<ExternalProjectPojo> SELECTED_PROJECT = DataKey.create("external.system.selected.project");
@NotNull public static final DataKey<ExternalSystemRecentTasksList> RECENT_TASKS_LIST
= DataKey.create("external.system.recent.tasks.list");
@@ -69,8 +69,9 @@ public class ExternalSystemTaskSettingsControl implements ExternalSystemSettings
@Override
public void fillUi(@NotNull final PaintAwarePanel canvas, int indentLevel) {
myProjectPathLabel =
new JBLabel(ExternalSystemBundle.message("run.configuration.settings.label.project", myExternalSystemId.getReadableName()));
myProjectPathLabel = new JBLabel(ExternalSystemBundle.message(
"run.configuration.settings.label.project", myExternalSystemId.getReadableName()
));
ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(myExternalSystemId);
FileChooserDescriptor projectPathChooserDescriptor = null;
if (manager instanceof ExternalSystemUiAware) {
@@ -15,7 +15,11 @@
*/
package com.intellij.openapi.externalSystem.service.task.ui;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants;
import com.intellij.openapi.project.Project;
import com.intellij.util.containers.ContainerUtilRt;
import org.jetbrains.annotations.NotNull;
@@ -28,6 +32,16 @@ import java.util.List;
*/
public class ExternalSystemRecentTaskListModel extends DefaultListModel {
@NotNull private final ProjectSystemId myExternalSystemId;
@NotNull private final Project myProject;
public ExternalSystemRecentTaskListModel(@NotNull ProjectSystemId externalSystemId, @NotNull Project project) {
myExternalSystemId = externalSystemId;
myProject = project;
ensureSize(ExternalSystemConstants.RECENT_TASKS_NUMBER);
}
@SuppressWarnings("unchecked")
public void setTasks(@NotNull List<ExternalTaskExecutionInfo> tasks) {
clear();
List<ExternalTaskExecutionInfo> tasksToUse = ContainerUtilRt.newArrayList(tasks);
@@ -36,6 +50,7 @@ public class ExternalSystemRecentTaskListModel extends DefaultListModel {
}
}
@SuppressWarnings("unchecked")
public void setFirst(@NotNull ExternalTaskExecutionInfo task) {
insertElementAt(task, 0);
if (size() > 1) {
@@ -44,9 +59,10 @@ public class ExternalSystemRecentTaskListModel extends DefaultListModel {
for (int i = 1; i < size(); i++) {
if (task.equals(getElementAt(i))) {
remove(i);
return;
break;
}
}
ensureSize(ExternalSystemConstants.RECENT_TASKS_NUMBER);
}
@NotNull
@@ -61,6 +77,7 @@ public class ExternalSystemRecentTaskListModel extends DefaultListModel {
return result;
}
@SuppressWarnings("unchecked")
public void ensureSize(int elementsNumber) {
int toAdd = elementsNumber - size();
if (toAdd <= 0) {
@@ -71,6 +88,26 @@ public class ExternalSystemRecentTaskListModel extends DefaultListModel {
}
}
/**
* Asks current model to remove all 'recent task info' entries which point to tasks from external project with the given path.
*
* @param externalProjectPath target external project's path
*/
public void forgetTasksFrom(@NotNull String externalProjectPath) {
for (int i = size() - 1; i >= 0; i--) {
Object e = getElementAt(i);
if (e instanceof ExternalTaskExecutionInfo) {
String path = ((ExternalTaskExecutionInfo)e).getSettings().getExternalProjectPath();
if (externalProjectPath.equals(path)
|| externalProjectPath.equals(ExternalSystemApiUtil.getRootProjectPath(path, myExternalSystemId, myProject)))
{
removeElementAt(i);
}
}
}
ensureSize(ExternalSystemConstants.RECENT_TASKS_NUMBER);
}
static class MyEmptyDescriptor {
}
}
@@ -66,7 +66,6 @@ public class ExternalSystemRecentTasksList extends JBList implements Producer<Ex
}
setCellRenderer(new MyRenderer(project, icon, ExternalSystemUtil.findConfigurationType(externalSystemId)));
setVisibleRowCount(ExternalSystemConstants.RECENT_TASKS_NUMBER);
model.ensureSize(ExternalSystemConstants.RECENT_TASKS_NUMBER);
addMouseListener(new MouseAdapter() {
@Override
@@ -94,7 +93,6 @@ public class ExternalSystemRecentTasksList extends JBList implements Producer<Ex
ExternalTaskExecutionInfo selected = produce();
ExternalSystemRecentTaskListModel model = getModel();
model.setFirst(task);
model.ensureSize(ExternalSystemConstants.RECENT_TASKS_NUMBER);
clearSelection();
if (selected == null) {
return;
@@ -26,6 +26,7 @@ import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo;
import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo;
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemTaskLocation;
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
@@ -79,7 +80,7 @@ public class ExternalSystemTasksPanel extends SimpleToolWindowPanel implements D
assert manager != null;
AbstractExternalSystemLocalSettings settings = manager.getLocalSettingsProvider().fun(project);
ExternalSystemRecentTaskListModel recentTasksModel = new ExternalSystemRecentTaskListModel();
ExternalSystemRecentTaskListModel recentTasksModel = new ExternalSystemRecentTaskListModel(externalSystemId, project);
recentTasksModel.setTasks(settings.getRecentTasks());
myRecentTasksList = new ExternalSystemRecentTasksList(recentTasksModel, externalSystemId, project) {
@Override
@@ -144,6 +145,18 @@ public class ExternalSystemTasksPanel extends SimpleToolWindowPanel implements D
else if (ExternalSystemDataKeys.SELECTED_TASK.is(dataId)) {
return mySelectedTaskProvider == null ? null : mySelectedTaskProvider.produce();
}
else if (ExternalSystemDataKeys.SELECTED_PROJECT.is(dataId)) {
if (mySelectedTaskProvider != myAllTasksTree) {
return null;
}
else {
Object component = myAllTasksTree.getLastSelectedPathComponent();
if (component instanceof ExternalSystemNode) {
Object element = ((ExternalSystemNode)component).getDescriptor().getElement();
return element instanceof ExternalProjectPojo ? element : null;
}
}
}
else if (Location.DATA_KEY.is(dataId)) {
Location location = buildLocation();
return location == null ? super.getData(dataId) : location;
@@ -16,15 +16,12 @@
package com.intellij.openapi.externalSystem.service.task.ui;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.ExternalSystemUiAware;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.execution.ExternalSystemTaskExecutionSettings;
import com.intellij.openapi.externalSystem.model.execution.ExternalTaskExecutionInfo;
import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo;
import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo;
import com.intellij.openapi.externalSystem.service.ui.DefaultExternalSystemUiAware;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.util.containers.ContainerUtilRt;
@@ -78,13 +75,7 @@ public class ExternalSystemTasksTreeModel extends DefaultTreeModel {
public ExternalSystemTasksTreeModel(@NotNull ProjectSystemId externalSystemId) {
super(new ExternalSystemNode<String>(new ExternalSystemNodeDescriptor<String>("", "", null)));
myExternalSystemId = externalSystemId;
ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(externalSystemId);
if (manager instanceof ExternalSystemUiAware) {
myUiAware = (ExternalSystemUiAware)manager;
}
else {
myUiAware = DefaultExternalSystemUiAware.INSTANCE;
}
myUiAware = ExternalSystemUiUtil.getUiAware(externalSystemId);
}
private static String getTaskName(@NotNull ExternalTaskExecutionInfo taskInfo) {
@@ -120,6 +111,27 @@ public class ExternalSystemTasksTreeModel extends DefaultTreeModel {
return result;
}
/**
* Asks current model to remove all nodes which have given data as a {@link ExternalSystemNodeDescriptor#getElement() payload}.
*
* @param payload target payload
*/
public void pruneNodes(@NotNull Object payload) {
Deque<ExternalSystemNode<?>> toProcess = new ArrayDeque<ExternalSystemNode<?>>();
toProcess.addFirst(getRoot());
while (!toProcess.isEmpty()) {
ExternalSystemNode<?> node = toProcess.removeLast();
if (payload.equals(node.getDescriptor().getElement())) {
removeNodeFromParent(node);
}
else {
for (int i = 0; i < node.getChildCount(); i++) {
toProcess.addFirst(node.getChildAt(i));
}
}
}
}
public void ensureSubProjectsStructure(@NotNull ExternalProjectPojo topLevelProject,
@NotNull Collection<ExternalProjectPojo> subProjects)
{
@@ -162,6 +174,9 @@ public class ExternalSystemTasksTreeModel extends DefaultTreeModel {
}
public void ensureTasks(@NotNull String externalProjectConfigPath, @NotNull Collection<ExternalTaskPojo> tasks) {
if (tasks.isEmpty()) {
return;
}
ExternalSystemNode<ExternalProjectPojo> moduleNode = findProjectNode(externalProjectConfigPath);
if (moduleNode == null) {
LOG.warn(String.format(
@@ -186,7 +201,7 @@ public class ExternalSystemTasksTreeModel extends DefaultTreeModel {
}
}
}
if (!toAdd.isEmpty()) {
for (ExternalTaskExecutionInfo taskInfo : toAdd) {
moduleNode.add(new ExternalSystemNode<ExternalTaskExecutionInfo>(descriptor(taskInfo, myUiAware.getTaskIcon())));
@@ -31,6 +31,7 @@ import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemTasksTr
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.externalSystem.util.ExternalSystemBundle;
import com.intellij.openapi.externalSystem.util.ExternalSystemUiUtil;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.project.Project;
@@ -166,13 +167,7 @@ public class ExternalProjectPathField extends ComponentWithBrowseButton<External
ExternalSystemManager<?, ?, ?, ?, ?> manager = ExternalSystemApiUtil.getManager(externalSystemId);
assert manager != null;
final AbstractExternalSystemLocalSettings settings = manager.getLocalSettingsProvider().fun(project);
final ExternalSystemUiAware uiAware;
if (manager instanceof ExternalSystemUiAware) {
uiAware = (ExternalSystemUiAware)manager;
}
else {
uiAware = DefaultExternalSystemUiAware.INSTANCE;
}
final ExternalSystemUiAware uiAware = ExternalSystemUiUtil.getUiAware(externalSystemId);
TextFieldCompletionProvider provider = new TextFieldCompletionProviderDumbAware() {
@Override
protected void addCompletionVariants(@NotNull String text, int offset, @NotNull String prefix, @NotNull CompletionResultSet result) {
@@ -224,13 +219,7 @@ public class ExternalProjectPathField extends ComponentWithBrowseButton<External
ExternalSystemManager<?,?,?,?,?> manager = ExternalSystemApiUtil.getManager(externalSystemId);
assert manager != null;
final AbstractExternalSystemLocalSettings settings = manager.getLocalSettingsProvider().fun(project);
final ExternalSystemUiAware uiAware;
if (manager instanceof ExternalSystemUiAware) {
uiAware = (ExternalSystemUiAware)manager;
}
else {
uiAware = DefaultExternalSystemUiAware.INSTANCE;
}
final ExternalSystemUiAware uiAware = ExternalSystemUiUtil.getUiAware(externalSystemId);
String rawText = editor.getDocument().getText();
for (Map.Entry<ExternalProjectPojo, Collection<ExternalProjectPojo>> entry : settings.getAvailableProjects().entrySet()) {
@@ -16,9 +16,13 @@
package com.intellij.openapi.externalSystem.util;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.externalSystem.ExternalSystemManager;
import com.intellij.openapi.externalSystem.ExternalSystemUiAware;
import com.intellij.openapi.externalSystem.model.ProjectSystemId;
import com.intellij.openapi.externalSystem.model.project.ExternalProjectPojo;
import com.intellij.openapi.externalSystem.model.execution.ExternalTaskPojo;
import com.intellij.openapi.externalSystem.service.task.ui.ExternalSystemTasksTreeModel;
import com.intellij.openapi.externalSystem.service.ui.DefaultExternalSystemUiAware;
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalSettings;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.Balloon;
@@ -179,4 +183,10 @@ public class ExternalSystemUiUtil {
}
}
}
@NotNull
public static ExternalSystemUiAware getUiAware(@NotNull ProjectSystemId externalSystemId) {
ExternalSystemManager<?,?,?,?,?> manager = ExternalSystemApiUtil.getManager(externalSystemId);
return manager instanceof ExternalSystemUiAware ? (ExternalSystemUiAware)manager : DefaultExternalSystemUiAware.INSTANCE;
}
}
@@ -12,6 +12,8 @@
<!--Context menu action-->
<group id="ExternalSystem.Tree.Context" popup="true">
<action id="ExternalSystem.DetachProject"
class="com.intellij.openapi.externalSystem.action.DetachExternalProjectAction"/>
<reference ref="RunContextGroup"/>
</group>
@@ -1,17 +1,18 @@
package org.jetbrains.plugins.gradle.config;
import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListenerAdapter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings;
import org.jetbrains.plugins.gradle.settings.GradleSettingsListener;
import java.util.Collection;
/**
* @author Denis Zhdanov
* @since 3/13/12 3:53 PM
*/
public abstract class GradleSettingsListenerAdapter implements GradleSettingsListener {
public abstract class GradleSettingsListenerAdapter extends ExternalSystemSettingsListenerAdapter<GradleProjectSettings>
implements GradleSettingsListener
{
@Override
public void onGradleHomeChange(@Nullable String oldPath, @Nullable String newPath, @NotNull String linkedProjectPath) {
@@ -24,24 +25,4 @@ public abstract class GradleSettingsListenerAdapter implements GradleSettingsLis
@Override
public void onServiceDirectoryPathChange(@Nullable String oldPath, @Nullable String newPath) {
}
@Override
public void onProjectsLinked(@NotNull Collection<GradleProjectSettings> settings) {
}
@Override
public void onProjectsUnlinked(@NotNull Collection<String> linkedProjectPaths) {
}
@Override
public void onUseAutoImportChange(boolean currentValue, @NotNull String linkedProjectPath) {
}
@Override
public void onBulkChangeStart() {
}
@Override
public void onBulkChangeEnd() {
}
}
@@ -5,14 +5,12 @@ import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionToolbar;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.SimpleToolWindowPanel;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.SideBorder;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.settings.GradleSettings;
import org.jetbrains.plugins.gradle.settings.GradleSettingsListener;
import org.jetbrains.plugins.gradle.ui.RichTextControlBuilder;
@@ -5,6 +5,7 @@ import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemLocalS
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.util.GradleConstants;
/**
* @author Denis Zhdanov
@@ -15,6 +16,10 @@ public class GradleLocalSettings extends AbstractExternalSystemLocalSettings
implements PersistentStateComponent<AbstractExternalSystemLocalSettings.State>
{
public GradleLocalSettings(@NotNull Project project) {
super(GradleConstants.SYSTEM_ID, project);
}
@NotNull
public static GradleLocalSettings getInstance(@NotNull Project project) {
return ServiceManager.getService(project, GradleLocalSettings.class);