Android: add action to create new activity on Kotlin

#KT-11264 Fixed
This commit is contained in:
Natalia Ukhorskaya
2016-02-24 14:24:21 +03:00
parent b50f2dc6e5
commit 40e89c76a9
4 changed files with 196 additions and 0 deletions
@@ -12,5 +12,6 @@
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="idea-analysis" />
<orderEntry type="module" module-name="idea" />
</component>
</module>
@@ -0,0 +1,157 @@
/*
* Copyright 2010-2016 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.kotlin.android.actions
import com.intellij.history.core.RevisionsCollector
import com.intellij.history.core.revisions.Revision
import com.intellij.history.integration.LocalHistoryImpl
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.module.Module
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiJavaFile
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.kotlin.idea.KotlinIcons
import org.jetbrains.kotlin.idea.actions.JavaToKotlinAction
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
import java.io.File
import kotlin.reflect.functions
import kotlin.reflect.memberFunctions
private val NEW_KOTLIN_ACTIVITY_START_LABEL = "Start New Kotlin Activity Action"
private val NEW_KOTLIN_ACTIVITY_END_LABEL = "Finish New Kotlin Activity Action"
class NewKotlinActivityAction: AnAction(KotlinIcons.FILE) {
companion object {
private val LOG = Logger.getInstance(NewKotlinActivityAction::class.java)
}
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
LocalHistoryImpl.getInstanceImpl().putSystemLabel(project, NEW_KOTLIN_ACTIVITY_START_LABEL)
val isSuccess = showWizard(e.dataContext)
LocalHistoryImpl.getInstanceImpl().putSystemLabel(project, NEW_KOTLIN_ACTIVITY_END_LABEL)
if (!isSuccess) return
val localHistory = LocalHistoryImpl.getInstanceImpl()
val gateway = localHistory.gateway!!
val localHistoryFacade = localHistory.facade
val revisionsCollector = RevisionsCollector(
localHistoryFacade, gateway.createTransientRootEntry(),
project.baseDir.path, project.locationHash, null)
val revisions = revisionsCollector.result
var endRevision: Revision? = null
for (rev in revisions) {
val label = rev.label ?: continue
if (label == NEW_KOTLIN_ACTIVITY_END_LABEL) {
endRevision = rev
}
if (label == NEW_KOTLIN_ACTIVITY_START_LABEL && endRevision != null) {
val javaFiles = arrayListOf<PsiJavaFile>()
val differences = endRevision.getDifferencesWith(rev)
for (difference in differences) {
if (difference.right == null && difference.isFile) {
val file = File(difference.left.path)
if (file.extension == "java") {
val psiFile = file.toPsiFile(project) as? PsiJavaFile
if (psiFile != null) {
javaFiles.add(psiFile)
}
}
}
}
if (javaFiles.isNotEmpty()) {
JavaToKotlinAction.convertFiles(javaFiles, project, false)
}
break
}
}
}
private fun showWizard(dataContext: DataContext): Boolean {
try {
val wizardClass = try {
// AS 1.5
Class.forName("com.android.tools.idea.wizard.NewAndroidActivityWizard")
}
catch(e: ClassNotFoundException) {
// AS 2.0
Class.forName("com.android.tools.idea.npw.NewAndroidActivityWizard")
}
val constructor = wizardClass.getConstructor(Module::class.java, VirtualFile::class.java, File::class.java)
val wizard = constructor.newInstance(
LangDataKeys.MODULE.getData(dataContext),
CommonDataKeys.VIRTUAL_FILE.getData(dataContext),
null)
wizardClass.kotlin.functions.firstOrNull { it.name == "init" }?.call(wizard)
return (wizardClass.kotlin.functions.firstOrNull { it.name == "showAndGet" }?.call(wizard) as? Boolean) ?: false
}
catch(e: Throwable) {
LOG.error(e)
return false
}
}
override fun update(e: AnActionEvent) {
val view = LangDataKeys.IDE_VIEW.getData(e.dataContext)
val module = LangDataKeys.MODULE.getData(e.dataContext)
val facet = if (module != null) AndroidFacet.getInstance(module) else null
val presentation = e.presentation
val isProjectReady = facet != null && isProjectReady(facet)
presentation.text = "Kotlin Activity" + if (isProjectReady) "" else " (Project not ready)"
presentation.isVisible = view != null && facet != null && isVisible(facet)
}
private fun isVisible(facet: AndroidFacet): Boolean {
try {
val shouldSetVisible = AndroidFacet::class.memberFunctions.singleOrNull {
it.name == "isGradleProject" || it.name == "requiresAndroidModel"
}
return shouldSetVisible?.call(facet) != null
}
catch(e: Throwable) {
LOG.error(e)
return false
}
}
private fun isProjectReady(facet: AndroidFacet): Boolean {
try {
val getAndroidProjectInfoFun = AndroidFacet::class.memberFunctions.singleOrNull {
it.name == "getIdeaAndroidProject" || it.name == "getAndroidModel"
}
return getAndroidProjectInfoFun?.call(facet) != null
}
catch(e: Throwable) {
LOG.error(e)
return false
}
}
override fun hashCode() = 0
override fun equals(other: Any?) = other is NewKotlinActivityAction
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2016 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.kotlin.android.facet
import com.intellij.openapi.project.Project
class KotlinAndroidStartupManager(private val project: Project) {
init {
}
}
+13
View File
@@ -24,4 +24,17 @@
<simpleNameReferenceExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidSimpleNameReferenceExtension"/>
<kotlinIndicesHelperExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidIndicesHelperExtension"/>
</extensions>
<project-components>
<component>
<interface-class>org.jetbrains.kotlin.android.facet.KotlinAndroidStartupManager</interface-class>
<implementation-class>org.jetbrains.kotlin.android.facet.KotlinAndroidStartupManager</implementation-class>
</component>
</project-components>
<actions>
<action id="Kotlin.new.activity" class="org.jetbrains.kotlin.android.actions.NewKotlinActivityAction">
<add-to-group group-id="NewGroup" anchor="after" relative-to-action="Kotlin.NewFile"/>
</action>
</actions>
</idea-plugin>