blob: 4dcbed1234b8746d95a3d2d1968f396d20e492ef [file] [log] [blame]
/*
* Copyright (c) 2010-2020 BSI Business Systems Integration AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BSI Business Systems Integration AG - initial API and implementation
*/
package org.eclipse.scout.sdk.s2i.nls
import com.intellij.openapi.module.Module
import com.intellij.openapi.progress.EmptyProgressIndicator
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import org.eclipse.scout.sdk.core.log.SdkLog
import org.eclipse.scout.sdk.core.s.nls.ITranslationStore
import org.eclipse.scout.sdk.core.s.nls.NlsFile
import org.eclipse.scout.sdk.core.s.nls.TranslationStoreStack
import org.eclipse.scout.sdk.core.s.nls.TranslationStores.createStack
import org.eclipse.scout.sdk.core.util.Ensure.newFail
import org.eclipse.scout.sdk.s2i.EclipseScoutBundle.message
import org.eclipse.scout.sdk.s2i.containingModule
import org.eclipse.scout.sdk.s2i.environment.IdeaEnvironment.Factory.callInIdeaEnvironmentSync
import org.eclipse.scout.sdk.s2i.environment.IdeaEnvironment.Factory.computeInLongReadAction
import org.eclipse.scout.sdk.s2i.getNioPath
import org.eclipse.scout.sdk.s2i.moduleDirPath
import org.eclipse.scout.sdk.s2i.toScoutProgress
object TranslationStoreStackLoader {
data class TranslationStoreStackLoaderResult(val stack: TranslationStoreStack, val primaryStore: ITranslationStore?, val nlsFile: VirtualFile?, val module: Module)
class ModalLoader(val module: Module, val nlsFile: VirtualFile?, title: String?) : Task.Modal(module.project, title ?: message("loading.translations"), true) {
private var m_errorHandler: ((Throwable) -> Unit)? = null
private var m_stackCreatedHandler: ((TranslationStoreStackLoaderResult?) -> Unit)? = null
fun withErrorHandler(handler: ((Throwable) -> Unit)?): ModalLoader {
m_errorHandler = handler
return this
}
fun withStackCreatedHandler(handler: ((TranslationStoreStackLoaderResult?) -> Unit)?): ModalLoader {
m_stackCreatedHandler = handler
return this
}
override fun run(indicator: ProgressIndicator) {
m_stackCreatedHandler?.invoke(createStack(module, nlsFile, indicator))
}
override fun onThrowable(error: Throwable) {
val handler = m_errorHandler ?: { SdkLog.error("Error computing texts for module '{}'.", module.name, it) }
handler.invoke(error)
}
}
/**
* Creates a [ModalLoader] to asynchronously create a [TranslationStoreStackLoaderResult].
* Use [ModalLoader.withStackCreatedHandler] and [ModalLoader.withErrorHandler] to register callbacks to be executed when the load finishes.
* [ModalLoader.queue] starts the computation. During the computation a modal progress indicator is displayed to the user.
*
* @param module The module for which the stack should be created.
* @param nlsFile An optional *.nls file within that module
* @param title An optional title to display in the modal progress bar
*/
fun createModalLoader(module: Module, nlsFile: VirtualFile? = null, title: String? = null) = ModalLoader(module, nlsFile, title)
/**
* Creates a [ModalLoader] to asynchronously create a [TranslationStoreStackLoaderResult].
* Use [ModalLoader.withStackCreatedHandler] and [ModalLoader.withErrorHandler] to register callbacks to be executed when the load finishes.
* [ModalLoader.queue] starts the computation. During the computation a modal progress indicator is displayed to the user.
*
* @param nlsFile The *.nls file that should be loaded
* @param project The [Project] in which it should loaded
* @param title An optional title to display in the modal progress bar
*/
fun createModalLoader(nlsFile: VirtualFile, project: Project, title: String? = null): ModalLoader {
val module = nlsFile.containingModule(project) ?: throw newFail("Module of file '{}' not found.", nlsFile)
return createModalLoader(module, nlsFile, title)
}
/**
* Loads the [TranslationStoreStack] for the given [Module].
*
* The load is executed synchronously and may take some time. Therefore it is recommended to use [createModalLoader] instead which executes the load asynchronously showing a progress bar.
* @param module The module for which the stack should be created.
* @return A [TranslationStoreStackLoaderResult] which holds the [TranslationStoreStack] (amongst others). The result may be null if not stack can be found for the given [Module] (e.g. if it is no Scout module).
*/
fun createStack(module: Module) = createStack(module, null)?.stack
/**
* Loads the [TranslationStoreStack] for the given [Module].
*
* The load is executed synchronously and may take some time. Therefore it is recommended to use [createModalLoader] instead which executes the load asynchronously showing a progress bar.
* @param module The module for which the stack should be created.
* @param nlsFile An optional [VirtualFile] that points to a *.nls file. This file will then be used to calculate the primary store of the stack.
* @return A [TranslationStoreStackLoaderResult] which holds the [TranslationStoreStack] (amongst others). The result may be null if not stack can be found for the given [Module] (e.g. if it is no Scout module).
*/
fun createStack(module: Module, nlsFile: VirtualFile? = null): TranslationStoreStackLoaderResult? {
val start = System.currentTimeMillis()
return try {
val indicator = ProgressManager.getInstance().progressIndicator ?: EmptyProgressIndicator()
return createStack(module, nlsFile, indicator)
} catch (e: Exception) {
SdkLog.error("Error computing texts for module '{}'.", module.name, e)
null
} finally {
SdkLog.debug("Translation stack creation took {}ms", System.currentTimeMillis() - start)
}
}
private fun createStack(module: Module, nlsFile: VirtualFile?, indicator: ProgressIndicator) = callInIdeaEnvironmentSync(module.project, indicator.toScoutProgress()) { e, p ->
return@callInIdeaEnvironmentSync computeInLongReadAction(module.project, p.indicator) {
return@computeInLongReadAction createStack(module.moduleDirPath(), e, p)
.map { stack -> TranslationStoreStackLoaderResult(stack, nlsFile?.let { findPrimaryStore(it, stack) }, nlsFile, module) }
.orElse(null)
}
}
private fun findPrimaryStore(nlsFile: VirtualFile, stack: TranslationStoreStack): ITranslationStore {
val nlsFilePath = nlsFile.getNioPath()
return NlsFile(nlsFilePath)
.findMatchingStoreIn(stack)
.orElseGet {
stack.allStores()
.findFirst()
.orElseThrow { newFail("No translation stores found for nls file '{}'.", nlsFilePath) }
}
}
}