diff --git a/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidResourceManager.kt b/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidResourceManager.kt index b54e393e9cd..f3b992233ce 100644 --- a/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidResourceManager.kt +++ b/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidResourceManager.kt @@ -19,9 +19,10 @@ package org.jetbrains.kotlin.lang.resolve.android import com.intellij.psi.PsiFile import com.intellij.psi.PsiElement import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.PsiManager -import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.util.* +import com.intellij.openapi.vfs.impl.* +import com.intellij.openapi.vfs.* public abstract class AndroidResourceManager(val project: Project) { @@ -60,6 +61,11 @@ public abstract class AndroidResourceManager(val project: Project) { .sortBy { it.getName() } } - inner class NoLayoutXmlFound : Exception("No android UI xmls found in " + androidModuleInfo?.mainResDirectory) + fun getMainLayoutDirectory(): VirtualFile? { + val info = androidModuleInfo + if (info == null) return null + return VirtualFileManager.getInstance().findFileByUrl("file://" + info.mainResDirectory) + } } + diff --git a/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidUIXmlProcessor.kt b/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidUIXmlProcessor.kt index f3c1202b2b5..c955484f844 100644 --- a/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidUIXmlProcessor.kt +++ b/plugins/android-compiler-plugin/src/org/jetbrains/kotlin/lang/resolve/android/AndroidUIXmlProcessor.kt @@ -28,13 +28,8 @@ import org.jetbrains.kotlin.psi.JetPsiFactory import org.jetbrains.kotlin.psi.JetFile import javax.xml.parsers.SAXParser import java.util.HashMap -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.openapi.vfs.VirtualFileManager -import com.intellij.openapi.vfs.VirtualFileAdapter -import com.intellij.openapi.vfs.VirtualFileEvent import com.intellij.openapi.project.Project import java.util.concurrent.ConcurrentLinkedQueue -import com.intellij.openapi.util.Key import com.intellij.testFramework.LightVirtualFile import com.intellij.psi.PsiManager import java.io.FileInputStream @@ -53,7 +48,10 @@ import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.CachedValueProvider.Result import java.util.concurrent.atomic.AtomicInteger import com.intellij.openapi.roots.ProjectRootModificationTracker -import com.intellij.openapi.util.ModificationTracker +import com.intellij.openapi.util.* +import com.intellij.openapi.vfs.impl.* +import com.intellij.openapi.vfs.* +import kotlin.properties.* public abstract class AndroidUIXmlProcessor(protected val project: Project) { @@ -64,29 +62,36 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) { "android.view.View", "android.widget.*") - //TODO - private val cachedSources = cachedValue { - Result.create(parse(), ProjectRootModificationTracker.getInstance(project)) - } - - private val cachedJetFiles = cachedValue { - val psiManager = PsiManager.getInstance(project) - val applicationPackage = resourceManager.androidModuleInfo?.applicationPackage - - val jetFiles = cachedSources.getValue().mapIndexed { (index, text) -> - val virtualFile = LightVirtualFile(AndroidConst.SYNTHETIC_FILENAME + index + ".kt", text) - val jetFile = psiManager.findFile(virtualFile) as JetFile - if (applicationPackage != null) { - jetFile.putUserData(AndroidConst.ANDROID_USER_PACKAGE, applicationPackage) - } - jetFile - } - - Result.create(jetFiles, cachedSources) - } - public abstract val resourceManager: AndroidResourceManager + private val vfsTracker: VfsModificationTracker by Delegates.lazy { + VfsModificationTracker(project, resourceManager.getMainLayoutDirectory()) + } + + private val cachedSources: CachedValue> by Delegates.lazy { + cachedValue { + Result.create(parse(), vfsTracker) + } + } + + private val cachedJetFiles: CachedValue> by Delegates.lazy { + cachedValue { + val psiManager = PsiManager.getInstance(project) + val applicationPackage = resourceManager.androidModuleInfo?.applicationPackage + + val jetFiles = cachedSources.getValue().mapIndexed { (index, text) -> + val virtualFile = LightVirtualFile(AndroidConst.SYNTHETIC_FILENAME + index + ".kt", text) + val jetFile = psiManager.findFile(virtualFile) as JetFile + if (applicationPackage != null) { + jetFile.putUserData(AndroidConst.ANDROID_USER_PACKAGE, applicationPackage) + } + jetFile + } + + Result.create(jetFiles, cachedSources) + } + } + protected val LOG: Logger = Logger.getInstance(javaClass) public fun parse(): List { @@ -132,3 +137,57 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) { } } + +private class VfsModificationTracker(project: Project, resDirectory: VirtualFile?): SimpleModificationTracker() { + { + val connection = project.getMessageBus().connect(); + connection.subscribe(VirtualFileManager.VFS_CHANGES, BulkVirtualFileListenerAdapter( + object : VirtualFileListener { + fun incModificationCountIfLayout(file: VirtualFile) { + if (resDirectory == null) { + incModificationCount() + } else { + val probablyLayoutDir = file.getParent() + val probablyResDir = file.getParent()?.getParent() + if (resDirectory == probablyResDir && probablyLayoutDir?.getName()?.startsWith("layout") ?: false) { + incModificationCount() + } + } + } + + override fun contentsChanged(event: VirtualFileEvent) { + incModificationCountIfLayout(event.getFile()) + } + + override fun propertyChanged(event: VirtualFilePropertyEvent) { + incModificationCountIfLayout(event.getFile()) + } + + override fun fileCreated(event: VirtualFileEvent) { + incModificationCountIfLayout(event.getFile()) + } + + override fun fileDeleted(event: VirtualFileEvent) { + incModificationCountIfLayout(event.getFile()) + } + + override fun fileMoved(event: VirtualFileMoveEvent) { + incModificationCountIfLayout(event.getFile()) + } + + override fun fileCopied(event: VirtualFileCopyEvent) { + incModificationCountIfLayout(event.getFile()) + } + + override fun beforePropertyChange(event: VirtualFilePropertyEvent) {} + + override fun beforeContentsChange(event: VirtualFileEvent) {} + + override fun beforeFileDeletion(event: VirtualFileEvent) {} + + override fun beforeFileMovement(event: VirtualFileMoveEvent) {} + } + )) + } +} +