
org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-android-extensions Show documentation
Show all versions of kotlin-android-extensions Show documentation
Kotlin Android Extensions Compiler
/*
* Copyright 2010-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.kotlin.android.synthetic.res
import org.jetbrains.kotlin.com.intellij.openapi.module.Module
import org.jetbrains.kotlin.com.intellij.openapi.module.ModuleServiceManager
import org.jetbrains.kotlin.com.intellij.openapi.project.Project
import org.jetbrains.kotlin.com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.com.intellij.openapi.vfs.VirtualFileManager
import org.jetbrains.kotlin.com.intellij.psi.PsiElement
import org.jetbrains.kotlin.com.intellij.psi.PsiFile
import org.jetbrains.kotlin.com.intellij.psi.PsiManager
import org.jetbrains.kotlin.android.synthetic.AndroidConst
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import java.util.*
class AndroidVariantData(val variant: AndroidVariant, private val layouts: Map>): Map> by layouts
class AndroidModuleData(val module: AndroidModule, private val variants: List): Iterable by variants {
companion object {
val EMPTY = AndroidModuleData(AndroidModule("android", listOf()), listOf())
}
}
abstract class AndroidLayoutXmlFileManager(val project: Project) {
abstract val androidModule: AndroidModule?
open fun propertyToXmlAttributes(propertyDescriptor: PropertyDescriptor): List = listOf()
open fun getModuleData(): AndroidModuleData {
val androidModule = androidModule ?: return AndroidModuleData.EMPTY
return AndroidModuleData(androidModule, androidModule.variants.map { getVariantData(it) })
}
fun getVariantData(variant: AndroidVariant): AndroidVariantData {
val psiManager = PsiManager.getInstance(project)
val fileManager = VirtualFileManager.getInstance()
fun VirtualFile.getAllChildren(): List {
val allChildren = arrayListOf()
val currentChildren = children ?: emptyArray()
for (child in currentChildren) {
if (child.isDirectory) {
allChildren.addAll(child.getAllChildren())
}
else {
allChildren.add(child)
}
}
return allChildren
}
val resDirectories = variant.resDirectories.map { fileManager.findFileByUrl("file://$it") }
val allChildren = resDirectories.flatMap { it?.getAllChildren() ?: listOf() }
val allLayoutFiles = allChildren.filter { it.parent.name.startsWith("layout") && it.name.toLowerCase().endsWith(".xml") }
val allLayoutPsiFiles = allLayoutFiles.fold(ArrayList(allLayoutFiles.size)) { list, file ->
val psiFile = psiManager.findFile(file)
if (psiFile != null && psiFile.parent != null) {
list += psiFile
}
list
}
val layoutNameToXmlFiles = allLayoutPsiFiles
.groupBy { it.name.substringBeforeLast('.') }
.mapValues { it.value.sortedBy { it.parent!!.name.length } }
return AndroidVariantData(variant, layoutNameToXmlFiles)
}
fun extractResources(files: List, module: ModuleDescriptor): List {
return filterDuplicates(doExtractResources(files, module))
}
protected abstract fun doExtractResources(files: List, module: ModuleDescriptor): List
protected fun parseAndroidResource(id: ResourceIdentifier, tag: String, sourceElement: PsiElement?): AndroidResource {
return when (tag) {
"fragment" -> AndroidResource.Fragment(id, sourceElement)
"include" -> AndroidResource.Widget(id, AndroidConst.VIEW_FQNAME, sourceElement)
else -> AndroidResource.Widget(id, tag, sourceElement)
}
}
private fun filterDuplicates(resources: List): List {
val resourceMap = linkedMapOf()
val resourcesToExclude = hashSetOf()
for (res in resources) {
if (resourceMap.contains(res.id.name)) {
val existing = resourceMap[res.id.name]!!
if (!res.sameClass(existing) || res.id.packageName != existing.id.packageName) {
resourcesToExclude.add(res.id.name)
}
else if (res is AndroidResource.Widget && existing is AndroidResource.Widget) {
// Widgets with the same id but different types exist.
if (res.xmlType != existing.xmlType && existing.xmlType != AndroidConst.VIEW_FQNAME) {
resourceMap.put(res.id.name, AndroidResource.Widget(res.id, AndroidConst.VIEW_FQNAME, res.sourceElement))
}
}
}
else resourceMap.put(res.id.name, res)
}
resourcesToExclude.forEach { resourceMap.remove(it) }
return resourceMap.values.toList()
}
companion object {
fun getInstance(module: Module): AndroidLayoutXmlFileManager? {
val service = ModuleServiceManager.getService(module, AndroidLayoutXmlFileManager::class.java)
return service ?: module.getComponent(AndroidLayoutXmlFileManager::class.java)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy