diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/BaseExternalSystemProgressEvent.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/BaseExternalSystemProgressEvent.java new file mode 100644 index 000000000000..507b99ea5f41 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/BaseExternalSystemProgressEvent.java @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Vladislav.Soroka + * @since 11/27/2015 + */ +public class BaseExternalSystemProgressEvent implements ExternalSystemProgressEvent { + @NotNull private final String myEventId; + @NotNull private final String myDescription; + @Nullable private final String myParentEventId; + private final long myEventTime; + + public BaseExternalSystemProgressEvent(@NotNull String eventId, + @Nullable String parentEventId, + @NotNull String description, + long eventTime) { + myEventId = eventId; + myDescription = description; + myParentEventId = parentEventId; + myEventTime = eventTime; + } + + @NotNull + @Override + public String getEventId() { + return myEventId; + } + + @Nullable + @Override + public String getParentEventId() { + return myParentEventId; + } + + @NotNull + @Override + public String getDescription() { + return myDescription; + } + + @Override + public long getEventTime() { + return myEventTime; + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/DefaultOperationResult.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/DefaultOperationResult.java new file mode 100644 index 000000000000..b2c4fdd7a7ed --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/DefaultOperationResult.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +/** + * @author Vladislav.Soroka + * @since 12/2/2015 + */ +public class DefaultOperationResult implements OperationResult { + + private final long myStartTime; + private final long myEndTime; + + public DefaultOperationResult(long startTime, long endTime) { + myStartTime = startTime; + myEndTime = endTime; + } + + @Override + public long getStartTime() { + return myStartTime; + } + + @Override + public long getEndTime() { + return myEndTime; + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemFinishEvent.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemFinishEvent.java new file mode 100644 index 000000000000..1b4e609edef4 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemFinishEvent.java @@ -0,0 +1,24 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +/** + * @author Vladislav.Soroka + * @since 11/27/2015 + */ +public interface ExternalSystemFinishEvent extends ExternalSystemProgressEvent { + OperationResult getOperationResult(); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemFinishEventImpl.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemFinishEventImpl.java new file mode 100644 index 000000000000..7998d3a820b1 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemFinishEventImpl.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Vladislav.Soroka + * @since 11/27/2015 + */ +public class ExternalSystemFinishEventImpl extends BaseExternalSystemProgressEvent implements ExternalSystemFinishEvent { + @NotNull + private final OperationResult myResult; + public ExternalSystemFinishEventImpl(@NotNull String eventId, + @Nullable String parentEventId, + @NotNull String description, + @NotNull OperationResult result) { + super(eventId, parentEventId, description, result.getEndTime()); + myResult = result; + } + + @Override + public OperationResult getOperationResult() { + return myResult; + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemProgressEvent.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemProgressEvent.java new file mode 100644 index 000000000000..7a7af09271ed --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemProgressEvent.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.Serializable; + +/** + * @author Vladislav.Soroka + * @since 11/27/2015 + */ +public interface ExternalSystemProgressEvent extends Serializable { + @NotNull + String getEventId(); + + @Nullable + String getParentEventId(); + + @NotNull + String getDescription(); + + long getEventTime(); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemStartEvent.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemStartEvent.java new file mode 100644 index 000000000000..be34037262f8 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemStartEvent.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +/** + * @author Vladislav.Soroka + * @since 11/27/2015 + */ +public interface ExternalSystemStartEvent extends ExternalSystemProgressEvent{ +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemStartEventImpl.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemStartEventImpl.java new file mode 100644 index 000000000000..c8ac0b1aa164 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemStartEventImpl.java @@ -0,0 +1,29 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Vladislav.Soroka + * @since 11/27/2015 + */ +public class ExternalSystemStartEventImpl extends BaseExternalSystemProgressEvent implements ExternalSystemStartEvent { + public ExternalSystemStartEventImpl(@NotNull String eventId, @Nullable String parentEventId, @NotNull String description, long eventTime) { + super(eventId, parentEventId, description, eventTime); + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemTaskExecutionEvent.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemTaskExecutionEvent.java new file mode 100644 index 000000000000..e3ffb0b9d35b --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/ExternalSystemTaskExecutionEvent.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationEvent; +import org.jetbrains.annotations.NotNull; + +/** + * @author Vladislav.Soroka + * @since 11/27/2015 + */ +public class ExternalSystemTaskExecutionEvent extends ExternalSystemTaskNotificationEvent { + + private static final long serialVersionUID = 1L; + @NotNull private final ExternalSystemProgressEvent myProgressEvent; + + public ExternalSystemTaskExecutionEvent(@NotNull ExternalSystemTaskId id, @NotNull ExternalSystemProgressEvent progressEvent) { + super(id, progressEvent.getDescription()); + myProgressEvent = progressEvent; + } + + @NotNull + public ExternalSystemProgressEvent getProgressEvent() { + return myProgressEvent; + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/FailureResult.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/FailureResult.java new file mode 100644 index 000000000000..826696a244e0 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/FailureResult.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +/** + * @author Vladislav.Soroka + * @since 12/1/2015 + */ +public interface FailureResult extends OperationResult { +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/FailureResultImpl.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/FailureResultImpl.java new file mode 100644 index 000000000000..4d90fcbf4bff --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/FailureResultImpl.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +/** + * @author Vladislav.Soroka + * @since 12/2/2015 + */ +public class FailureResultImpl extends DefaultOperationResult implements FailureResult{ + public FailureResultImpl(long startTime, long endTime) { + super(startTime, endTime); + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/OperationResult.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/OperationResult.java new file mode 100644 index 000000000000..9cf5d94a32ee --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/OperationResult.java @@ -0,0 +1,27 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +import java.io.Serializable; + +/** + * @author Vladislav.Soroka + * @since 12/1/2015 + */ +public interface OperationResult extends Serializable { + long getStartTime(); + long getEndTime(); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/SkippedResult.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/SkippedResult.java new file mode 100644 index 000000000000..e1547a2b002f --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/SkippedResult.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +/** + * @author Vladislav.Soroka + * @since 12/1/2015 + */ +public interface SkippedResult extends OperationResult { +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/SkippedResultImpl.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/SkippedResultImpl.java new file mode 100644 index 000000000000..a21ababa320a --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/SkippedResultImpl.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +/** + * @author Vladislav.Soroka + * @since 12/2/2015 + */ +public class SkippedResultImpl extends DefaultOperationResult implements SkippedResult { + public SkippedResultImpl(long startTime, long endTime) { + super(startTime, endTime); + } +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/SuccessResult.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/SuccessResult.java new file mode 100644 index 000000000000..1a0d2a14e194 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/SuccessResult.java @@ -0,0 +1,24 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +/** + * @author Vladislav.Soroka + * @since 12/1/2015 + */ +public interface SuccessResult extends OperationResult { + boolean isUpToDate(); +} diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/SuccessResultImpl.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/SuccessResultImpl.java new file mode 100644 index 000000000000..fd6704fd2492 --- /dev/null +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/task/event/SuccessResultImpl.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2015 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.model.task.event; + +/** + * @author Vladislav.Soroka + * @since 12/2/2015 + */ +public class SuccessResultImpl extends DefaultOperationResult implements SuccessResult { + + private final boolean myUpToDate; + + public SuccessResultImpl(long startTime, long endTime, boolean isUpToDate) { + super(startTime, endTime); + myUpToDate = isUpToDate; + } + + @Override + public boolean isUpToDate() { + return myUpToDate; + } +} \ No newline at end of file diff --git a/plugins/gradle/resources/i18n/GradleBundle.properties b/plugins/gradle/resources/i18n/GradleBundle.properties index dc149f88a0b1..ac3ed8153a32 100644 --- a/plugins/gradle/resources/i18n/GradleBundle.properties +++ b/plugins/gradle/resources/i18n/GradleBundle.properties @@ -37,6 +37,7 @@ gradle.codeInsight.action.add_maven_dependency.text=Add maven artifact dependenc gradle.codeInsight.action.add_maven_dependency.description=Add selected maven artifact dependency to the project gradle.runner=Runner +gradle.runner.toggle.tree.text.action.name=Toggle tasks executions/text mode gradle.preferred_test_runner.ask=Let me choose per test gradle.preferred_test_runner.PLATFORM_TEST_RUNNER=Platform Test Runner gradle.preferred_test_runner.GRADLE_TEST_RUNNER=Gradle Test Runner diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index 121810970cf6..c9726666c5d6 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -91,6 +91,7 @@ order="last"/> + diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/ExecutionInfo.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/ExecutionInfo.java new file mode 100644 index 000000000000..77f05ff2d4bb --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/ExecutionInfo.java @@ -0,0 +1,100 @@ +/* + * Copyright 2000-2015 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 org.jetbrains.plugins.gradle.execution; + +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.Nullable; + +/** + * @author Vladislav.Soroka + * @since 12/1/2015 + */ +public class ExecutionInfo { + private final @Nullable String id; + private String myDisplayName; + private long startTime; + private long endTime; + private boolean isFailed; + private boolean isSkipped; + private boolean isUpToDate; + + public ExecutionInfo(@Nullable String id, String displayName) { + this.id = id; + this.myDisplayName = displayName; + } + + @Nullable + public String getId() { + return id; + } + + public String getDisplayName() { + return myDisplayName; + } + + public void setDisplayName(String displayName) { + this.myDisplayName = displayName; + } + + public long getStartTime() { + return startTime; + } + + public void setStartTime(long startTime) { + this.startTime = startTime; + } + + public long getEndTime() { + return endTime; + } + + public void setEndTime(long endTime) { + this.endTime = endTime; + } + + public boolean isFailed() { + return isFailed; + } + + public void setFailed(boolean failed) { + isFailed = failed; + } + + public boolean isSkipped() { + return isSkipped; + } + + public void setSkipped(boolean skipped) { + isSkipped = skipped; + } + + public boolean isUpToDate() { + return isUpToDate; + } + + public void setUpToDate(boolean upToDate) { + isUpToDate = upToDate; + } + + public boolean isRunning() { + return endTime <= 0; + } + + @Override + public String toString() { + return myDisplayName; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/ExecutionNode.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/ExecutionNode.java new file mode 100644 index 000000000000..494e3a5bdb60 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/ExecutionNode.java @@ -0,0 +1,122 @@ +/* + * Copyright 2000-2015 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 org.jetbrains.plugins.gradle.execution; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.SimpleTextAttributes; +import com.intellij.ui.treeStructure.CachingSimpleNode; +import com.intellij.ui.treeStructure.SimpleTree; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 12/1/2015 + */ +public class ExecutionNode extends CachingSimpleNode { + + @NotNull + private ExecutionInfo myInfo; + private final List myNodes = ContainerUtil.newArrayList(); + + protected ExecutionNode(Project project) { + super(project, null); + this.myInfo = new ExecutionInfo(null, "--"); + } + + public void add(ExecutionNode node) { + myNodes.add(node); + cleanUpCache(); + } + + @NotNull + public ExecutionInfo getInfo() { + return myInfo; + } + + public void setInfo(@NotNull ExecutionInfo info) { + myInfo = info; + } + + @Override + public String getName() { + return myInfo.getDisplayName(); + } + + public String getDuration() { + if (myInfo.isRunning()) { + final long duration = myInfo.getStartTime() == 0 ? 0 : System.currentTimeMillis() - myInfo.getStartTime(); + return "Running for " + StringUtil.formatDuration(duration); + } + else { + return StringUtil.formatDuration(myInfo.getEndTime() - myInfo.getStartTime()); + } + } + + @Override + public boolean isAutoExpandNode() { + return true; + } + + @Override + protected ExecutionNode[] buildChildren() { + return ContainerUtil.toArray(myNodes, new ExecutionNode[myNodes.size()]); + } + + @Override + protected void doUpdate() { + setNameAndTooltip(getName(), null, myInfo.isUpToDate() ? "UP-TO-DATE" : null); + setIcon( + myInfo.isRunning() ? NodeProgressAnimator.getCurrentFrame() : + myInfo.isFailed() ? AllIcons.RunConfigurations.TestError : + myInfo.isSkipped() ? AllIcons.RunConfigurations.TestError : + AllIcons.RunConfigurations.TestPassed + ); + } + + @Override + public void handleSelection(SimpleTree tree) { + super.handleSelection(tree); + } + + protected void setNameAndTooltip(String name, @Nullable String tooltip) { + setNameAndTooltip(name, tooltip, (String)null); + } + + protected void setNameAndTooltip(String name, @Nullable String tooltip, @Nullable String hint) { + final SimpleTextAttributes textAttributes = getPlainAttributes(); + setNameAndTooltip(name, tooltip, textAttributes); + if (!StringUtil.isEmptyOrSpaces(hint)) { + addColoredFragment(" " + hint, SimpleTextAttributes.GRAY_ATTRIBUTES); + } + } + + protected void setNameAndTooltip(String name, @Nullable String tooltip, SimpleTextAttributes attributes) { + clearColoredText(); + addColoredFragment(name, prepareAttributes(attributes)); + final String s = (tooltip != null ? tooltip + "\n\r" : ""); + getTemplatePresentation().setTooltip(s); + } + + private static SimpleTextAttributes prepareAttributes(SimpleTextAttributes from) { + return new SimpleTextAttributes(from.getBgColor(), from.getFgColor(), null, from.getStyle()); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleExecutionConsoleManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleExecutionConsoleManager.java new file mode 100644 index 000000000000..eaadb450a110 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleExecutionConsoleManager.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2015 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 org.jetbrains.plugins.gradle.execution; + +import com.intellij.execution.ExecutionException; +import com.intellij.execution.Executor; +import com.intellij.execution.filters.TextConsoleBuilderFactory; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.ui.ConsoleView; +import com.intellij.execution.ui.ExecutionConsole; +import com.intellij.openapi.externalSystem.model.ProjectSystemId; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTask; +import com.intellij.openapi.externalSystem.service.execution.DefaultExternalSystemExecutionConsoleManager; +import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.util.GradleConstants; + +import static org.jetbrains.plugins.gradle.execution.GradleRunnerUtil.attachTaskExecutionView; + +/** + * @author Vladislav.Soroka + * @since 11/27/2015 + */ +public class GradleExecutionConsoleManager extends DefaultExternalSystemExecutionConsoleManager { + + @NotNull + @Override + public ProjectSystemId getExternalSystemId() { + return GradleConstants.SYSTEM_ID; + } + + @NotNull + @Override + public ExecutionConsole attachExecutionConsole(@NotNull ExternalSystemTask task, + @NotNull Project project, + @NotNull ExternalSystemRunConfiguration configuration, + @NotNull Executor executor, + @NotNull ExecutionEnvironment env, + @NotNull ProcessHandler processHandler) throws ExecutionException { + final ConsoleView textConsole = TextConsoleBuilderFactory.getInstance().createBuilder(project).getConsole(); + textConsole.attachToProcess(processHandler); + return attachTaskExecutionView(project, textConsole, true, "gradle.runner.text.console", processHandler, task.getId()); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleRunnerUtil.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleRunnerUtil.java new file mode 100644 index 000000000000..5801bf504519 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleRunnerUtil.java @@ -0,0 +1,122 @@ +/* + * Copyright 2000-2015 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 org.jetbrains.plugins.gradle.execution; + +import com.intellij.execution.console.DuplexConsoleView; +import com.intellij.execution.process.ProcessAdapter; +import com.intellij.execution.process.ProcessEvent; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.ui.ConsoleView; +import com.intellij.icons.AllIcons; +import com.intellij.ide.util.PropertiesComponent; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationEvent; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListenerAdapter; +import com.intellij.openapi.externalSystem.model.task.event.ExternalSystemTaskExecutionEvent; +import com.intellij.openapi.externalSystem.service.notification.ExternalSystemProgressNotificationManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.util.GradleBundle; + +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 12/4/2015 + */ +public class GradleRunnerUtil { + + public static DuplexConsoleView attachTaskExecutionView(@NotNull final Project project, + @NotNull final ConsoleView consoleView, + final boolean isTaskConsoleEnabledByDefault, + @Nullable final String stateStorageKey, + @NotNull final ProcessHandler processHandler, + @NotNull final ExternalSystemTaskId taskId) { + if (stateStorageKey != null && isTaskConsoleEnabledByDefault && !PropertiesComponent.getInstance().isValueSet(stateStorageKey)) { + PropertiesComponent.getInstance().setValue(stateStorageKey, true); + } + ; + + final TaskExecutionView gradleExecutionConsole = new TaskExecutionView(project); + final Ref duplexConsoleViewRef = Ref.create(); + final DuplexConsoleView duplexConsoleView = + new DuplexConsoleView(gradleExecutionConsole, consoleView, stateStorageKey) { + @NotNull + @Override + public AnAction[] createConsoleActions() { + + final DefaultActionGroup textActionGroup = new DefaultActionGroup() { + @Override + public void update(AnActionEvent e) { + super.update(e); + if (duplexConsoleViewRef.get() != null) { + e.getPresentation().setVisible(!duplexConsoleViewRef.get().isPrimaryConsoleEnabled()); + } + } + }; + final AnAction[] consoleActions = consoleView.createConsoleActions(); + for (AnAction anAction : consoleActions) { + textActionGroup.add(anAction); + } + + final List anActions = ContainerUtil.newArrayList(super.createConsoleActions()); + anActions.add(textActionGroup); + return ArrayUtil.toObjectArray(anActions, AnAction.class); + } + }; + + duplexConsoleViewRef.set(duplexConsoleView); + + duplexConsoleView.setDisableSwitchConsoleActionOnProcessEnd(false); + duplexConsoleView.getSwitchConsoleActionPresentation().setIcon(AllIcons.Debugger.Console); + duplexConsoleView.getSwitchConsoleActionPresentation().setText(GradleBundle.message("gradle.runner.toggle.tree.text.action.name")); + + final ExternalSystemProgressNotificationManager progressManager = + ServiceManager.getService(ExternalSystemProgressNotificationManager.class); + final ExternalSystemTaskNotificationListenerAdapter taskListener = new ExternalSystemTaskNotificationListenerAdapter() { + @Override + public void onStatusChange(@NotNull final ExternalSystemTaskNotificationEvent event) { + if (event instanceof ExternalSystemTaskExecutionEvent) { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + gradleExecutionConsole.onStatusChange((ExternalSystemTaskExecutionEvent)event); + } + }); + } + } + }; + progressManager.addNotificationListener(taskId, taskListener); + + processHandler.addProcessListener(new ProcessAdapter() { + @Override + public void processTerminated(ProcessEvent event) { + progressManager.removeNotificationListener(taskListener); + } + }); + + return duplexConsoleView; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/NodeProgressAnimator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/NodeProgressAnimator.java new file mode 100644 index 000000000000..b3868675eff1 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/NodeProgressAnimator.java @@ -0,0 +1,152 @@ +/* + * Copyright 2000-2015 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 org.jetbrains.plugins.gradle.execution; + +import com.intellij.icons.AllIcons; +import com.intellij.ide.util.treeView.AbstractTreeBuilder; +import com.intellij.ide.util.treeView.AbstractTreeUi; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.util.Disposer; +import com.intellij.ui.treeStructure.SimpleNode; +import com.intellij.util.Alarm; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; + +/** + * @author Vladislav.Soroka + * @since 11/27/2015 + */ +public class NodeProgressAnimator implements Runnable, Disposable { + private static final int FRAMES_COUNT = 8; + private static final int MOVIE_TIME = 800; + private static final int FRAME_TIME = MOVIE_TIME / FRAMES_COUNT; + + public static final Icon[] FRAMES = new Icon[FRAMES_COUNT]; + + private long myLastInvocationTime = -1; + + private Alarm myAlarm; + private SimpleNode myCurrentNode; + private AbstractTreeBuilder myTreeBuilder; + + public NodeProgressAnimator(AbstractTreeBuilder builder) { + Disposer.register(builder, this); + init(builder); + } + + static { + FRAMES[0] = AllIcons.RunConfigurations.TestInProgress1; + FRAMES[1] = AllIcons.RunConfigurations.TestInProgress2; + FRAMES[2] = AllIcons.RunConfigurations.TestInProgress3; + FRAMES[3] = AllIcons.RunConfigurations.TestInProgress4; + FRAMES[4] = AllIcons.RunConfigurations.TestInProgress5; + FRAMES[5] = AllIcons.RunConfigurations.TestInProgress6; + FRAMES[6] = AllIcons.RunConfigurations.TestInProgress7; + FRAMES[7] = AllIcons.RunConfigurations.TestInProgress8; + } + + public static int getCurrentFrameIndex() { + return (int) ((System.currentTimeMillis() % MOVIE_TIME) / FRAME_TIME); + } + + public static Icon getCurrentFrame() { + return FRAMES[getCurrentFrameIndex()]; + } + + /** + * Initializes animator: creates alarm and sets tree builder + * @param treeBuilder tree builder + */ + protected void init(final AbstractTreeBuilder treeBuilder) { + myAlarm = new Alarm(); + myTreeBuilder = treeBuilder; + } + + public SimpleNode getCurrentNode() { + return myCurrentNode; + } + + public void run() { + if (myCurrentNode != null) { + final long time = System.currentTimeMillis(); + // optimization: + // we shouldn't repaint if this frame was painted in current interval + if (time - myLastInvocationTime >= FRAME_TIME) { + repaintSubTree(); + myLastInvocationTime = time; + } + } + scheduleRepaint(); + } + + public void setCurrentNode(@Nullable final SimpleNode node) { + myCurrentNode = node; + scheduleRepaint(); + } + + public void stopMovie() { + repaintSubTree(); + setCurrentNode(null); + cancelAlarm(); + } + + + public void dispose() { + myTreeBuilder = null; + myCurrentNode = null; + cancelAlarm(); + } + + private void cancelAlarm() { + if (myAlarm != null) { + myAlarm.cancelAllRequests(); + myAlarm = null; + } + } + + private void repaintSubTree() { + if (myTreeBuilder != null && myCurrentNode != null) { + repaintWithParents(myCurrentNode); + } + } + + public void repaintWithParents(final SimpleNode element) { + SimpleNode current = element; + do { + DefaultMutableTreeNode node = myTreeBuilder.getNodeForElement(current); + if (node != null) { + final AbstractTreeUi treeUi = myTreeBuilder.getUi(); + treeUi.addSubtreeToUpdate(node, false); + } + current = current.getParent(); + } + while (current != null); + } + + + private void scheduleRepaint() { + if (myAlarm == null) { + return; + } + myAlarm.cancelAllRequests(); + if (myCurrentNode != null) { + myAlarm.addRequest(this, FRAME_TIME); + } + } + +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/TaskExecutionView.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/TaskExecutionView.java new file mode 100644 index 000000000000..3bf5a33411c0 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/TaskExecutionView.java @@ -0,0 +1,309 @@ +/* + * Copyright 2000-2015 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 org.jetbrains.plugins.gradle.execution; + +import com.intellij.execution.filters.Filter; +import com.intellij.execution.filters.HyperlinkInfo; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.ui.ConsoleView; +import com.intellij.execution.ui.ConsoleViewContentType; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.externalSystem.model.task.event.*; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.ui.*; +import com.intellij.ui.speedSearch.SpeedSearchUtil; +import com.intellij.ui.treeStructure.SimpleTreeBuilder; +import com.intellij.ui.treeStructure.SimpleTreeStructure; +import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns; +import com.intellij.ui.treeStructure.treetable.TreeColumnInfo; +import com.intellij.ui.treeStructure.treetable.TreeTable; +import com.intellij.ui.treeStructure.treetable.TreeTableTree; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.ColumnInfo; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeCellRenderer; +import java.awt.*; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 12/1/2015 + */ +public class TaskExecutionView implements ConsoleView { + + private static final int TIME_COLUMN_WIDTH = 140; + private final Project myProject; + private final Map nodeMap = ContainerUtil.newHashMap(); + private final JScrollPane myPane; + private final TreeTable myTreeTable; + private final SimpleTreeBuilder myBuilder; + private final NodeProgressAnimator myProgressAnimator; + private final ExecutionNode myRoot; + + public TaskExecutionView(Project project) { + myProject = project; + final ColumnInfo[] COLUMNS = new ColumnInfo[]{ + new TreeColumnInfo("name"), + new ColumnInfo("time elapsed") { + @Nullable + @Override + public Object valueOf(Object o) { + if (o instanceof DefaultMutableTreeNode) { + final Object userObject = ((DefaultMutableTreeNode)o).getUserObject(); + if (userObject instanceof ExecutionNode) { + return ((ExecutionNode)userObject).getDuration(); + } + } + return null; + } + } + , + new ColumnInfo("") { + @Nullable + @Override + public Object valueOf(Object o) { + return ""; + } + } + }; + myRoot = new ExecutionNode(project); + myRoot.setInfo(new ExecutionInfo(null, "Run build")); + final ListTreeTableModelOnColumns model = new ListTreeTableModelOnColumns(new DefaultMutableTreeNode(myRoot), COLUMNS); + + myTreeTable = new TreeTable(model) { + @Override + public TableCellRenderer getCellRenderer(int row, int column) { + if (column == 1) { + return new DefaultTableCellRenderer() { + @Override + public Component getTableCellRendererComponent(JTable table, + Object value, + boolean isSelected, + boolean hasFocus, + int row, + int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + setHorizontalAlignment(SwingConstants.RIGHT); + return this; + } + }; + } + return super.getCellRenderer(row, column); + } + }; + + final TreeCellRenderer treeCellRenderer = myTreeTable.getTree().getCellRenderer(); + + myTreeTable.getTree().setCellRenderer(new TreeCellRenderer() { + @Override + public Component getTreeCellRendererComponent(JTree tree, + Object value, + boolean selected, + boolean expanded, + boolean leaf, + int row, + boolean hasFocus) { + final Component rendererComponent = + treeCellRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); + if (rendererComponent instanceof SimpleColoredComponent) { + final Color bg = selected ? UIUtil.getTreeSelectionBackground() : UIUtil.getTreeTextBackground(); + final Color fg = selected ? UIUtil.getTreeSelectionForeground() : UIUtil.getTreeForeground(); + if (selected) { + for (SimpleColoredComponent.ColoredIterator it = ((SimpleColoredComponent)rendererComponent).iterator(); it.hasNext(); ) { + it.next(); + int offset = it.getOffset(); + int endOffset = it.getEndOffset(); + SimpleTextAttributes currentAttributes = it.getTextAttributes(); + SimpleTextAttributes newAttributes = + new SimpleTextAttributes(bg, fg, currentAttributes.getWaveColor(), currentAttributes.getStyle()); + it.split(endOffset - offset, newAttributes); + } + } + + SpeedSearchUtil.applySpeedSearchHighlighting(myTreeTable, (SimpleColoredComponent)rendererComponent, true, selected); + } + return rendererComponent; + } + }); + + new TreeTableSpeedSearch(myTreeTable).setComparator(new SpeedSearchComparator(false)); + myTreeTable.setTableHeader(null); + + final TableColumn treeColumn = myTreeTable.getColumnModel().getColumn(0); + treeColumn.setMinWidth(300); + final TableColumn timeColumn = myTreeTable.getColumnModel().getColumn(1); + timeColumn.setMaxWidth(TIME_COLUMN_WIDTH); + timeColumn.setMinWidth(TIME_COLUMN_WIDTH); + + TreeTableTree tree = myTreeTable.getTree(); + final SimpleTreeStructure treeStructure = new SimpleTreeStructure.Impl(myRoot); + + myBuilder = new SimpleTreeBuilder(tree, model, treeStructure, null); + Disposer.register(this, myBuilder); + myBuilder.expand(treeStructure.getRootElement(), null); + + myBuilder.initRoot(); + myBuilder.expand(myRoot, null); + myProgressAnimator = new NodeProgressAnimator(myBuilder); + myProgressAnimator.setCurrentNode(myRoot); + myBuilder.queueUpdateFrom(myRoot, false, true); + + myPane = ScrollPaneFactory.createScrollPane(myTreeTable, + ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, + ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + } + + public void onStatusChange(ExternalSystemTaskExecutionEvent event) { + final ExternalSystemProgressEvent progressEvent = event.getProgressEvent(); + final String parentEventId = progressEvent.getParentEventId(); + if (progressEvent instanceof ExternalSystemStartEvent) { + final ExecutionInfo executionInfo = new ExecutionInfo(progressEvent.getEventId(), progressEvent.getDescription()); + executionInfo.setStartTime(progressEvent.getEventTime()); + final ExecutionNode currentNode = parentEventId == null ? myRoot : new ExecutionNode(myProject); + if (parentEventId != null) { + final ExecutionNode parentNode = nodeMap.get(parentEventId); + if (parentNode != null) { + parentNode.add(currentNode); + } + } + currentNode.setInfo(executionInfo); + nodeMap.put(progressEvent.getEventId(), currentNode); + + myProgressAnimator.setCurrentNode(currentNode); + myBuilder.queueUpdateFrom(currentNode, false, true); + } + else if (progressEvent instanceof ExternalSystemFinishEvent) { + final ExecutionInfo executionInfo; + final ExecutionNode node = nodeMap.get(progressEvent.getEventId()); + executionInfo = node.getInfo(); + executionInfo.setDisplayName(progressEvent.getDescription()); + executionInfo.setEndTime(progressEvent.getEventTime()); + final OperationResult operationResult = ((ExternalSystemFinishEvent)progressEvent).getOperationResult(); + if (operationResult instanceof FailureResult) { + executionInfo.setFailed(true); + } + else if (operationResult instanceof SkippedResult) { + executionInfo.setSkipped(true); + } + else if (operationResult instanceof SuccessResult) { + executionInfo.setUpToDate(((SuccessResult)operationResult).isUpToDate()); + } + if (parentEventId == null) { + myProgressAnimator.stopMovie(); + } + + myBuilder.queueUpdateFrom(node, false, false); + } + } + + @Override + public void print(@NotNull String s, @NotNull ConsoleViewContentType contentType) { + } + + @Override + public void clear() { + + } + + @Override + public void scrollTo(int offset) { + + } + + @Override + public void attachToProcess(ProcessHandler processHandler) { + + } + + @Override + public void setOutputPaused(boolean value) { + + } + + @Override + public boolean isOutputPaused() { + return false; + } + + @Override + public boolean hasDeferredOutput() { + return false; + } + + @Override + public void performWhenNoDeferredOutput(Runnable runnable) { + + } + + @Override + public void setHelpId(String helpId) { + + } + + @Override + public void addMessageFilter(Filter filter) { + + } + + @Override + public void printHyperlink(String hyperlinkText, HyperlinkInfo info) { + + } + + @Override + public int getContentSize() { + return 0; + } + + @Override + public boolean canPause() { + return false; + } + + @NotNull + @Override + public AnAction[] createConsoleActions() { + return new AnAction[0]; + } + + @Override + public void allowHeavyFilters() { + + } + + @Override + public JComponent getComponent() { + return myPane; + } + + @Override + public JComponent getPreferredFocusableComponent() { + return myTreeTable; + } + + @Override + public void dispose() { + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/GradleTestsExecutionConsole.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/GradleTestsExecutionConsole.java index 04b734f2f6f8..29ae04e74bcb 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/GradleTestsExecutionConsole.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/GradleTestsExecutionConsole.java @@ -15,35 +15,45 @@ */ package org.jetbrains.plugins.gradle.execution.test.runner; -import com.intellij.execution.filters.Filter; -import com.intellij.execution.filters.HyperlinkInfo; +import com.intellij.execution.console.DuplexConsoleView; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.testframework.TestConsoleProperties; import com.intellij.execution.testframework.sm.runner.SMTestLocator; import com.intellij.execution.testframework.sm.runner.SMTestProxy; import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView; -import com.intellij.execution.testframework.sm.runner.ui.SMTestRunnerResultsForm; import com.intellij.execution.ui.ConsoleView; -import com.intellij.execution.ui.ConsoleViewContentType; -import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import javax.swing.*; import java.util.Map; +import static org.jetbrains.plugins.gradle.execution.GradleRunnerUtil.attachTaskExecutionView; + /** * @author Vladislav.Soroka * @since 10/28/2015 */ -public class GradleTestsExecutionConsole implements ConsoleView { +public class GradleTestsExecutionConsole extends SMTRunnerConsoleView { private Map testsMap = ContainerUtil.newHashMap(); private StringBuilder myBuffer = new StringBuilder(); - private SMTRunnerConsoleView myExecutionConsole; + private DuplexConsoleView myConsoleView; - public GradleTestsExecutionConsole(SMTRunnerConsoleView executionConsole) { - myExecutionConsole = executionConsole; + public GradleTestsExecutionConsole(TestConsoleProperties consoleProperties, @Nullable String splitterProperty) { + super(consoleProperties, splitterProperty); + } + + public void initTaskExecutionView(Project project, ProcessHandler processHandler, ExternalSystemTaskId taskId) { + myConsoleView = attachTaskExecutionView(project, super.getConsole(), false, "gradle.test.runner.text.console", processHandler, taskId); + } + + @NotNull + @Override + public ConsoleView getConsole() { + return myConsoleView != null ? myConsoleView : super.getConsole(); } public Map getTestsMap() { @@ -54,103 +64,10 @@ public class GradleTestsExecutionConsole implements ConsoleView { return myBuffer; } - @Override - public void print(@NotNull String s, @NotNull ConsoleViewContentType contentType) { - myExecutionConsole.print(s, contentType); - } - - @Override - public void clear() { - myExecutionConsole.clear(); - } - - @Override - public void scrollTo(int offset) { - myExecutionConsole.scrollTo(offset); - } - - @Override - public void attachToProcess(ProcessHandler processHandler) { - myExecutionConsole.attachToProcess(processHandler); - } - - @Override - public void setOutputPaused(boolean value) { - myExecutionConsole.setOutputPaused(value); - } - - @Override - public boolean isOutputPaused() { - return myExecutionConsole.isOutputPaused(); - } - - @Override - public boolean hasDeferredOutput() { - return myExecutionConsole.hasDeferredOutput(); - } - - @Override - public void performWhenNoDeferredOutput(Runnable runnable) { - myExecutionConsole.performWhenNoDeferredOutput(runnable); - } - - @Override - public void setHelpId(String helpId) { - myExecutionConsole.setHelpId(helpId); - } - - @Override - public void addMessageFilter(Filter filter) { - myExecutionConsole.addMessageFilter(filter); - } - - @Override - public void printHyperlink(String hyperlinkText, HyperlinkInfo info) { - myExecutionConsole.printHyperlink(hyperlinkText, info); - } - - @Override - public int getContentSize() { - return myExecutionConsole.getContentSize(); - } - - @Override - public boolean canPause() { - return myExecutionConsole.canPause(); - } - - @NotNull - @Override - public AnAction[] createConsoleActions() { - return myExecutionConsole.createConsoleActions(); - } - - @Override - public void allowHeavyFilters() { - myExecutionConsole.allowHeavyFilters(); - } - - @Override - public JComponent getComponent() { - return myExecutionConsole.getComponent(); - } - - @Override - public JComponent getPreferredFocusableComponent() { - return myExecutionConsole.getPreferredFocusableComponent(); - } - @Override public void dispose() { - Disposer.dispose(myExecutionConsole); - } - - public SMTestRunnerResultsForm getResultsViewer() { - return myExecutionConsole.getResultsViewer(); - } - - public TestConsoleProperties getProperties() { - return myExecutionConsole.getProperties(); + super.dispose(); + Disposer.dispose(myConsoleView); } public SMTestLocator getUrlProvider() { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/GradleTestsExecutionConsoleManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/GradleTestsExecutionConsoleManager.java index 2c9149f87974..b18a193e462a 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/GradleTestsExecutionConsoleManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/test/runner/GradleTestsExecutionConsoleManager.java @@ -26,6 +26,7 @@ import com.intellij.execution.testframework.sm.runner.states.TestStateInfo; import com.intellij.execution.testframework.sm.runner.ui.SMRootTestProxyFormatter; import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView; import com.intellij.execution.testframework.sm.runner.ui.TestTreeRenderer; +import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.diagnostic.Logger; @@ -76,10 +77,15 @@ public class GradleTestsExecutionConsoleManager @NotNull final Executor executor, @NotNull final ExecutionEnvironment env, @NotNull final ProcessHandler processHandler) throws ExecutionException { - final GradleConsoleProperties properties = new GradleConsoleProperties(configuration, executor); - final SMTRunnerConsoleView executionConsole = (SMTRunnerConsoleView)SMTestRunnerConnectionUtil.createAndAttachConsole( - configuration.getSettings().getExternalSystemId().getReadableName(), processHandler, properties); - final TestTreeView testTreeView = executionConsole.getResultsViewer().getTreeView(); + final GradleConsoleProperties consoleProperties = new GradleConsoleProperties(configuration, executor); + String testFrameworkName = configuration.getSettings().getExternalSystemId().getReadableName(); + String splitterPropertyName = SMTestRunnerConnectionUtil.getSplitterPropertyName(testFrameworkName); + final GradleTestsExecutionConsole consoleView = new GradleTestsExecutionConsole(consoleProperties, splitterPropertyName); + consoleView.initTaskExecutionView(project, processHandler, task.getId()); + SMTestRunnerConnectionUtil.initConsoleView(consoleView, testFrameworkName); + consoleView.attachToProcess(processHandler); + + final TestTreeView testTreeView = consoleView.getResultsViewer().getTreeView(); if (testTreeView != null) { TestTreeRenderer originalRenderer = ObjectUtils.tryCast(testTreeView.getCellRenderer(), TestTreeRenderer.class); if (originalRenderer != null) { @@ -113,7 +119,7 @@ public class GradleTestsExecutionConsoleManager } } - return new GradleTestsExecutionConsole(executionConsole); + return consoleView; } @Override diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleExecutionHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleExecutionHelper.java index d38268e43485..3dd1b60a12f5 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleExecutionHelper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleExecutionHelper.java @@ -24,6 +24,7 @@ import com.intellij.openapi.externalSystem.model.ExternalSystemException; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationEvent; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener; +import com.intellij.openapi.externalSystem.model.task.event.*; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.text.StringUtil; @@ -34,9 +35,17 @@ import org.gradle.initialization.BuildLayoutParameters; import org.gradle.internal.nativeintegration.services.NativeServices; import org.gradle.process.internal.JvmOptions; import org.gradle.tooling.*; +import org.gradle.tooling.events.FailureResult; +import org.gradle.tooling.events.FinishEvent; +import org.gradle.tooling.events.SkippedResult; +import org.gradle.tooling.events.StartEvent; +import org.gradle.tooling.events.internal.DefaultOperationDescriptor; +import org.gradle.tooling.events.task.TaskProgressEvent; +import org.gradle.tooling.events.task.TaskSuccessResult; import org.gradle.tooling.internal.consumer.DefaultExecutorServiceFactory; import org.gradle.tooling.internal.consumer.DefaultGradleConnector; import org.gradle.tooling.internal.consumer.Distribution; +import org.gradle.tooling.internal.protocol.events.InternalOperationDescriptor; import org.gradle.tooling.model.build.BuildEnvironment; import org.gradle.util.GradleVersion; import org.jetbrains.annotations.NotNull; @@ -154,12 +163,12 @@ public class GradleExecutionHelper { operation.setJvmArguments(ArrayUtil.toStringArray(filteredArgs)); } - if(settings.isOfflineWork()) { + if (settings.isOfflineWork()) { commandLineArgs.add(GradleConstants.OFFLINE_MODE_CMD_OPTION); } final Application application = ApplicationManager.getApplication(); - if(application != null && application.isUnitTestMode()) { + if (application != null && application.isUnitTestMode()) { commandLineArgs.add("--info"); commandLineArgs.add("--recompile-scripts"); } @@ -193,13 +202,59 @@ public class GradleExecutionHelper { operation.addProgressListener(new org.gradle.tooling.events.ProgressListener() { @Override public void statusChanged(org.gradle.tooling.events.ProgressEvent event) { - listener.onStatusChange(new ExternalSystemTaskNotificationEvent(id, event.getDisplayName())); + listener.onStatusChange(convert(id, event)); } }); operation.setStandardOutput(standardOutput); operation.setStandardError(standardError); } + @NotNull + private static ExternalSystemTaskNotificationEvent convert(ExternalSystemTaskId id, org.gradle.tooling.events.ProgressEvent event) { + final InternalOperationDescriptor internalDesc = + event.getDescriptor() instanceof DefaultOperationDescriptor ? ((DefaultOperationDescriptor)event.getDescriptor()) + .getInternalOperationDescriptor() : null; + final String eventId = internalDesc == null ? event.getDescriptor().getDisplayName() : internalDesc.getId().toString(); + final String parentEventId; + if (event.getDescriptor().getParent() == null) { + parentEventId = null; + } + else { + parentEventId = internalDesc == null ? event.getDescriptor().getParent().getDisplayName() : internalDesc.getParentId().toString(); + } + final String description = event.getDescriptor().getName(); + + if (event instanceof StartEvent) { + return new ExternalSystemTaskExecutionEvent( + id, new ExternalSystemStartEventImpl(eventId, parentEventId, description, event.getEventTime())); + } + else if (event instanceof FinishEvent) { + return new ExternalSystemTaskExecutionEvent( + id, new ExternalSystemFinishEventImpl(eventId, parentEventId, description, convert(((FinishEvent)event).getResult()))); + } + else if (event instanceof TaskProgressEvent) { + return new ExternalSystemTaskExecutionEvent( + id, new BaseExternalSystemProgressEvent(eventId, parentEventId, description, event.getEventTime())); + } + else { + return new ExternalSystemTaskNotificationEvent(id, description); + } + } + + @NotNull + private static OperationResult convert(org.gradle.tooling.events.OperationResult operationResult) { + if (operationResult instanceof FailureResult) { + return new FailureResultImpl(operationResult.getStartTime(), operationResult.getEndTime()); + } + else if (operationResult instanceof SkippedResult) { + return new SkippedResultImpl(operationResult.getStartTime(), operationResult.getEndTime()); + } + else { + final boolean isUpToDate = operationResult instanceof TaskSuccessResult && ((TaskSuccessResult)operationResult).isUpToDate(); + return new SuccessResultImpl(operationResult.getStartTime(), operationResult.getEndTime(), isUpToDate); + } + } + public T execute(@NotNull String projectPath, @Nullable GradleExecutionSettings settings, @NotNull Function f) { final String projectDir; @@ -275,8 +330,9 @@ public class GradleExecutionHelper { }; final File tempFile = writeToFileGradleInitScript(StringUtil.join(lines, SystemProperties.getLineSeparator())); - BuildLauncher launcher = getBuildLauncher(id, connection, settings, listener, ContainerUtil.newArrayList(), - ContainerUtil.newArrayList(GradleConstants.INIT_SCRIPT_CMD_OPTION, tempFile.getAbsolutePath())); + BuildLauncher launcher = getBuildLauncher( + id, connection, settings, listener, ContainerUtil.newArrayList(), + ContainerUtil.newArrayList(GradleConstants.INIT_SCRIPT_CMD_OPTION, tempFile.getAbsolutePath())); launcher.forTasks("wrapper"); launcher.run(); String wrapperPropertyFile = FileUtil.loadFile(wrapperPropertyFileLocation);