mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -476,10 +476,16 @@ public class JVMNameUtil {
|
||||
|
||||
@Nullable
|
||||
public static String getClassVMName(@Nullable PsiClass containingClass) {
|
||||
if (containingClass == null) return null;
|
||||
// no support for local classes for now
|
||||
if (containingClass == null || PsiUtil.isLocalClass(containingClass)) return null;
|
||||
if (containingClass instanceof PsiAnonymousClass) {
|
||||
return getClassVMName(PsiTreeUtil.getParentOfType(containingClass, PsiClass.class)) +
|
||||
JavaAnonymousClassesHelper.getName((PsiAnonymousClass)containingClass);
|
||||
String parentName = getClassVMName(PsiTreeUtil.getParentOfType(containingClass, PsiClass.class));
|
||||
if (parentName == null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return parentName + JavaAnonymousClassesHelper.getName((PsiAnonymousClass)containingClass);
|
||||
}
|
||||
}
|
||||
return ClassUtil.getJVMClassName(containingClass);
|
||||
}
|
||||
|
||||
@@ -213,8 +213,8 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio
|
||||
}
|
||||
|
||||
private PsiElement remapElement(PsiElement element) {
|
||||
PsiClass aClass = getEnclosingClass(element);
|
||||
if (!Comparing.equal(myExpectedClassName, JVMNameUtil.getClassVMName(aClass))) {
|
||||
String name = JVMNameUtil.getClassVMName(getEnclosingClass(element));
|
||||
if (name != null && !name.equals(myExpectedClassName)) {
|
||||
return null;
|
||||
}
|
||||
PsiElement method = DebuggerUtilsEx.getContainingMethod(element);
|
||||
|
||||
+31
-26
@@ -25,6 +25,7 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
|
||||
import com.intellij.openapi.fileChooser.FileChooserFactory;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.project.ex.ProjectEx;
|
||||
@@ -224,35 +225,39 @@ public class ProjectConfigurable extends ProjectStructureElementConfigurable<Pro
|
||||
throw new ConfigurationException("Please, specify project name!");
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
DumbService.getInstance(myProject).allowStartingDumbModeInside(DumbService.DumbModePermission.MAY_START_BACKGROUND, new Runnable() {
|
||||
public void run() {
|
||||
// set the output path first so that handlers of RootsChanged event sent after JDK is set
|
||||
// would see the updated path
|
||||
String canonicalPath = myProjectCompilerOutput.getText();
|
||||
if (canonicalPath != null && canonicalPath.length() > 0) {
|
||||
try {
|
||||
canonicalPath = FileUtil.resolveShortWindowsName(canonicalPath);
|
||||
}
|
||||
catch (IOException e) {
|
||||
//file doesn't exist yet
|
||||
}
|
||||
canonicalPath = FileUtil.toSystemIndependentName(canonicalPath);
|
||||
compilerProjectExtension.setCompilerOutputUrl(VfsUtilCore.pathToUrl(canonicalPath));
|
||||
}
|
||||
else {
|
||||
compilerProjectExtension.setCompilerOutputPointer(null);
|
||||
}
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// set the output path first so that handlers of RootsChanged event sent after JDK is set
|
||||
// would see the updated path
|
||||
String canonicalPath = myProjectCompilerOutput.getText();
|
||||
if (canonicalPath != null && canonicalPath.length() > 0) {
|
||||
try {
|
||||
canonicalPath = FileUtil.resolveShortWindowsName(canonicalPath);
|
||||
}
|
||||
catch (IOException e) {
|
||||
//file doesn't exist yet
|
||||
}
|
||||
canonicalPath = FileUtil.toSystemIndependentName(canonicalPath);
|
||||
compilerProjectExtension.setCompilerOutputUrl(VfsUtilCore.pathToUrl(canonicalPath));
|
||||
}
|
||||
else {
|
||||
compilerProjectExtension.setCompilerOutputPointer(null);
|
||||
}
|
||||
|
||||
LanguageLevelProjectExtension extension = LanguageLevelProjectExtension.getInstance(myProject);
|
||||
extension.setLanguageLevel(myLanguageLevelCombo.getSelectedLevel());
|
||||
extension.setDefault(myLanguageLevelCombo.isDefault());
|
||||
myProjectJdkConfigurable.apply();
|
||||
LanguageLevelProjectExtension extension = LanguageLevelProjectExtension.getInstance(myProject);
|
||||
extension.setLanguageLevel(myLanguageLevelCombo.getSelectedLevel());
|
||||
extension.setDefault(myLanguageLevelCombo.isDefault());
|
||||
myProjectJdkConfigurable.apply();
|
||||
|
||||
if (myProjectName != null) {
|
||||
((ProjectEx)myProject).setProjectName(myProjectName.getText().trim());
|
||||
if (myDetailsComponent != null) myDetailsComponent.setText(getBannerSlogan());
|
||||
}
|
||||
if (myProjectName != null) {
|
||||
((ProjectEx)myProject).setProjectName(myProjectName.getText().trim());
|
||||
if (myDetailsComponent != null) myDetailsComponent.setText(getBannerSlogan());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ public abstract class ExecutionWithDebuggerToolsTestCase extends ExecutionTestCa
|
||||
}
|
||||
catch (AssertionError e) {
|
||||
addException(e);
|
||||
paused(suspendContext);
|
||||
resume(suspendContext);
|
||||
}
|
||||
|
||||
if (myScriptRunnables.isEmpty()) {
|
||||
|
||||
@@ -143,25 +143,28 @@ public class Main {
|
||||
return args.length > 0 && Comparing.strEqual(args[0], "traverseUI");
|
||||
}
|
||||
|
||||
private static boolean checkBundledJava(File java) throws IOException {
|
||||
private static boolean checkBundledJava(File java) throws Exception {
|
||||
String[] command = new String[]{java.getPath(), "-version"};
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec(command);
|
||||
String line = (new BufferedReader(new InputStreamReader(process.getErrorStream()))).readLine();
|
||||
if (line != null && (line.toLowerCase().startsWith("java version") || (line.toLowerCase().startsWith("openjdk version")))){
|
||||
String[] javaVersion = line.split("\\.");
|
||||
int i = 1;
|
||||
if (javaVersion.length > i && Integer.parseInt(javaVersion[i]) > 5) {
|
||||
return true;
|
||||
int pos = line.indexOf('.');
|
||||
if (pos > 0){
|
||||
int majorVersion = Integer.parseInt(line.substring(pos-1, pos));
|
||||
int minorVersion = Integer.parseInt(line.substring(pos+1, pos+2));
|
||||
if (majorVersion > 1 || minorVersion > 5) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
System.out.println("updater: the java: " + command[0] + " is invalid.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String getBundledJava(String javaHome) throws IOException {
|
||||
private static String getBundledJava(String javaHome) throws Exception {
|
||||
String javaHomeCopy = System.getProperty("user.home") + "/." + System.getProperty("idea.paths.selector") + "/restart/jre";
|
||||
File javaCopy = SystemInfoRt.isWindows ? new File(javaHomeCopy + "/bin/java.exe") : new File(javaHomeCopy + "/bin/java");
|
||||
if (javaCopy != null && javaCopy.isFile() && checkBundledJava(javaCopy)) {
|
||||
@@ -177,7 +180,7 @@ public class Main {
|
||||
return javaHome;
|
||||
}
|
||||
|
||||
private static String getJava() throws IOException {
|
||||
private static String getJava() throws Exception {
|
||||
String javaHome = System.getProperty("java.home");
|
||||
if (javaHome.toLowerCase().startsWith(PathManager.getHomePath().toLowerCase())) {
|
||||
System.out.println("Updater: uses bundled java.");
|
||||
@@ -186,7 +189,7 @@ public class Main {
|
||||
return javaHome + "/bin/java";
|
||||
}
|
||||
|
||||
private static void installPatch() throws IOException {
|
||||
private static void installPatch() throws Exception {
|
||||
String platform = System.getProperty(PLATFORM_PREFIX_PROPERTY, "idea");
|
||||
String patchFileName = ("jetbrains.patch.jar." + platform).toLowerCase(Locale.US);
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.configurationStore
|
||||
|
||||
import com.intellij.application.options.PathMacrosImpl
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.application.impl.ApplicationImpl
|
||||
import com.intellij.openapi.components.PathMacroManager
|
||||
import com.intellij.openapi.components.StateStorage
|
||||
import com.intellij.openapi.components.StateStorageOperation
|
||||
import com.intellij.openapi.components.StoragePathMacros
|
||||
import com.intellij.openapi.components.impl.BasePathMacroManager
|
||||
import com.intellij.openapi.components.impl.stores.DirectoryStorageData
|
||||
import com.intellij.openapi.components.impl.stores.StateStorageManager
|
||||
import com.intellij.openapi.components.impl.stores.StorageData
|
||||
import com.intellij.openapi.util.NamedJDOMExternalizable
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
|
||||
class ApplicationPathMacroManager : BasePathMacroManager(null)
|
||||
|
||||
class ApplicationStoreImpl(private val application: ApplicationImpl, pathMacroManager: PathMacroManager) : ComponentStoreImpl() {
|
||||
private val stateStorageManager: StateStorageManager
|
||||
|
||||
companion object {
|
||||
private val DEFAULT_STORAGE_SPEC = "${StoragePathMacros.APP_CONFIG}/${PathManager.DEFAULT_OPTIONS_FILE_NAME}${DirectoryStorageData.DEFAULT_EXT}"
|
||||
}
|
||||
|
||||
init {
|
||||
stateStorageManager = object : StateStorageManagerImpl(pathMacroManager.createTrackingSubstitutor(), "application", application, application.getPicoContainer()) {
|
||||
private var configDirectoryRefreshed = false
|
||||
|
||||
override fun createStorageTopicListener() = application.getMessageBus().syncPublisher(StateStorage.STORAGE_TOPIC)
|
||||
|
||||
override fun createStorageData(fileSpec: String, filePath: String) = StorageData(rootTagName)
|
||||
|
||||
override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String? {
|
||||
if (component is NamedJDOMExternalizable) {
|
||||
return "${StoragePathMacros.APP_CONFIG}/${component.getExternalFileName()}${DirectoryStorageData.DEFAULT_EXT}"
|
||||
}
|
||||
else {
|
||||
return DEFAULT_STORAGE_SPEC
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMacroSubstitutor(fileSpec: String) = if (fileSpec == "${StoragePathMacros.APP_CONFIG}/${PathMacrosImpl.EXT_FILE_NAME}${DirectoryStorageData.DEFAULT_EXT}") null else super.getMacroSubstitutor(fileSpec)
|
||||
|
||||
override fun isUseXmlProlog() = false
|
||||
|
||||
override fun beforeFileBasedStorageCreate() {
|
||||
if (configDirectoryRefreshed || (!application.isUnitTestMode() && !application.isDispatchThread())) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
val configPath = expandMacros(StoragePathMacros.ROOT_CONFIG)
|
||||
if (configPath == StoragePathMacros.ROOT_CONFIG) {
|
||||
LOG.warn("Macros ROOT_CONFIG is not defined")
|
||||
return
|
||||
}
|
||||
|
||||
val configDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(configPath)
|
||||
if (configDir != null) {
|
||||
VfsUtil.markDirtyAndRefresh(false, true, true, configDir)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
configDirectoryRefreshed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMessageBus() = application.getMessageBus()
|
||||
|
||||
override fun getStateStorageManager() = stateStorageManager
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.configurationStore
|
||||
|
||||
import com.intellij.openapi.components.PathMacroManager
|
||||
import com.intellij.openapi.components.PathMacroSubstitutor
|
||||
import com.intellij.openapi.components.impl.stores.StateStorageManager
|
||||
import com.intellij.openapi.components.impl.stores.StorageData
|
||||
import org.jdom.Element
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
abstract class BaseFileConfigurableStoreImpl(protected val pathMacroManager: PathMacroManager) : ComponentStoreImpl() {
|
||||
val storageManager by Delegates.lazy { createStorageManager() }
|
||||
|
||||
override fun getStateStorageManager() = storageManager
|
||||
|
||||
override fun getPathMacroManagerForDefaults() = pathMacroManager
|
||||
|
||||
protected abstract fun createStorageManager(): StateStorageManager
|
||||
}
|
||||
|
||||
open class ProjectStorageData : StorageData {
|
||||
companion object {
|
||||
val CURRENT_FORMAT_VERSION = 4
|
||||
val VERSION_OPTION: String = "version"
|
||||
}
|
||||
|
||||
private var version = CURRENT_FORMAT_VERSION
|
||||
|
||||
constructor(rootElementName: String) : super(rootElementName) {
|
||||
}
|
||||
|
||||
protected constructor(storageData: ProjectStorageData) : super(storageData) {
|
||||
}
|
||||
|
||||
override fun load(rootElement: Element, pathMacroSubstitutor: PathMacroSubstitutor?, intern: Boolean) {
|
||||
super.load(rootElement, pathMacroSubstitutor, intern)
|
||||
|
||||
version = rootElement.getAttributeValue(VERSION_OPTION)?.toInt() ?: CURRENT_FORMAT_VERSION
|
||||
}
|
||||
|
||||
override fun save(newLiveStates: Map<String, Element>): Element {
|
||||
var root = super.save(newLiveStates)
|
||||
if (root == null) {
|
||||
root = Element(myRootElementName)
|
||||
}
|
||||
writeOptions(root, Integer.toString(version))
|
||||
return root
|
||||
}
|
||||
|
||||
override fun clone() = ProjectStorageData(this)
|
||||
|
||||
protected open fun writeOptions(root: Element, versionString: String) {
|
||||
root.setAttribute(VERSION_OPTION, "4")
|
||||
}
|
||||
|
||||
override fun getChangedComponentNames(newStorageData: StorageData, substitutor: PathMacroSubstitutor?): Set<String>? {
|
||||
if (version != (newStorageData as ProjectStorageData).version) {
|
||||
return null
|
||||
}
|
||||
return super.getChangedComponentNames(newStorageData, substitutor)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,494 @@
|
||||
/*
|
||||
* 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.configurationStore
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.application.ReadAction
|
||||
import com.intellij.openapi.application.WriteAction
|
||||
import com.intellij.openapi.application.ex.DecodeDefaultsUtil
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.components.StateStorage.SaveSession
|
||||
import com.intellij.openapi.components.StateStorageChooserEx.Resolution
|
||||
import com.intellij.openapi.components.impl.ComponentManagerImpl
|
||||
import com.intellij.openapi.components.impl.stores.*
|
||||
import com.intellij.openapi.components.impl.stores.StateStorageManager.ExternalizationSession
|
||||
import com.intellij.openapi.components.store.ReadOnlyModificationException
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util
|
||||
import com.intellij.openapi.util.*
|
||||
import com.intellij.openapi.util.Pair
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
|
||||
import com.intellij.util.ArrayUtilRt
|
||||
import com.intellij.util.ReflectionUtil
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import com.intellij.util.containers.SmartHashSet
|
||||
import com.intellij.util.lang.CompoundRuntimeException
|
||||
import com.intellij.util.messages.MessageBus
|
||||
import com.intellij.util.xmlb.JDOMXIncluder
|
||||
import gnu.trove.THashMap
|
||||
import org.jdom.Element
|
||||
import org.jdom.JDOMException
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.Arrays
|
||||
import java.util.Collections
|
||||
import java.util.Comparator
|
||||
import java.util.LinkedHashSet
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import kotlin.reflect.jvm.java
|
||||
|
||||
private val LOG = Logger.getInstance(javaClass<ComponentStoreImpl>())
|
||||
|
||||
public abstract class ComponentStoreImpl : IComponentStore {
|
||||
private val myComponents = Collections.synchronizedMap(THashMap<String, Any>())
|
||||
private val mySettingsSavingComponents = CopyOnWriteArrayList<SettingsSavingComponent>()
|
||||
|
||||
protected open val defaultStorageChooser: StateStorageChooser<PersistentStateComponent<*>>? = null
|
||||
|
||||
override fun initComponent(component: Any, service: Boolean) {
|
||||
if (component is SettingsSavingComponent) {
|
||||
mySettingsSavingComponents.add(component)
|
||||
}
|
||||
|
||||
if (!(component is JDOMExternalizable || component is PersistentStateComponent<*>)) {
|
||||
return
|
||||
}
|
||||
|
||||
val token = ReadAction.start()
|
||||
try {
|
||||
val componentNameIfStateExists: String?
|
||||
if (component is PersistentStateComponent<*>) {
|
||||
componentNameIfStateExists = initPersistentComponent(component, null, false)
|
||||
}
|
||||
else {
|
||||
componentNameIfStateExists = initJdomExternalizable(component as JDOMExternalizable)
|
||||
}
|
||||
|
||||
// if not service, so, component manager will check it later for all components
|
||||
if (componentNameIfStateExists != null && service) {
|
||||
val project = getProject()
|
||||
val app = ApplicationManager.getApplication()
|
||||
if (project != null && !app.isHeadlessEnvironment() && !app.isUnitTestMode() && project.isInitialized()) {
|
||||
val substitutor = getStateStorageManager().getMacroSubstitutor()
|
||||
if (substitutor != null) {
|
||||
StorageUtil.notifyUnknownMacros(substitutor, project, componentNameIfStateExists)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e: StateStorageException) {
|
||||
throw e
|
||||
}
|
||||
catch (e: ProcessCanceledException) {
|
||||
throw e
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
}
|
||||
finally {
|
||||
token.finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun save(readonlyFiles: MutableList<util.Pair<StateStorage.SaveSession, VirtualFile>>) {
|
||||
val externalizationSession = if (myComponents.isEmpty()) null else getStateStorageManager().startExternalization()
|
||||
if (externalizationSession != null) {
|
||||
val names = ArrayUtilRt.toStringArray(myComponents.keySet())
|
||||
Arrays.sort(names)
|
||||
for (name in names) {
|
||||
commitComponent(externalizationSession, myComponents.get(name)!!, name)
|
||||
}
|
||||
}
|
||||
|
||||
var errors: MutableList<Throwable>? = null
|
||||
for (settingsSavingComponent in mySettingsSavingComponents) {
|
||||
try {
|
||||
settingsSavingComponent.save()
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
if (errors == null) {
|
||||
errors = SmartList<Throwable>()
|
||||
}
|
||||
errors.add(e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
errors = doSave(externalizationSession?.createSaveSessions(), readonlyFiles, errors)
|
||||
CompoundRuntimeException.doThrow(errors)
|
||||
}
|
||||
|
||||
override TestOnly fun saveApplicationComponent(component: Any) {
|
||||
val externalizationSession = getStateStorageManager().startExternalization() ?: return
|
||||
|
||||
commitComponent(externalizationSession, component, null)
|
||||
val sessions = externalizationSession.createSaveSessions()
|
||||
if (sessions.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val file: File
|
||||
val state = StoreUtil.getStateSpec(component.javaClass)
|
||||
if (state != null) {
|
||||
file = File(getStateStorageManager().expandMacros(findNonDeprecated(state.storages).file))
|
||||
}
|
||||
else if (component is ExportableApplicationComponent && component is NamedJDOMExternalizable) {
|
||||
file = PathManager.getOptionsFile(component)
|
||||
}
|
||||
else {
|
||||
throw AssertionError("${component.javaClass} doesn't have @State annotation and doesn't implement ExportableApplicationComponent")
|
||||
}
|
||||
|
||||
val token = WriteAction.start()
|
||||
try {
|
||||
VfsRootAccess.allowRootAccess(file.getAbsolutePath())
|
||||
CompoundRuntimeException.doThrow(doSave(sessions, arrayListOf(), null))
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
VfsRootAccess.disallowRootAccess(file.getAbsolutePath())
|
||||
}
|
||||
finally {
|
||||
token.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun commitComponent(externalizationSession: ExternalizationSession, component: Any, componentName: String?) {
|
||||
if (component is PersistentStateComponent<*>) {
|
||||
commitPersistentComponent(component, externalizationSession, componentName)
|
||||
}
|
||||
else if (component is JDOMExternalizable) {
|
||||
externalizationSession.setStateInOldStorage(component, componentName ?: ComponentManagerImpl.getComponentName(component), component)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun doSave(saveSessions: List<SaveSession>?, readonlyFiles: MutableList<Pair<SaveSession, VirtualFile>>, prevErrors: MutableList<Throwable>?): MutableList<Throwable>? {
|
||||
var errors = prevErrors
|
||||
if (saveSessions != null) {
|
||||
for (session in saveSessions) {
|
||||
errors = executeSave(session, readonlyFiles, prevErrors)
|
||||
}
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
private fun <T> commitPersistentComponent(component: PersistentStateComponent<T>, session: ExternalizationSession, componentName: String?) {
|
||||
val state = component.getState()
|
||||
if (state != null) {
|
||||
val storageSpecs = getComponentStorageSpecs(component, StoreUtil.getStateSpec(component), StateStorageOperation.WRITE)
|
||||
session.setState(storageSpecs, component, componentName ?: StoreUtil.getComponentName(component), state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initJdomExternalizable(component: JDOMExternalizable): String? {
|
||||
val componentName = ComponentManagerImpl.getComponentName(component)
|
||||
doAddComponent(componentName, component)
|
||||
|
||||
if (optimizeTestLoading()) {
|
||||
return null
|
||||
}
|
||||
|
||||
loadJdomDefaults(component, componentName)
|
||||
|
||||
val stateStorage = getStateStorageManager().getOldStorage(component, componentName, StateStorageOperation.READ) ?: return null
|
||||
val element = stateStorage.getState<Element>(component, componentName, javaClass<Element>(), null) ?: return null
|
||||
try {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Loading configuration for " + component.javaClass)
|
||||
}
|
||||
component.readExternal(element)
|
||||
}
|
||||
catch (e: InvalidDataException) {
|
||||
LOG.error(e)
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
return componentName
|
||||
}
|
||||
|
||||
private fun doAddComponent(componentName: String, component: Any) {
|
||||
val existing = myComponents.get(componentName)
|
||||
if (existing != null && existing !== component) {
|
||||
LOG.error("Conflicting component name '" + componentName + "': " + existing.javaClass + " and " + component.javaClass)
|
||||
}
|
||||
myComponents.put(componentName, component)
|
||||
}
|
||||
|
||||
private fun loadJdomDefaults(component: JDOMExternalizable, componentName: String) {
|
||||
try {
|
||||
val defaultState = getDefaultState(component, componentName, javaClass<Element>())
|
||||
if (defaultState != null) {
|
||||
component.readExternal(defaultState)
|
||||
}
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error("Cannot load defaults for " + component.javaClass, e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected open fun getProject(): Project? = null
|
||||
|
||||
private fun <T> initPersistentComponent(component: PersistentStateComponent<T>, changedStorages: Set<StateStorage>?, reloadData: Boolean): String? {
|
||||
val stateSpec = StoreUtil.getStateSpec(component)
|
||||
val name = stateSpec.name
|
||||
if (changedStorages == null || !reloadData) {
|
||||
doAddComponent(name, component)
|
||||
}
|
||||
if (optimizeTestLoading()) {
|
||||
return null
|
||||
}
|
||||
|
||||
val stateClass = ComponentSerializationUtil.getStateClass<T>(component.javaClass)
|
||||
if (!stateSpec.defaultStateAsResource && LOG.isDebugEnabled() && getDefaultState(component, name, stateClass) != null) {
|
||||
LOG.error(name + " has default state, but not marked to load it")
|
||||
}
|
||||
|
||||
var state = if (stateSpec.defaultStateAsResource) getDefaultState(component, name, stateClass) else null
|
||||
val storageSpecs = getComponentStorageSpecs(component, stateSpec, StateStorageOperation.READ)
|
||||
val stateStorageChooser = component as? StateStorageChooserEx
|
||||
for (storageSpec in storageSpecs) {
|
||||
val resolution = if (stateStorageChooser == null) Resolution.DO else stateStorageChooser.getResolution(storageSpec, StateStorageOperation.READ)
|
||||
if (resolution === Resolution.SKIP) {
|
||||
continue
|
||||
}
|
||||
|
||||
val stateStorage = getStateStorageManager().getStateStorage(storageSpec)
|
||||
if (stateStorage != null) {
|
||||
var forcedState = false
|
||||
if (!stateStorage.hasState(component, name, stateClass, reloadData)) {
|
||||
forcedState = changedStorages != null && changedStorages.contains(stateStorage)
|
||||
if (!forcedState) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
state = stateStorage.getState(component, name, stateClass, state)
|
||||
if (state == null && forcedState) {
|
||||
// state will be null if file deleted
|
||||
// we must create empty (initial) state to reinit component
|
||||
state = DefaultStateSerializer.deserializeState(Element("state"), stateClass, null)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (state != null) {
|
||||
component.loadState(state)
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
protected open fun getPathMacroManagerForDefaults(): PathMacroManager? = null
|
||||
|
||||
protected fun <T : Any> getDefaultState(component: Any, componentName: String, stateClass: Class<T>): T? {
|
||||
val url = DecodeDefaultsUtil.getDefaults(component, componentName) ?: return null
|
||||
try {
|
||||
val documentElement = JDOMXIncluder.resolve(JDOMUtil.loadDocument(url), url.toExternalForm()).detachRootElement()
|
||||
getPathMacroManagerForDefaults()?.expandPaths(documentElement)
|
||||
return DefaultStateSerializer.deserializeState<T>(documentElement, stateClass, null)
|
||||
}
|
||||
catch (e: IOException) {
|
||||
throw StateStorageException("Error loading state from " + url, e)
|
||||
}
|
||||
catch (e: JDOMException) {
|
||||
throw StateStorageException("Error loading state from " + url, e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected open fun <T> getComponentStorageSpecs(component: PersistentStateComponent<T>, stateSpec: State, operation: StateStorageOperation): Array<Storage> {
|
||||
val storages = stateSpec.storages
|
||||
if (storages.size() == 1 || component is StateStorageChooserEx) {
|
||||
return storages
|
||||
}
|
||||
assert(!storages.isEmpty())
|
||||
|
||||
var storageChooserClass = stateSpec.storageChooser.java
|
||||
if (storageChooserClass != javaClass<StateStorageChooser<*>>()) {
|
||||
@suppress("UNCHECKED_CAST")
|
||||
val stateStorageChooser: StateStorageChooser<Any> = ReflectionUtil.newInstance(stateSpec.storageChooser.java as Class<out StateStorageChooser<Any>>)
|
||||
return stateStorageChooser.selectStorages(storages, component, operation)
|
||||
}
|
||||
|
||||
val defaultChooser = defaultStorageChooser
|
||||
if (defaultChooser != null) {
|
||||
return defaultChooser.selectStorages(storages, component, operation)
|
||||
}
|
||||
|
||||
var actualStorageCount = 0
|
||||
for (storage in storages) {
|
||||
if (!storage.deprecated) {
|
||||
actualStorageCount++
|
||||
}
|
||||
}
|
||||
|
||||
if (actualStorageCount > 1) {
|
||||
LOG.error("State chooser not specified for: " + component.javaClass)
|
||||
}
|
||||
|
||||
if (!storages[0].deprecated) {
|
||||
var othersAreDeprecated = true
|
||||
for (i in 1..storages.size() - 1) {
|
||||
if (!storages[i].deprecated) {
|
||||
othersAreDeprecated = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (othersAreDeprecated) {
|
||||
return storages
|
||||
}
|
||||
}
|
||||
|
||||
val sorted = Arrays.copyOf(storages, storages.size())
|
||||
Arrays.sort(sorted, object : Comparator<Storage> {
|
||||
override fun compare(o1: Storage, o2: Storage): Int {
|
||||
val w1 = if (o1.deprecated) 1 else 0
|
||||
val w2 = if (o2.deprecated) 1 else 0
|
||||
return w1 - w2
|
||||
}
|
||||
})
|
||||
return sorted
|
||||
}
|
||||
|
||||
protected open fun optimizeTestLoading(): Boolean = false
|
||||
|
||||
override fun isReloadPossible(componentNames: Set<String>): Boolean {
|
||||
for (componentName in componentNames) {
|
||||
val component = myComponents.get(componentName)
|
||||
if (component != null && (component !is PersistentStateComponent<*> || !StoreUtil.getStateSpec(component).reloadable)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getNotReloadableComponents(componentNames: Collection<String>): Collection<String> {
|
||||
var notReloadableComponents: MutableSet<String>? = null
|
||||
for (componentName in componentNames) {
|
||||
val component = myComponents.get(componentName)
|
||||
if (component != null && (component !is PersistentStateComponent<*> || !StoreUtil.getStateSpec(component).reloadable)) {
|
||||
if (notReloadableComponents == null) {
|
||||
notReloadableComponents = LinkedHashSet<String>()
|
||||
}
|
||||
notReloadableComponents.add(componentName)
|
||||
}
|
||||
}
|
||||
return if (notReloadableComponents == null) emptySet<String>() else notReloadableComponents
|
||||
}
|
||||
|
||||
override fun reinitComponents(componentNames: Set<String>, reloadData: Boolean) {
|
||||
reinitComponents(componentNames, emptySet<String>(), emptySet<StateStorage>())
|
||||
}
|
||||
|
||||
override fun reinitComponent(componentName: String, changedStorages: Set<StateStorage>): Boolean {
|
||||
val component = myComponents.get(componentName) as PersistentStateComponent<*>?
|
||||
if (component == null) {
|
||||
return false
|
||||
}
|
||||
else {
|
||||
val changedStoragesEmpty = changedStorages.isEmpty()
|
||||
initPersistentComponent(component, if (changedStoragesEmpty) null else changedStorages, changedStoragesEmpty)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun getMessageBus(): MessageBus
|
||||
|
||||
override fun reload(changedStorages: MultiMap<StateStorage, VirtualFile>): Collection<String>? {
|
||||
if (changedStorages.isEmpty()) {
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
val componentNames = SmartHashSet<String>()
|
||||
for (storage in changedStorages.keySet()) {
|
||||
try {
|
||||
// we must update (reload in-memory storage data) even if non-reloadable component will be detected later
|
||||
// not saved -> user does own modification -> new (on disk) state will be overwritten and not applied
|
||||
storage.analyzeExternalChangesAndUpdateIfNeed(changedStorages.get(storage), componentNames)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
LOG.error(e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (componentNames.isEmpty()) {
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
val notReloadableComponents = getNotReloadableComponents(componentNames)
|
||||
reinitComponents(componentNames, notReloadableComponents, changedStorages.keySet())
|
||||
return if (notReloadableComponents.isEmpty()) null else notReloadableComponents
|
||||
}
|
||||
|
||||
// used in settings repository plugin
|
||||
public fun reinitComponents(componentNames: Set<String>, notReloadableComponents: Collection<String>, changedStorages: Set<StateStorage>) {
|
||||
val messageBus = getMessageBus()
|
||||
messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateStarted()
|
||||
try {
|
||||
for (componentName in componentNames) {
|
||||
if (!notReloadableComponents.contains(componentName)) {
|
||||
reinitComponent(componentName, changedStorages)
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateFinished()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun findNonDeprecated(storages: Array<Storage>): Storage {
|
||||
for (storage in storages) {
|
||||
if (!storage.deprecated) {
|
||||
return storage
|
||||
}
|
||||
}
|
||||
throw AssertionError("All storages are deprecated")
|
||||
}
|
||||
|
||||
protected fun executeSave(session: SaveSession, readonlyFiles: MutableList<Pair<SaveSession, VirtualFile>>, previousErrors: MutableList<Throwable>?): MutableList<Throwable>? {
|
||||
var errors = previousErrors
|
||||
try {
|
||||
session.save()
|
||||
}
|
||||
catch (e: ReadOnlyModificationException) {
|
||||
LOG.warn(e)
|
||||
readonlyFiles.add(util.Pair.create<SaveSession, VirtualFile>(if (e.getSession() == null) session else e.getSession(), e.getFile()))
|
||||
}
|
||||
catch (e: Exception) {
|
||||
if (errors == null) {
|
||||
errors = SmartList<Throwable>()
|
||||
}
|
||||
errors.add(e)
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.configurationStore
|
||||
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.components.impl.stores.FileBasedStorage
|
||||
import com.intellij.openapi.components.impl.stores.StateStorageManager
|
||||
import com.intellij.openapi.components.impl.stores.StreamProvider
|
||||
import com.intellij.openapi.project.impl.ProjectImpl
|
||||
import com.intellij.openapi.project.impl.ProjectManagerImpl
|
||||
import com.intellij.openapi.util.Couple
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jdom.Element
|
||||
|
||||
class DefaultProjectStoreImpl(project: ProjectImpl, private val projectManager: ProjectManagerImpl, pathMacroManager: PathMacroManager) : ProjectStoreImpl(project, pathMacroManager) {
|
||||
fun getStateCopy(): Element? {
|
||||
val element = projectManager.getDefaultProjectRootElement()
|
||||
return element?.clone()
|
||||
}
|
||||
|
||||
override protected fun createStorageManager(): StateStorageManager {
|
||||
val storage = DefaultProjectStorage(this, pathMacroManager, projectManager)
|
||||
//noinspection deprecation
|
||||
return object : StateStorageManager {
|
||||
override fun addMacro(macro: String, expansion: String) = throw UnsupportedOperationException("Method addMacro not implemented in " + javaClass)
|
||||
|
||||
override fun getMacroSubstitutor() = null
|
||||
|
||||
override fun getStateStorage(storageSpec: Storage) = storage
|
||||
|
||||
override fun getStateStorage(fileSpec: String, roamingType: RoamingType) = storage
|
||||
|
||||
override fun getCachedFileStateStorages(changed: Collection<String>, deleted: Collection<String>): Couple<Collection<FileBasedStorage>> = Couple(emptyList<FileBasedStorage>(), emptyList<FileBasedStorage>())
|
||||
|
||||
override fun clearStateStorage(file: String) {
|
||||
}
|
||||
|
||||
override fun startExternalization(): StateStorageManager.ExternalizationSession? {
|
||||
val externalizationSession = storage.startExternalization()
|
||||
return if (externalizationSession == null) null else MyExternalizationSession(externalizationSession)
|
||||
}
|
||||
|
||||
override fun expandMacros(file: String) = throw UnsupportedOperationException("Method expandMacros not implemented in " + javaClass)
|
||||
|
||||
override fun collapseMacros(path: String) = throw UnsupportedOperationException("Method collapseMacros not implemented in " + javaClass)
|
||||
|
||||
override fun getOldStorage(component: Any, componentName: String, operation: StateStorageOperation) = storage
|
||||
|
||||
override fun setStreamProvider(streamProvider: StreamProvider?) = throw UnsupportedOperationException("Method setStreamProvider not implemented in " + javaClass)
|
||||
|
||||
override fun getStreamProvider() = throw UnsupportedOperationException("Method getStreamProviders not implemented in " + javaClass)
|
||||
|
||||
override fun getStorageFileNames() = throw UnsupportedOperationException("Method getStorageFileNames not implemented in " + javaClass)
|
||||
}
|
||||
}
|
||||
|
||||
private class MyExternalizationSession(val externalizationSession: StateStorage.ExternalizationSession) : StateStorageManager.ExternalizationSession {
|
||||
override fun setState(storageSpecs: Array<Storage>, component: Any, componentName: String, state: Any) {
|
||||
externalizationSession.setState(component, componentName, state, null)
|
||||
}
|
||||
|
||||
override fun setStateInOldStorage(component: Any, componentName: String, state: Any) {
|
||||
externalizationSession.setState(component, componentName, state, null)
|
||||
}
|
||||
|
||||
override fun createSaveSessions() = ContainerUtil.createMaybeSingletonList(externalizationSession.createSaveSession())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.configurationStore
|
||||
|
||||
import com.intellij.openapi.components.PathMacroSubstitutor
|
||||
import com.intellij.openapi.components.impl.stores.StorageData
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.OptionManager
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jdom.Element
|
||||
import java.util.TreeMap
|
||||
|
||||
class ModuleFileData : ProjectStorageData, OptionManager {
|
||||
private var options: TreeMap<String, String>? = null
|
||||
private val module: Module
|
||||
|
||||
private var dirty = true
|
||||
|
||||
override fun isDirty() = dirty
|
||||
|
||||
public constructor(rootElementName: String, module: Module) : super(rootElementName) {
|
||||
this.module = module
|
||||
options = TreeMap<String, String>()
|
||||
}
|
||||
|
||||
private constructor(storageData: ModuleFileData) : super(storageData) {
|
||||
module = storageData.module
|
||||
dirty = storageData.dirty
|
||||
options = TreeMap(storageData.options)
|
||||
}
|
||||
|
||||
override fun load(rootElement: Element, pathMacroSubstitutor: PathMacroSubstitutor?, intern: Boolean) {
|
||||
super<ProjectStorageData>.load(rootElement, pathMacroSubstitutor, intern)
|
||||
|
||||
for (attribute in rootElement.getAttributes()) {
|
||||
val name = attribute.getName()
|
||||
if (name != ProjectStorageData.VERSION_OPTION && !StringUtil.isEmpty(name)) {
|
||||
options!!.put(name, attribute.getValue())
|
||||
}
|
||||
}
|
||||
|
||||
dirty = false
|
||||
}
|
||||
|
||||
override fun writeOptions(root: Element, versionString: String) {
|
||||
if (!options!!.isEmpty()) {
|
||||
for (key in options!!.keySet()) {
|
||||
val value = options!!.get(key)
|
||||
if (value != null) {
|
||||
root.setAttribute(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
// need be last for compat reasons
|
||||
super<ProjectStorageData>.writeOptions(root, versionString)
|
||||
|
||||
dirty = false
|
||||
}
|
||||
|
||||
override fun clone() = ModuleFileData(this)
|
||||
|
||||
override fun getChangedComponentNames(newStorageData: StorageData, substitutor: PathMacroSubstitutor?): Set<String>? {
|
||||
val data = newStorageData as ModuleFileData
|
||||
if (options != data.options) {
|
||||
return null
|
||||
}
|
||||
|
||||
return super<ProjectStorageData>.getChangedComponentNames(newStorageData, substitutor)
|
||||
}
|
||||
|
||||
override fun setOption(key: String, value: String) {
|
||||
if (value != options!!.put(key, value)) {
|
||||
dirty = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearOption(key: String) {
|
||||
if (options!!.remove(key) != null) {
|
||||
dirty = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun getOptionValue(key: String) = options!!.get(key)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.configurationStore
|
||||
|
||||
import com.intellij.openapi.components.StateStorage
|
||||
import com.intellij.openapi.components.StateStorageOperation
|
||||
import com.intellij.openapi.components.StoragePathMacros
|
||||
import com.intellij.openapi.components.TrackingPathMacroSubstitutor
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
|
||||
class ModuleStateStorageManager(pathMacroManager: TrackingPathMacroSubstitutor, private val myModule: Module) : StateStorageManagerImpl(pathMacroManager, "module", myModule, myModule.getPicoContainer()) {
|
||||
override fun createStorageData(fileSpec: String, filePath: String) = ModuleFileData(rootTagName, myModule)
|
||||
|
||||
override fun startExternalization() = MyStateStorageManagerExternalizationSession(this)
|
||||
|
||||
private class MyStateStorageManagerExternalizationSession(storageManager: StateStorageManagerImpl) : StateStorageManagerImpl.StateStorageManagerExternalizationSession(storageManager) {
|
||||
override fun createSaveSessions(): List<StateStorage.SaveSession> {
|
||||
val storage = ContainerUtil.getFirstItem(storageManager.getCachedFileStorages(listOf(StoragePathMacros.MODULE_FILE)))
|
||||
if (storage != null && storage.getStorageData().isDirty()) {
|
||||
// force XmlElementStorageSaveSession creation
|
||||
getExternalizationSession(storage)
|
||||
}
|
||||
return super.createSaveSessions()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation) = StoragePathMacros.MODULE_FILE
|
||||
|
||||
override fun createStorageTopicListener() = myModule.getProject().getMessageBus().syncPublisher(StateStorage.PROJECT_STORAGE_TOPIC)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.configurationStore
|
||||
|
||||
import com.intellij.openapi.components.PathMacroManager
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.ex.ProjectEx
|
||||
|
||||
class ModuleStoreImpl(private val myModule: Module, pathMacroManager: PathMacroManager) : BaseFileConfigurableStoreImpl(pathMacroManager) {
|
||||
override fun getProject() = myModule.getProject()
|
||||
|
||||
override fun optimizeTestLoading() = (myModule.getProject() as ProjectEx).isOptimiseTestLoadSpeed()
|
||||
|
||||
override fun getMessageBus() = myModule.getMessageBus()
|
||||
|
||||
override fun createStorageManager() = ModuleStateStorageManager(pathMacroManager.createTrackingSubstitutor(), myModule)
|
||||
}
|
||||
+6
-7
@@ -13,14 +13,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.components.impl.stores;
|
||||
package com.intellij.configurationStore
|
||||
|
||||
import com.intellij.openapi.project.impl.ProjectStoreClassProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.intellij.openapi.components.impl.stores.IComponentStore
|
||||
import com.intellij.openapi.project.impl.ProjectStoreClassProvider
|
||||
|
||||
public class PlatformProjectStoreClassProvider implements ProjectStoreClassProvider {
|
||||
@NotNull
|
||||
public Class<? extends IComponentStore> getProjectStoreClass(boolean isDefaultProject) {
|
||||
return isDefaultProject ? DefaultProjectStoreImpl.class : ProjectStoreImpl.class;
|
||||
class PlatformProjectStoreClassProvider : ProjectStoreClassProvider {
|
||||
override fun getProjectStoreClass(isDefaultProject: Boolean): Class<out IComponentStore> {
|
||||
return if (isDefaultProject) javaClass<DefaultProjectStoreImpl>() else javaClass<ProjectStoreImpl>()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.configurationStore
|
||||
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.project.impl.ProjectImpl
|
||||
import org.jdom.Element
|
||||
|
||||
class ProjectStateStorageManager(macroSubstitutor: TrackingPathMacroSubstitutor, private val project: ProjectImpl) : StateStorageManagerImpl(macroSubstitutor, "project", project, project.getPicoContainer()) {
|
||||
override fun createStorageData(fileSpec: String, filePath: String) = ProjectStorageData(rootTagName)
|
||||
|
||||
override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String? {
|
||||
val workspace = project.isWorkspaceComponent(component.javaClass)
|
||||
var fileSpec = if (workspace) StoragePathMacros.WORKSPACE_FILE else StoragePathMacros.PROJECT_FILE
|
||||
val storage = getStateStorage(fileSpec, if (workspace) RoamingType.DISABLED else RoamingType.PER_USER)
|
||||
if (operation === StateStorageOperation.READ && storage != null && workspace && !storage.hasState(component, componentName, javaClass<Element>(), false)) {
|
||||
fileSpec = StoragePathMacros.PROJECT_FILE
|
||||
}
|
||||
return fileSpec
|
||||
}
|
||||
|
||||
override fun createStorageTopicListener() = project.getMessageBus().syncPublisher(StateStorage.PROJECT_STORAGE_TOPIC)
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* 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.configurationStore
|
||||
|
||||
import com.intellij.ide.highlighter.ProjectFileType
|
||||
import com.intellij.ide.highlighter.WorkspaceFileType
|
||||
import com.intellij.notification.Notifications
|
||||
import com.intellij.notification.NotificationsManager
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.application.ReadAction
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.components.StateStorage.SaveSession
|
||||
import com.intellij.openapi.components.impl.stores.*
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.impl.ProjectImpl
|
||||
import com.intellij.openapi.project.impl.ProjectManagerImpl.UnableToSaveProjectNotification
|
||||
import com.intellij.openapi.util.Pair
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.*
|
||||
import com.intellij.util.PathUtilRt
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.lang.CompoundRuntimeException
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.util.ArrayList
|
||||
|
||||
open class ProjectStoreImpl(protected var myProject: ProjectImpl, pathMacroManager: PathMacroManager) : BaseFileConfigurableStoreImpl(pathMacroManager), IProjectStore {
|
||||
// protected setter used in upsource
|
||||
private var scheme = StorageScheme.DEFAULT
|
||||
protected set
|
||||
|
||||
private var presentableUrl: String? = null
|
||||
|
||||
override fun getSubstitutors(): Array<TrackingPathMacroSubstitutor> {
|
||||
val substitutor = getStateStorageManager().getMacroSubstitutor()
|
||||
return if (substitutor == null) emptyArray() else arrayOf(substitutor)
|
||||
}
|
||||
|
||||
override fun optimizeTestLoading() = myProject.isOptimiseTestLoadSpeed()
|
||||
|
||||
override fun getProject() = myProject
|
||||
|
||||
override fun setProjectFilePath(filePath: String) {
|
||||
val stateStorageManager = getStateStorageManager()
|
||||
val fs = LocalFileSystem.getInstance()
|
||||
|
||||
val file = File(filePath)
|
||||
if (isIprPath(file)) {
|
||||
scheme = StorageScheme.DEFAULT
|
||||
|
||||
stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, filePath)
|
||||
|
||||
val workspacePath = composeWsPath(filePath)
|
||||
stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, workspacePath)
|
||||
|
||||
ApplicationManager.getApplication().invokeAndWait(object : Runnable {
|
||||
override fun run() {
|
||||
VfsUtil.markDirtyAndRefresh(false, true, false, fs.refreshAndFindFileByPath(filePath), fs.refreshAndFindFileByPath(workspacePath))
|
||||
}
|
||||
}, ModalityState.defaultModalityState())
|
||||
}
|
||||
else {
|
||||
scheme = StorageScheme.DIRECTORY_BASED
|
||||
|
||||
val dirStore = File(if (file.isDirectory()) file else file.getParentFile(), Project.DIRECTORY_STORE_FOLDER)
|
||||
stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, File(dirStore, "misc.xml").getPath())
|
||||
stateStorageManager.addMacro(StoragePathMacros.PROJECT_CONFIG_DIR, dirStore.getPath())
|
||||
|
||||
val workspace = File(dirStore, "workspace.xml")
|
||||
stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, workspace.getPath())
|
||||
if (!workspace.exists() && !file.isDirectory()) {
|
||||
useOldWorkspaceContent(filePath, workspace)
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().invokeAndWait(object : Runnable {
|
||||
override fun run() {
|
||||
VfsUtil.markDirtyAndRefresh(false, true, true, fs.refreshAndFindFileByIoFile(dirStore))
|
||||
}
|
||||
}, ModalityState.defaultModalityState())
|
||||
}
|
||||
|
||||
presentableUrl = null
|
||||
}
|
||||
|
||||
override fun getProjectBaseDir(): VirtualFile? {
|
||||
if (myProject.isDefault()) {
|
||||
return null
|
||||
}
|
||||
val path = getProjectBasePath() ?: return null
|
||||
return LocalFileSystem.getInstance().findFileByPath(path)
|
||||
}
|
||||
|
||||
override fun getProjectBasePath(): String? {
|
||||
if (myProject.isDefault()) {
|
||||
return null
|
||||
}
|
||||
|
||||
val path = getProjectFilePath()
|
||||
if (!StringUtil.isEmptyOrSpaces(path)) {
|
||||
return getBasePath(File(path))
|
||||
}
|
||||
|
||||
//we are not yet initialized completely ("open directory", etc)
|
||||
val storage = getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER)
|
||||
return if (storage is FileBasedStorage) getBasePath(storage.getFile()) else null
|
||||
}
|
||||
|
||||
private fun getBasePath(file: File) = if (scheme == StorageScheme.DEFAULT) file.getParent() else file.getParentFile()?.getParent()
|
||||
|
||||
override fun getProjectName(): String {
|
||||
if (scheme == StorageScheme.DIRECTORY_BASED) {
|
||||
val baseDir = getProjectBaseDir()
|
||||
assert(baseDir != null) { "scheme=$scheme project file=${getProjectFilePath()}" }
|
||||
|
||||
val ideaDir = baseDir!!.findChild(Project.DIRECTORY_STORE_FOLDER)
|
||||
if (ideaDir != null && ideaDir.isValid()) {
|
||||
val nameFile = ideaDir.findChild(ProjectImpl.NAME_FILE)
|
||||
if (nameFile != null && nameFile.isValid()) {
|
||||
try {
|
||||
val `in` = BufferedReader(InputStreamReader(nameFile.getInputStream(), CharsetToolkit.UTF8_CHARSET))
|
||||
try {
|
||||
val name = `in`.readLine()
|
||||
if (name != null && !name.isEmpty()) {
|
||||
return name.trim()
|
||||
}
|
||||
}
|
||||
finally {
|
||||
`in`.close()
|
||||
}
|
||||
}
|
||||
catch (ignored: IOException) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return baseDir.getName().replace(":", "")
|
||||
}
|
||||
else {
|
||||
var temp = PathUtilRt.getFileName((getProjectFileStorage() as FileBasedStorage).getFilePath())
|
||||
val fileType = FileTypeManager.getInstance().getFileTypeByFileName(temp)
|
||||
if (fileType is ProjectFileType) {
|
||||
temp = temp.substring(0, temp.length() - fileType.getDefaultExtension().length() - 1)
|
||||
}
|
||||
val i = temp.lastIndexOf(File.separatorChar)
|
||||
if (i >= 0) {
|
||||
temp = temp.substring(i + 1, temp.length() - i + 1)
|
||||
}
|
||||
return temp
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStorageScheme() = scheme
|
||||
|
||||
override fun getPresentableUrl(): String? {
|
||||
if (myProject.isDefault()) {
|
||||
return null
|
||||
}
|
||||
if (presentableUrl == null) {
|
||||
val url = if (scheme == StorageScheme.DIRECTORY_BASED) getProjectBasePath() else getProjectFilePath()
|
||||
if (url != null) {
|
||||
presentableUrl = FileUtil.toSystemDependentName(url)
|
||||
}
|
||||
}
|
||||
return presentableUrl
|
||||
}
|
||||
|
||||
override fun getProjectFile() = if (myProject.isDefault()) null else (getProjectFileStorage() as FileBasedStorage).getVirtualFile()
|
||||
|
||||
override fun getProjectFilePath() = if (myProject.isDefault()) "" else (getProjectFileStorage() as FileBasedStorage).getFilePath()
|
||||
|
||||
// XmlElementStorage if default project, otherwise FileBasedStorage
|
||||
private fun getProjectFileStorage() = getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER) as XmlElementStorage
|
||||
|
||||
override fun getWorkspaceFile(): VirtualFile? {
|
||||
if (myProject.isDefault()) return null
|
||||
val storage = getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED) as FileBasedStorage?
|
||||
assert(storage != null)
|
||||
return storage!!.getVirtualFile()
|
||||
}
|
||||
|
||||
override fun getWorkspaceFilePath(): String? {
|
||||
if (myProject.isDefault()) {
|
||||
return null
|
||||
}
|
||||
return (getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED) as FileBasedStorage?)!!.getFilePath()
|
||||
}
|
||||
|
||||
override fun loadProjectFromTemplate(defaultProject: ProjectImpl) {
|
||||
defaultProject.save()
|
||||
|
||||
val element = (defaultProject.getStateStore() as DefaultProjectStoreImpl).getStateCopy()
|
||||
if (element != null) {
|
||||
getProjectFileStorage().setDefaultState(element)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createStorageManager(): StateStorageManager = ProjectStateStorageManager(pathMacroManager.createTrackingSubstitutor(), myProject)
|
||||
|
||||
override fun doSave(saveSessions: List<SaveSession>?, readonlyFiles: MutableList<Pair<SaveSession, VirtualFile>>, prevErrors: MutableList<Throwable>?): MutableList<Throwable>? {
|
||||
var errors = prevErrors
|
||||
beforeSave(readonlyFiles)
|
||||
|
||||
super<BaseFileConfigurableStoreImpl>.doSave(saveSessions, readonlyFiles, errors)
|
||||
|
||||
val notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(javaClass<UnableToSaveProjectNotification>(), myProject)
|
||||
if (readonlyFiles.isEmpty()) {
|
||||
for (notification in notifications) {
|
||||
notification.expire()
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
if (!notifications.isEmpty()) {
|
||||
throw IComponentStore.SaveCancelledException()
|
||||
}
|
||||
|
||||
val status: ReadonlyStatusHandler.OperationStatus
|
||||
val token = ReadAction.start()
|
||||
try {
|
||||
status = ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(*getFilesList(readonlyFiles))
|
||||
}
|
||||
finally {
|
||||
token.finish()
|
||||
}
|
||||
|
||||
if (status.hasReadonlyFiles()) {
|
||||
dropUnableToSaveProjectNotification(myProject, status.getReadonlyFiles())
|
||||
throw IComponentStore.SaveCancelledException()
|
||||
}
|
||||
val oldList = ArrayList(readonlyFiles)
|
||||
readonlyFiles.clear()
|
||||
for (entry in oldList) {
|
||||
errors = ComponentStoreImpl.executeSave(entry.first, readonlyFiles, errors)
|
||||
}
|
||||
|
||||
if (errors != null) {
|
||||
CompoundRuntimeException.doThrow(errors)
|
||||
}
|
||||
|
||||
if (!readonlyFiles.isEmpty()) {
|
||||
dropUnableToSaveProjectNotification(myProject, getFilesList(readonlyFiles))
|
||||
throw IComponentStore.SaveCancelledException()
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
protected open fun beforeSave(readonlyFiles: List<Pair<SaveSession, VirtualFile>>) {
|
||||
}
|
||||
|
||||
private var _defaultStorageChooser: StateStorageChooser<PersistentStateComponent<*>>? = null
|
||||
|
||||
override val defaultStorageChooser: StateStorageChooser<PersistentStateComponent<*>>?
|
||||
get() {
|
||||
if (_defaultStorageChooser == null) {
|
||||
_defaultStorageChooser = DefaultStorageChooser(scheme)
|
||||
}
|
||||
return _defaultStorageChooser
|
||||
}
|
||||
|
||||
override fun getMessageBus() = myProject.getMessageBus()
|
||||
|
||||
override fun <T> getComponentStorageSpecs(component: PersistentStateComponent<T>, stateSpec: State, operation: StateStorageOperation): Array<Storage> {
|
||||
// if we create project from default, component state written not to own storage file, but to project file,
|
||||
// we don't have time to fix it properly, so, ancient hack restored.
|
||||
val result = super<BaseFileConfigurableStoreImpl>.getComponentStorageSpecs(component, stateSpec, operation)
|
||||
// don't add fake storage if project file storage already listed, otherwise data will be deleted on write (because of "deprecated")
|
||||
for (storage in result) {
|
||||
if (storage.file == StoragePathMacros.PROJECT_FILE) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return Array(result.size() + 1) { if (it == result.size()) DEFAULT_STORAGE_ANNOTATION else result[it] }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DEFAULT_STORAGE_ANNOTATION = DefaultStorageAnnotation()
|
||||
|
||||
private fun isIprPath(file: File) = FileUtilRt.extensionEquals(file.getName(), ProjectFileType.DEFAULT_EXTENSION)
|
||||
|
||||
private fun composeWsPath(filePath: String): String {
|
||||
val lastDot = filePath.lastIndexOf('.')
|
||||
val filePathWithoutExt = if (lastDot > 0) filePath.substring(0, lastDot) else filePath
|
||||
return "$filePathWithoutExt${WorkspaceFileType.DOT_DEFAULT_EXTENSION}"
|
||||
}
|
||||
|
||||
private fun useOldWorkspaceContent(filePath: String, ws: File) {
|
||||
val oldWs = File(composeWsPath(filePath))
|
||||
if (!oldWs.exists()) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
FileUtil.copyContent(oldWs, ws)
|
||||
}
|
||||
catch (e: IOException) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun dropUnableToSaveProjectNotification(project: Project, readOnlyFiles: Array<VirtualFile>) {
|
||||
val notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(javaClass<UnableToSaveProjectNotification>(), project)
|
||||
if (notifications.isEmpty()) {
|
||||
Notifications.Bus.notify(UnableToSaveProjectNotification(project, readOnlyFiles), project)
|
||||
}
|
||||
else {
|
||||
notifications[0].myFiles = readOnlyFiles
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFilesList(readonlyFiles: List<Pair<SaveSession, VirtualFile>>) = Array(readonlyFiles.size()) { readonlyFiles.get(it).second }
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultStorageChooser(private val scheme: StorageScheme) : StateStorageChooser<PersistentStateComponent<*>> {
|
||||
override fun selectStorages(storages: Array<Storage>, component: PersistentStateComponent<*>, operation: StateStorageOperation): Array<Storage> {
|
||||
if (operation === StateStorageOperation.READ) {
|
||||
val result = SmartList<Storage>()
|
||||
for (i in storages.indices.reversed()) {
|
||||
val storage = storages[i]
|
||||
if (storage.scheme == scheme) {
|
||||
result.add(storage)
|
||||
}
|
||||
}
|
||||
|
||||
for (storage in storages) {
|
||||
if (storage.scheme == StorageScheme.DEFAULT && !result.contains(storage)) {
|
||||
result.add(storage)
|
||||
}
|
||||
}
|
||||
|
||||
return result.toTypedArray()
|
||||
}
|
||||
else if (operation == StateStorageOperation.WRITE) {
|
||||
val result = SmartList<Storage>()
|
||||
for (storage in storages) {
|
||||
if (storage.scheme == scheme) {
|
||||
result.add(storage)
|
||||
}
|
||||
}
|
||||
|
||||
if (result.isEmpty()) {
|
||||
for (storage in storages) {
|
||||
if (storage.scheme == StorageScheme.DEFAULT) {
|
||||
result.add(storage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.toTypedArray()
|
||||
}
|
||||
else {
|
||||
return emptyArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.configurationStore
|
||||
|
||||
import com.intellij.openapi.components.PathMacroManager
|
||||
import com.intellij.openapi.components.StateStorage
|
||||
import com.intellij.openapi.components.StateStorage.SaveSession
|
||||
import com.intellij.openapi.components.TrackingPathMacroSubstitutor
|
||||
import com.intellij.openapi.components.impl.stores.IComponentStore
|
||||
import com.intellij.openapi.components.stateStore
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.project.impl.ProjectImpl
|
||||
import com.intellij.openapi.project.impl.ProjectStoreClassProvider
|
||||
import com.intellij.openapi.util.Pair
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
|
||||
class PlatformLangProjectStoreClassProvider : ProjectStoreClassProvider {
|
||||
override fun getProjectStoreClass(isDefaultProject: Boolean): Class<out IComponentStore> {
|
||||
return if (isDefaultProject) javaClass<DefaultProjectStoreImpl>() else javaClass<ProjectWithModulesStoreImpl>()
|
||||
}
|
||||
}
|
||||
|
||||
class ProjectWithModulesStoreImpl(project: ProjectImpl, pathMacroManager: PathMacroManager) : ProjectStoreImpl(project, pathMacroManager) {
|
||||
override fun reinitComponent(componentName: String, changedStorages: Set<StateStorage>): Boolean {
|
||||
if (super.reinitComponent(componentName, changedStorages)) {
|
||||
return true
|
||||
}
|
||||
|
||||
for (module in getPersistentModules()) {
|
||||
// we have to reinit all modules for component because we don't know affected module
|
||||
module.stateStore.reinitComponent(componentName, changedStorages)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getSubstitutors(): Array<TrackingPathMacroSubstitutor> {
|
||||
val result = SmartList<TrackingPathMacroSubstitutor>()
|
||||
ContainerUtil.addIfNotNull(result, getStateStorageManager().getMacroSubstitutor())
|
||||
|
||||
for (module in getPersistentModules()) {
|
||||
ContainerUtil.addIfNotNull(result, module.stateStore.getStateStorageManager().getMacroSubstitutor())
|
||||
}
|
||||
return result.toTypedArray()
|
||||
}
|
||||
|
||||
override fun isReloadPossible(componentNames: Set<String>): Boolean {
|
||||
if (!super.isReloadPossible(componentNames)) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (module in getPersistentModules()) {
|
||||
if (!module.stateStore.isReloadPossible(componentNames)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getPersistentModules() = ModuleManager.getInstance(myProject)?.getModules() ?: Module.EMPTY_ARRAY
|
||||
|
||||
override protected fun beforeSave(readonlyFiles: List<Pair<SaveSession, VirtualFile>>) {
|
||||
super.beforeSave(readonlyFiles)
|
||||
|
||||
for (module in getPersistentModules()) {
|
||||
module.stateStore.save(readonlyFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,6 @@ import com.intellij.openapi.components.impl.stores.DirectoryStorageData
|
||||
import com.intellij.openapi.components.impl.stores.StorageUtil
|
||||
import com.intellij.openapi.components.impl.stores.StreamProvider
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.extensions.AbstractExtensionPointBean
|
||||
import com.intellij.openapi.options.*
|
||||
import com.intellij.openapi.util.Comparing
|
||||
@@ -54,8 +53,6 @@ import java.io.InputStream
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
|
||||
private val LOG = Logger.getInstance(javaClass<SchemeManagerImpl<*, *>>())
|
||||
|
||||
public class SchemeManagerImpl<T : Scheme, E : ExternalizableScheme>(private val fileSpec: String,
|
||||
private val processor: SchemeProcessor<E>,
|
||||
private val roamingType: RoamingType,
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* 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.configurationStore
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.components.StateStorage.SaveSession
|
||||
import com.intellij.openapi.components.StateStorageChooserEx.Resolution
|
||||
import com.intellij.openapi.components.impl.stores.*
|
||||
import com.intellij.openapi.util.Couple
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.util.PathUtilRt
|
||||
import com.intellij.util.ReflectionUtil
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import gnu.trove.THashMap
|
||||
import org.jdom.Element
|
||||
import org.picocontainer.MutablePicoContainer
|
||||
import org.picocontainer.PicoContainer
|
||||
import java.io.File
|
||||
import java.util.LinkedHashMap
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.concurrent.withLock
|
||||
import kotlin.reflect.jvm.java
|
||||
|
||||
abstract class StateStorageManagerImpl(private val pathMacroSubstitutor: TrackingPathMacroSubstitutor, protected val rootTagName: String, parentDisposable: Disposable, private val picoContainer: PicoContainer) : StateStorageManager, Disposable {
|
||||
private val macros = LinkedHashMap<String, String>()
|
||||
private val storageLock = ReentrantLock()
|
||||
private val storages = THashMap<String, StateStorage>()
|
||||
|
||||
private var streamProvider: StreamProvider? = null
|
||||
|
||||
init {
|
||||
Disposer.register(parentDisposable, this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val MACRO_PATTERN = Pattern.compile("(\\$[^\\$]*\\$)")
|
||||
}
|
||||
|
||||
override fun getStreamProvider() = streamProvider
|
||||
|
||||
override fun setStreamProvider(value: StreamProvider?) {
|
||||
streamProvider = value
|
||||
}
|
||||
|
||||
override fun getMacroSubstitutor() = pathMacroSubstitutor
|
||||
|
||||
synchronized override fun addMacro(macro: String, expansion: String) {
|
||||
assert(!macro.isEmpty())
|
||||
macros.put(macro, expansion)
|
||||
}
|
||||
|
||||
override fun getStateStorage(storageSpec: Storage): StateStorage {
|
||||
@suppress("USELESS_CAST")
|
||||
val storageClass = storageSpec.storageClass.java as Class<out StateStorage>
|
||||
val key = if (storageClass == javaClass<StateStorage>()) storageSpec.file else storageClass.getName()
|
||||
|
||||
storageLock.withLock {
|
||||
var stateStorage: StateStorage? = storages.get(key)
|
||||
if (stateStorage == null) {
|
||||
stateStorage = createStateStorage(storageClass, storageSpec.file, storageSpec.roamingType, storageSpec.stateSplitter.java)
|
||||
storages.put(key, stateStorage)
|
||||
}
|
||||
return stateStorage
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStateStorage(fileSpec: String, roamingType: RoamingType): StateStorage? {
|
||||
storageLock.withLock {
|
||||
var stateStorage: StateStorage? = storages.get(fileSpec)
|
||||
if (stateStorage == null) {
|
||||
stateStorage = createStateStorage(javaClass<StateStorage>(), fileSpec, roamingType, javaClass<StateSplitterEx>())
|
||||
storages.put(fileSpec, stateStorage)
|
||||
}
|
||||
return stateStorage
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCachedFileStateStorages(changed: Collection<String>, deleted: Collection<String>) = storageLock.withLock { Couple.of(getCachedFileStorages(changed), getCachedFileStorages(deleted)) }
|
||||
|
||||
fun getCachedFileStorages(fileSpecs: Collection<String>): Collection<FileBasedStorage> {
|
||||
if (fileSpecs.isEmpty()) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
var result: MutableList<FileBasedStorage>? = null
|
||||
for (fileSpec in fileSpecs) {
|
||||
val storage = storages.get(fileSpec)
|
||||
if (storage is FileBasedStorage) {
|
||||
if (result == null) {
|
||||
result = SmartList<FileBasedStorage>()
|
||||
}
|
||||
result.add(storage)
|
||||
}
|
||||
}
|
||||
return result ?: emptyList<FileBasedStorage>()
|
||||
}
|
||||
|
||||
override fun getStorageFileNames() = storageLock.withLock { storages.keySet() }
|
||||
|
||||
// overridden in upsource
|
||||
protected fun createStateStorage(storageClass: Class<out StateStorage>, fileSpec: String, roamingType: RoamingType, SuppressWarnings("deprecation") stateSplitter: Class<out StateSplitter>): StateStorage {
|
||||
if (storageClass != javaClass<StateStorage>()) {
|
||||
val key = UUID.randomUUID().toString()
|
||||
(picoContainer as MutablePicoContainer).registerComponentImplementation(key, storageClass)
|
||||
return picoContainer.getComponentInstance(key) as StateStorage
|
||||
}
|
||||
|
||||
val filePath = expandMacros(fileSpec)
|
||||
val file = File(filePath)
|
||||
|
||||
//noinspection deprecation
|
||||
if (stateSplitter != javaClass<StateSplitter>() && stateSplitter != javaClass<StateSplitterEx>()) {
|
||||
return DirectoryBasedStorage(pathMacroSubstitutor, file, ReflectionUtil.newInstance(stateSplitter), this, createStorageTopicListener())
|
||||
}
|
||||
|
||||
if (!ApplicationManager.getApplication().isHeadlessEnvironment() && PathUtilRt.getFileName(filePath).lastIndexOf('.') < 0) {
|
||||
throw IllegalArgumentException("Extension is missing for storage file: " + filePath)
|
||||
}
|
||||
|
||||
val effectiveRoamingType = if (roamingType == RoamingType.PER_USER && fileSpec == StoragePathMacros.WORKSPACE_FILE) RoamingType.DISABLED else roamingType
|
||||
beforeFileBasedStorageCreate()
|
||||
return object : FileBasedStorage(file, fileSpec, effectiveRoamingType, getMacroSubstitutor(fileSpec), rootTagName, this@StateStorageManagerImpl, createStorageTopicListener(), streamProvider) {
|
||||
override fun createStorageData() = this@StateStorageManagerImpl.createStorageData(myFileSpec, getFilePath())
|
||||
|
||||
override fun isUseXmlProlog() = this@StateStorageManagerImpl.isUseXmlProlog()
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearStateStorage(file: String) {
|
||||
storageLock.withLock { storages.remove(file) }
|
||||
}
|
||||
|
||||
protected open fun createStorageTopicListener(): StateStorage.Listener? = null
|
||||
|
||||
protected open fun isUseXmlProlog(): Boolean = true
|
||||
|
||||
protected open fun beforeFileBasedStorageCreate() {
|
||||
}
|
||||
|
||||
protected open fun getMacroSubstitutor(fileSpec: String): TrackingPathMacroSubstitutor? = pathMacroSubstitutor
|
||||
|
||||
protected abstract fun createStorageData(fileSpec: String, filePath: String): StorageData
|
||||
|
||||
synchronized override fun expandMacros(file: String): String {
|
||||
val matcher = MACRO_PATTERN.matcher(file)
|
||||
while (matcher.find()) {
|
||||
val m = matcher.group(1)
|
||||
if (!macros.containsKey(m)) {
|
||||
throw IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file)
|
||||
}
|
||||
}
|
||||
|
||||
var expanded = file
|
||||
for (entry in macros.entrySet()) {
|
||||
expanded = StringUtil.replace(expanded, entry.getKey(), entry.getValue())
|
||||
}
|
||||
return expanded
|
||||
}
|
||||
|
||||
override fun collapseMacros(path: String): String {
|
||||
var result = path
|
||||
for (entry in macros.entrySet()) {
|
||||
result = StringUtil.replace(result, entry.getValue(), entry.getKey())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun startExternalization() = StateStorageManagerExternalizationSession(this)
|
||||
|
||||
open class StateStorageManagerExternalizationSession(protected val storageManager: StateStorageManagerImpl) : StateStorageManager.ExternalizationSession {
|
||||
private val mySessions = LinkedHashMap<StateStorage, StateStorage.ExternalizationSession>()
|
||||
|
||||
override fun setState(storageSpecs: Array<Storage>, component: Any, componentName: String, state: Any) {
|
||||
val stateStorageChooser = if (component is StateStorageChooserEx) component else null
|
||||
for (storageSpec in storageSpecs) {
|
||||
val resolution = if (stateStorageChooser == null) Resolution.DO else stateStorageChooser.getResolution(storageSpec, StateStorageOperation.WRITE)
|
||||
if (resolution === Resolution.SKIP) {
|
||||
continue
|
||||
}
|
||||
|
||||
val stateStorage = storageManager.getStateStorage(storageSpec)
|
||||
val session = getExternalizationSession(stateStorage)
|
||||
session?.setState(component, componentName, if (storageSpec.deprecated || resolution === Resolution.CLEAR) Element("empty") else state, storageSpec)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setStateInOldStorage(component: Any, componentName: String, state: Any) {
|
||||
val stateStorage = storageManager.getOldStorage(component, componentName, StateStorageOperation.WRITE)
|
||||
if (stateStorage != null) {
|
||||
val session = getExternalizationSession(stateStorage)
|
||||
session?.setState(component, componentName, state, null)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun getExternalizationSession(stateStorage: StateStorage): StateStorage.ExternalizationSession? {
|
||||
var session: StateStorage.ExternalizationSession? = mySessions.get(stateStorage)
|
||||
if (session == null) {
|
||||
session = stateStorage.startExternalization()
|
||||
if (session != null) {
|
||||
mySessions.put(stateStorage, session)
|
||||
}
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
override fun createSaveSessions(): List<SaveSession> {
|
||||
if (mySessions.isEmpty()) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
var saveSessions: MutableList<SaveSession>? = null
|
||||
val externalizationSessions = mySessions.values()
|
||||
for (session in externalizationSessions) {
|
||||
val saveSession = session.createSaveSession()
|
||||
if (saveSession != null) {
|
||||
if (saveSessions == null) {
|
||||
if (externalizationSessions.size() == 1) {
|
||||
return listOf(saveSession)
|
||||
}
|
||||
saveSessions = SmartList<SaveSession>()
|
||||
}
|
||||
saveSessions.add(saveSession)
|
||||
}
|
||||
}
|
||||
return ContainerUtil.notNullize(saveSessions)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getOldStorage(component: Any, componentName: String, operation: StateStorageOperation): StateStorage? {
|
||||
val oldStorageSpec = getOldStorageSpec(component, componentName, operation)
|
||||
@suppress("DEPRECATED_SYMBOL_WITH_MESSAGE")
|
||||
return if (oldStorageSpec == null) null else getStateStorage(oldStorageSpec, if (component is com.intellij.openapi.util.RoamingTypeDisabled) RoamingType.DISABLED else RoamingType.PER_USER)
|
||||
}
|
||||
|
||||
protected abstract fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String?
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package com.intellij.configurationStore;
|
||||
|
||||
import com.intellij.openapi.components.PathMacroManager;
|
||||
import com.intellij.openapi.components.RoamingType;
|
||||
import com.intellij.openapi.components.impl.stores.StorageData;
|
||||
import com.intellij.openapi.components.impl.stores.XmlElementStorage;
|
||||
import com.intellij.openapi.project.impl.ProjectManagerImpl;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class DefaultProjectStorage extends XmlElementStorage {
|
||||
private final DefaultProjectStoreImpl store;
|
||||
private final ProjectManagerImpl projectManager;
|
||||
|
||||
public DefaultProjectStorage(DefaultProjectStoreImpl store, PathMacroManager pathMacroManager, ProjectManagerImpl projectManager) {
|
||||
super("", RoamingType.DISABLED, pathMacroManager.createTrackingSubstitutor(), "defaultProject", null);
|
||||
|
||||
this.store = store;
|
||||
this.projectManager = projectManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected Element loadLocalData() {
|
||||
return store.getStateCopy();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected XmlElementStorageSaveSession createSaveSession(@NotNull StorageData storageData) {
|
||||
return new XmlElementStorageSaveSession(storageData) {
|
||||
@Override
|
||||
protected void doSave(@Nullable Element element) {
|
||||
// we must set empty element instead of null as indicator - ProjectManager state is ready to save
|
||||
projectManager.setDefaultProjectRootElement(element == null ? new Element("empty") : element);
|
||||
}
|
||||
|
||||
// we must not collapse paths here, because our solution is just a big hack
|
||||
// by default, getElementToSave() returns collapsed paths -> setDefaultProjectRootElement -> project manager writeExternal -> save -> compare old and new - diff because old has expanded, but new collapsed
|
||||
// -> needless save
|
||||
@Override
|
||||
protected boolean isCollapsePathsOnSave() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected StorageData createStorageData() {
|
||||
return new StorageData(myRootElementName);
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.intellij.configurationStore;
|
||||
|
||||
import com.intellij.openapi.components.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
@SuppressWarnings("ClassExplicitlyAnnotation")
|
||||
public final class DefaultStorageAnnotation implements Storage {
|
||||
@Override
|
||||
public String id() {
|
||||
return "___Default___";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String file() {
|
||||
return StoragePathMacros.PROJECT_FILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageScheme scheme() {
|
||||
return StorageScheme.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deprecated() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoamingType roamingType() {
|
||||
return RoamingType.PER_USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends StateStorage> storageClass() {
|
||||
return StateStorage.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<StateSplitterEx> stateSplitter() {
|
||||
return StateSplitterEx.class;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
throw new UnsupportedOperationException("Method annotationType not implemented in " + getClass());
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.components.impl;
|
||||
|
||||
/**
|
||||
* @author mike
|
||||
*/
|
||||
public class ApplicationPathMacroManager extends BasePathMacroManager {
|
||||
public ApplicationPathMacroManager() {
|
||||
super(null);
|
||||
}
|
||||
}
|
||||
-113
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* 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.components.impl.stores;
|
||||
|
||||
import com.intellij.application.options.PathMacrosImpl;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.application.impl.ApplicationImpl;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.NamedJDOMExternalizable;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
class ApplicationStoreImpl extends ComponentStoreImpl {
|
||||
private static final Logger LOG = Logger.getInstance(ApplicationStoreImpl.class);
|
||||
|
||||
private static final String DEFAULT_STORAGE_SPEC = StoragePathMacros.APP_CONFIG + "/" + PathManager.DEFAULT_OPTIONS_FILE_NAME + DirectoryStorageData.DEFAULT_EXT;
|
||||
private static final String ROOT_ELEMENT_NAME = "application";
|
||||
|
||||
private final ApplicationImpl myApplication;
|
||||
private final StateStorageManager myStateStorageManager;
|
||||
|
||||
public ApplicationStoreImpl(@NotNull ApplicationImpl application, @NotNull PathMacroManager pathMacroManager) {
|
||||
myApplication = application;
|
||||
myStateStorageManager = new StateStorageManagerImpl(pathMacroManager.createTrackingSubstitutor(), ROOT_ELEMENT_NAME, application, application.getPicoContainer()) {
|
||||
private boolean myConfigDirectoryRefreshed;
|
||||
|
||||
@Nullable
|
||||
protected StateStorage.Listener createStorageTopicListener() {
|
||||
return myApplication.getMessageBus().syncPublisher(StateStorage.STORAGE_TOPIC);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath) {
|
||||
return new StorageData(ROOT_ELEMENT_NAME);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) {
|
||||
if (component instanceof NamedJDOMExternalizable) {
|
||||
return StoragePathMacros.APP_CONFIG + '/' + ((NamedJDOMExternalizable)component).getExternalFileName() + DirectoryStorageData.DEFAULT_EXT;
|
||||
}
|
||||
else {
|
||||
return DEFAULT_STORAGE_SPEC;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TrackingPathMacroSubstitutor getMacroSubstitutor(@NotNull String fileSpec) {
|
||||
return fileSpec.equals(StoragePathMacros.APP_CONFIG + '/' + PathMacrosImpl.EXT_FILE_NAME + DirectoryStorageData.DEFAULT_EXT) ? null : super.getMacroSubstitutor(fileSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isUseXmlProlog() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeFileBasedStorageCreate() {
|
||||
if (myConfigDirectoryRefreshed || (!myApplication.isUnitTestMode() && !myApplication.isDispatchThread())) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String configPath = getMacrosValue(StoragePathMacros.ROOT_CONFIG);
|
||||
if (configPath == null) {
|
||||
LOG.warn("Macros ROOT_CONFIG is not defined");
|
||||
return;
|
||||
}
|
||||
|
||||
VirtualFile configDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(configPath);
|
||||
if (configDir != null) {
|
||||
VfsUtil.markDirtyAndRefresh(false, true, true, configDir);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
myConfigDirectoryRefreshed = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected MessageBus getMessageBus() {
|
||||
return myApplication.getMessageBus();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public StateStorageManager getStateStorageManager() {
|
||||
return myStateStorageManager;
|
||||
}
|
||||
}
|
||||
-116
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* 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.components.impl.stores;
|
||||
|
||||
import com.intellij.openapi.components.PathMacroManager;
|
||||
import com.intellij.openapi.components.PathMacroSubstitutor;
|
||||
import com.intellij.openapi.project.impl.ProjectManagerImpl;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl {
|
||||
@NonNls protected static final String VERSION_OPTION = "version";
|
||||
@NonNls public static final String ATTRIBUTE_NAME = "name";
|
||||
|
||||
private static final List<String> ourConversionProblemsStorage = new SmartList<String>();
|
||||
|
||||
private StateStorageManager myStateStorageManager;
|
||||
protected final PathMacroManager myPathMacroManager;
|
||||
|
||||
protected BaseFileConfigurableStoreImpl(@NotNull PathMacroManager pathMacroManager) {
|
||||
myPathMacroManager = pathMacroManager;
|
||||
}
|
||||
|
||||
protected static class BaseStorageData extends StorageData {
|
||||
private int myVersion = ProjectManagerImpl.CURRENT_FORMAT_VERSION;
|
||||
|
||||
public BaseStorageData(@NotNull String rootElementName) {
|
||||
super(rootElementName);
|
||||
}
|
||||
|
||||
protected BaseStorageData(BaseStorageData storageData) {
|
||||
super(storageData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) {
|
||||
super.load(rootElement, pathMacroSubstitutor, intern);
|
||||
|
||||
String v = rootElement.getAttributeValue(VERSION_OPTION);
|
||||
myVersion = v == null ? ProjectManagerImpl.CURRENT_FORMAT_VERSION : Integer.parseInt(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected final Element save(@NotNull Map<String, Element> newLiveStates) {
|
||||
Element root = super.save(newLiveStates);
|
||||
if (root == null) {
|
||||
root = new Element(myRootElementName);
|
||||
}
|
||||
writeOptions(root, Integer.toString(myVersion));
|
||||
return root;
|
||||
}
|
||||
|
||||
protected void writeOptions(@NotNull Element root, @NotNull String versionString) {
|
||||
root.setAttribute(VERSION_OPTION, versionString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageData clone() {
|
||||
return new BaseStorageData(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Set<String> getChangedComponentNames(@NotNull StorageData newStorageData, @Nullable PathMacroSubstitutor substitutor) {
|
||||
BaseStorageData data = (BaseStorageData)newStorageData;
|
||||
if (myVersion != data.myVersion) {
|
||||
return null;
|
||||
}
|
||||
return super.getChangedComponentNames(newStorageData, substitutor);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static List<String> getConversionProblemsStorage() {
|
||||
return ourConversionProblemsStorage;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected final PathMacroManager getPathMacroManagerForDefaults() {
|
||||
return myPathMacroManager;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public final StateStorageManager getStateStorageManager() {
|
||||
if (myStateStorageManager == null) {
|
||||
myStateStorageManager = createStateStorageManager();
|
||||
}
|
||||
return myStateStorageManager;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract StateStorageManager createStateStorageManager();
|
||||
}
|
||||
-529
@@ -1,529 +0,0 @@
|
||||
/*
|
||||
* 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.components.impl.stores;
|
||||
|
||||
import com.intellij.openapi.application.*;
|
||||
import com.intellij.openapi.application.ex.DecodeDefaultsUtil;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.components.StateStorage.SaveSession;
|
||||
import com.intellij.openapi.components.StateStorageChooserEx.Resolution;
|
||||
import com.intellij.openapi.components.impl.ComponentManagerImpl;
|
||||
import com.intellij.openapi.components.impl.stores.StateStorageManager.ExternalizationSession;
|
||||
import com.intellij.openapi.components.store.ReadOnlyModificationException;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
|
||||
import com.intellij.util.ArrayUtilRt;
|
||||
import com.intellij.util.ReflectionUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.containers.SmartHashSet;
|
||||
import com.intellij.util.lang.CompoundRuntimeException;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import com.intellij.util.xmlb.JDOMXIncluder;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jdom.Element;
|
||||
import org.jdom.JDOMException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
@SuppressWarnings({"deprecation"})
|
||||
public abstract class ComponentStoreImpl implements IComponentStore {
|
||||
private static final Logger LOG = Logger.getInstance(ComponentStoreImpl.class);
|
||||
private final Map<String, Object> myComponents = Collections.synchronizedMap(new THashMap<String, Object>());
|
||||
private final List<SettingsSavingComponent> mySettingsSavingComponents = new CopyOnWriteArrayList<SettingsSavingComponent>();
|
||||
|
||||
@Override
|
||||
public void initComponent(@NotNull Object component, boolean service) {
|
||||
if (component instanceof SettingsSavingComponent) {
|
||||
mySettingsSavingComponents.add((SettingsSavingComponent)component);
|
||||
}
|
||||
|
||||
if (!(component instanceof JDOMExternalizable || component instanceof PersistentStateComponent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AccessToken token = ReadAction.start();
|
||||
try {
|
||||
String componentNameIfStateExists;
|
||||
if (component instanceof PersistentStateComponent) {
|
||||
componentNameIfStateExists = initPersistentComponent((PersistentStateComponent<?>)component, null, false);
|
||||
}
|
||||
else {
|
||||
componentNameIfStateExists = initJdomExternalizable((JDOMExternalizable)component);
|
||||
}
|
||||
|
||||
// if not service, so, component manager will check it later for all components
|
||||
if (componentNameIfStateExists != null && service) {
|
||||
Project project = getProject();
|
||||
Application app = ApplicationManager.getApplication();
|
||||
if (project != null && !app.isHeadlessEnvironment() && !app.isUnitTestMode() && project.isInitialized()) {
|
||||
TrackingPathMacroSubstitutor substitutor = getStateStorageManager().getMacroSubstitutor();
|
||||
if (substitutor != null) {
|
||||
StorageUtil.notifyUnknownMacros(substitutor, project, componentNameIfStateExists);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (StateStorageException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
finally {
|
||||
token.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void save(@NotNull List<Pair<StateStorage.SaveSession, VirtualFile>> readonlyFiles) {
|
||||
ExternalizationSession externalizationSession = myComponents.isEmpty() ? null : getStateStorageManager().startExternalization();
|
||||
if (externalizationSession != null) {
|
||||
String[] names = ArrayUtilRt.toStringArray(myComponents.keySet());
|
||||
Arrays.sort(names);
|
||||
for (String name : names) {
|
||||
commitComponent(externalizationSession, myComponents.get(name), name);
|
||||
}
|
||||
}
|
||||
|
||||
List<Throwable> errors = null;
|
||||
for (SettingsSavingComponent settingsSavingComponent : mySettingsSavingComponents) {
|
||||
try {
|
||||
settingsSavingComponent.save();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
if (errors == null) {
|
||||
errors = new SmartList<Throwable>();
|
||||
}
|
||||
errors.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
errors = doSave(externalizationSession == null ? null : externalizationSession.createSaveSessions(), readonlyFiles, errors);
|
||||
CompoundRuntimeException.doThrow(errors);
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
@Override
|
||||
public void saveApplicationComponent(@NotNull Object component) {
|
||||
StateStorageManager.ExternalizationSession externalizationSession = getStateStorageManager().startExternalization();
|
||||
if (externalizationSession == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
commitComponent(externalizationSession, component, null);
|
||||
List<SaveSession> sessions = externalizationSession.createSaveSessions();
|
||||
if (sessions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final File file;
|
||||
State state = StoreUtil.getStateSpec(component.getClass());
|
||||
if (state != null) {
|
||||
file = new File(getStateStorageManager().expandMacros(findNonDeprecated(state.storages()).file()));
|
||||
}
|
||||
else if (component instanceof ExportableApplicationComponent && component instanceof NamedJDOMExternalizable) {
|
||||
file = PathManager.getOptionsFile((NamedJDOMExternalizable)component);
|
||||
}
|
||||
else {
|
||||
throw new AssertionError(component.getClass() + " doesn't have @State annotation and doesn't implement ExportableApplicationComponent");
|
||||
}
|
||||
|
||||
AccessToken token = WriteAction.start();
|
||||
try {
|
||||
VfsRootAccess.allowRootAccess(file.getAbsolutePath());
|
||||
CompoundRuntimeException.doThrow(doSave(sessions, Collections.<Pair<SaveSession, VirtualFile>>emptyList(), null));
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
VfsRootAccess.disallowRootAccess(file.getAbsolutePath());
|
||||
}
|
||||
finally {
|
||||
token.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Storage findNonDeprecated(Storage[] storages) {
|
||||
for (Storage storage : storages) {
|
||||
if (!storage.deprecated()) {
|
||||
return storage;
|
||||
}
|
||||
}
|
||||
throw new AssertionError("All storages are deprecated");
|
||||
}
|
||||
|
||||
private void commitComponent(@NotNull ExternalizationSession externalizationSession, @NotNull Object component, @Nullable String componentName) {
|
||||
if (component instanceof PersistentStateComponent) {
|
||||
commitPersistentComponent((PersistentStateComponent<?>)component, externalizationSession, componentName);
|
||||
}
|
||||
else if (component instanceof JDOMExternalizable) {
|
||||
externalizationSession.setStateInOldStorage(component, componentName == null ? ComponentManagerImpl.getComponentName(component) : componentName, component);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected List<Throwable> doSave(@Nullable List<SaveSession> saveSessions, @NotNull List<Pair<SaveSession, VirtualFile>> readonlyFiles, @Nullable List<Throwable> errors) {
|
||||
if (saveSessions != null) {
|
||||
for (SaveSession session : saveSessions) {
|
||||
errors = executeSave(session, readonlyFiles, errors);
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static List<Throwable> executeSave(@NotNull SaveSession session, @NotNull List<Pair<SaveSession, VirtualFile>> readonlyFiles, @Nullable List<Throwable> errors) {
|
||||
try {
|
||||
session.save();
|
||||
}
|
||||
catch (ReadOnlyModificationException e) {
|
||||
LOG.warn(e);
|
||||
readonlyFiles.add(Pair.create(e.getSession() == null ? session : e.getSession(), e.getFile()));
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (errors == null) {
|
||||
errors = new SmartList<Throwable>();
|
||||
}
|
||||
errors.add(e);
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
private <T> void commitPersistentComponent(@NotNull PersistentStateComponent<T> component, @NotNull ExternalizationSession session, @Nullable String componentName) {
|
||||
T state = component.getState();
|
||||
if (state != null) {
|
||||
Storage[] storageSpecs = getComponentStorageSpecs(component, StoreUtil.getStateSpec(component), StateStorageOperation.WRITE);
|
||||
session.setState(storageSpecs, component, componentName == null ? StoreUtil.getComponentName(component) : componentName, state);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String initJdomExternalizable(@NotNull JDOMExternalizable component) {
|
||||
String componentName = ComponentManagerImpl.getComponentName(component);
|
||||
doAddComponent(componentName, component);
|
||||
|
||||
if (optimizeTestLoading()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
loadJdomDefaults(component, componentName);
|
||||
|
||||
StateStorage stateStorage = getStateStorageManager().getOldStorage(component, componentName, StateStorageOperation.READ);
|
||||
if (stateStorage == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Element element = stateStorage.getState(component, componentName, Element.class, null);
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Loading configuration for " + component.getClass());
|
||||
}
|
||||
component.readExternal(element);
|
||||
}
|
||||
catch (InvalidDataException e) {
|
||||
LOG.error(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return componentName;
|
||||
}
|
||||
|
||||
private void doAddComponent(String componentName, Object component) {
|
||||
Object existing = myComponents.get(componentName);
|
||||
if (existing != null && existing != component) {
|
||||
LOG.error("Conflicting component name '" + componentName + "': " + existing.getClass() + " and " + component.getClass());
|
||||
}
|
||||
myComponents.put(componentName, component);
|
||||
}
|
||||
|
||||
private void loadJdomDefaults(@NotNull JDOMExternalizable component, @NotNull String componentName) {
|
||||
try {
|
||||
Element defaultState = getDefaultState(component, componentName, Element.class);
|
||||
if (defaultState != null) {
|
||||
component.readExternal(defaultState);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error("Cannot load defaults for " + component.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Project getProject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T> String initPersistentComponent(@NotNull PersistentStateComponent<T> component, @Nullable Set<StateStorage> changedStorages, boolean reloadData) {
|
||||
State stateSpec = StoreUtil.getStateSpec(component);
|
||||
String name = stateSpec.name();
|
||||
if (changedStorages == null || !reloadData) {
|
||||
doAddComponent(name, component);
|
||||
}
|
||||
if (optimizeTestLoading()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<T> stateClass = ComponentSerializationUtil.getStateClass(component.getClass());
|
||||
if (!stateSpec.defaultStateAsResource() && LOG.isDebugEnabled() && getDefaultState(component, name, stateClass) != null) {
|
||||
LOG.error(name + " has default state, but not marked to load it");
|
||||
}
|
||||
|
||||
T state = stateSpec.defaultStateAsResource() ? getDefaultState(component, name, stateClass) : null;
|
||||
Storage[] storageSpecs = getComponentStorageSpecs(component, stateSpec, StateStorageOperation.READ);
|
||||
StateStorageChooserEx stateStorageChooser = component instanceof StateStorageChooserEx ? (StateStorageChooserEx)component : null;
|
||||
for (Storage storageSpec : storageSpecs) {
|
||||
Resolution resolution = stateStorageChooser == null ? Resolution.DO : stateStorageChooser.getResolution(storageSpec, StateStorageOperation.READ);
|
||||
if (resolution == Resolution.SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
StateStorage stateStorage = getStateStorageManager().getStateStorage(storageSpec);
|
||||
boolean forcedState = false;
|
||||
if (stateStorage != null && (stateStorage.hasState(component, name, stateClass, reloadData) ||
|
||||
(forcedState = changedStorages != null && changedStorages.contains(stateStorage)))) {
|
||||
state = stateStorage.getState(component, name, stateClass, state);
|
||||
if (state == null && forcedState) {
|
||||
// state will be null if file deleted
|
||||
// we must create empty (initial) state to reinit component
|
||||
state = DefaultStateSerializer.deserializeState(new Element("state"), stateClass, null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state != null) {
|
||||
component.loadState(state);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected PathMacroManager getPathMacroManagerForDefaults() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected <T> T getDefaultState(@NotNull Object component, @NotNull String componentName, @NotNull final Class<T> stateClass) {
|
||||
URL url = DecodeDefaultsUtil.getDefaults(component, componentName);
|
||||
if (url == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
Element documentElement = JDOMXIncluder.resolve(JDOMUtil.loadDocument(url), url.toExternalForm()).detachRootElement();
|
||||
|
||||
PathMacroManager pathMacroManager = getPathMacroManagerForDefaults();
|
||||
if (pathMacroManager != null) {
|
||||
pathMacroManager.expandPaths(documentElement);
|
||||
}
|
||||
|
||||
return DefaultStateSerializer.deserializeState(documentElement, stateClass, null);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new StateStorageException("Error loading state from " + url, e);
|
||||
}
|
||||
catch (JDOMException e) {
|
||||
throw new StateStorageException("Error loading state from " + url, e);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected <T> Storage[] getComponentStorageSpecs(@NotNull PersistentStateComponent<T> component,
|
||||
@NotNull State stateSpec,
|
||||
@NotNull StateStorageOperation operation) {
|
||||
Storage[] storages = stateSpec.storages();
|
||||
if (storages.length == 1) {
|
||||
return storages;
|
||||
}
|
||||
assert storages.length > 0;
|
||||
|
||||
StateStorageChooser<PersistentStateComponent<T>> storageChooser;
|
||||
Class<? extends StateStorageChooser> storageChooserClass = stateSpec.storageChooser();
|
||||
if (storageChooserClass != StateStorageChooser.class) {
|
||||
//noinspection unchecked
|
||||
storageChooser = ReflectionUtil.newInstance(storageChooserClass);
|
||||
return storageChooser.selectStorages(storages, component, operation);
|
||||
}
|
||||
|
||||
StateStorageChooser<PersistentStateComponent<?>> defaultStateStorageChooser = getDefaultStateStorageChooser();
|
||||
if (defaultStateStorageChooser != null) {
|
||||
return defaultStateStorageChooser.selectStorages(storages, component, operation);
|
||||
}
|
||||
|
||||
if (component instanceof StateStorageChooserEx) {
|
||||
return storages;
|
||||
}
|
||||
|
||||
int actualStorageCount = 0;
|
||||
for (Storage storage : storages) {
|
||||
if (!storage.deprecated()) {
|
||||
actualStorageCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (actualStorageCount > 1) {
|
||||
LOG.error("State chooser not specified for: " + component.getClass());
|
||||
}
|
||||
|
||||
if (!storages[0].deprecated()) {
|
||||
boolean othersAreDeprecated = true;
|
||||
for (int i = 1; i < storages.length; i++) {
|
||||
if (!storages[i].deprecated()) {
|
||||
othersAreDeprecated = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (othersAreDeprecated) {
|
||||
return storages;
|
||||
}
|
||||
}
|
||||
|
||||
Storage[] sorted = Arrays.copyOf(storages, storages.length);
|
||||
Arrays.sort(sorted, new Comparator<Storage>() {
|
||||
@Override
|
||||
public int compare(Storage o1, Storage o2) {
|
||||
int w1 = o1.deprecated() ? 1 : 0;
|
||||
int w2 = o2.deprecated() ? 1 : 0;
|
||||
return w1 - w2;
|
||||
}
|
||||
});
|
||||
return sorted;
|
||||
}
|
||||
|
||||
protected boolean optimizeTestLoading() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected StateStorageChooser<PersistentStateComponent<?>> getDefaultStateStorageChooser() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReloadPossible(@NotNull final Set<String> componentNames) {
|
||||
for (String componentName : componentNames) {
|
||||
final Object component = myComponents.get(componentName);
|
||||
if (component != null && (!(component instanceof PersistentStateComponent) || !StoreUtil.getStateSpec((PersistentStateComponent<?>)component).reloadable())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public final Collection<String> getNotReloadableComponents(@NotNull Collection<String> componentNames) {
|
||||
Set<String> notReloadableComponents = null;
|
||||
for (String componentName : componentNames) {
|
||||
Object component = myComponents.get(componentName);
|
||||
if (component != null && (!(component instanceof PersistentStateComponent) || !StoreUtil.getStateSpec((PersistentStateComponent<?>)component).reloadable())) {
|
||||
if (notReloadableComponents == null) {
|
||||
notReloadableComponents = new LinkedHashSet<String>();
|
||||
}
|
||||
notReloadableComponents.add(componentName);
|
||||
}
|
||||
}
|
||||
return notReloadableComponents == null ? Collections.<String>emptySet() : notReloadableComponents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reinitComponents(@NotNull Set<String> componentNames, boolean reloadData) {
|
||||
reinitComponents(componentNames, Collections.<String>emptySet(), Collections.<StateStorage>emptySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reinitComponent(@NotNull String componentName, @NotNull Set<StateStorage> changedStorages) {
|
||||
PersistentStateComponent component = (PersistentStateComponent)myComponents.get(componentName);
|
||||
if (component == null) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
boolean changedStoragesEmpty = changedStorages.isEmpty();
|
||||
initPersistentComponent(component, changedStoragesEmpty ? null : changedStorages, changedStoragesEmpty);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract MessageBus getMessageBus();
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public final Collection<String> reload(@NotNull MultiMap<StateStorage, VirtualFile> changedStorages) {
|
||||
if (changedStorages.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set<String> componentNames = new SmartHashSet<String>();
|
||||
for (StateStorage storage : changedStorages.keySet()) {
|
||||
try {
|
||||
// we must update (reload in-memory storage data) even if non-reloadable component will be detected later
|
||||
// not saved -> user does own modification -> new (on disk) state will be overwritten and not applied
|
||||
storage.analyzeExternalChangesAndUpdateIfNeed(changedStorages.get(storage), componentNames);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (componentNames.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Collection<String> notReloadableComponents = getNotReloadableComponents(componentNames);
|
||||
reinitComponents(componentNames, notReloadableComponents, changedStorages.keySet());
|
||||
return notReloadableComponents.isEmpty() ? null : notReloadableComponents;
|
||||
}
|
||||
|
||||
// used in settings repository plugin
|
||||
public void reinitComponents(@NotNull Set<String> componentNames, @NotNull Collection<String> notReloadableComponents, @NotNull Set<StateStorage> changedStorages) {
|
||||
MessageBus messageBus = getMessageBus();
|
||||
messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateStarted();
|
||||
try {
|
||||
for (String componentName : componentNames) {
|
||||
if (!notReloadableComponents.contains(componentName)) {
|
||||
reinitComponent(componentName, changedStorages);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
messageBus.syncPublisher(BatchUpdateListener.TOPIC).onBatchUpdateFinished();
|
||||
}
|
||||
}
|
||||
}
|
||||
-189
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* 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.components.impl.stores;
|
||||
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.components.StateStorage.SaveSession;
|
||||
import com.intellij.openapi.project.impl.ProjectImpl;
|
||||
import com.intellij.openapi.project.impl.ProjectManagerImpl;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class DefaultProjectStoreImpl extends ProjectStoreImpl {
|
||||
private final ProjectManagerImpl myProjectManager;
|
||||
@NonNls private static final String ROOT_TAG_NAME = "defaultProject";
|
||||
|
||||
public DefaultProjectStoreImpl(@NotNull ProjectImpl project, @NotNull ProjectManagerImpl projectManager, @NotNull PathMacroManager pathMacroManager) {
|
||||
super(project, pathMacroManager);
|
||||
|
||||
myProjectManager = projectManager;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Element getStateCopy() {
|
||||
final Element element = myProjectManager.getDefaultProjectRootElement();
|
||||
return element != null ? element.clone() : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected StateStorageManager createStateStorageManager() {
|
||||
final XmlElementStorage storage = new XmlElementStorage("", RoamingType.DISABLED, myPathMacroManager.createTrackingSubstitutor(),
|
||||
ROOT_TAG_NAME, null) {
|
||||
@Override
|
||||
@Nullable
|
||||
protected Element loadLocalData() {
|
||||
return getStateCopy();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected XmlElementStorageSaveSession createSaveSession(@NotNull StorageData storageData) {
|
||||
return new XmlElementStorageSaveSession(storageData) {
|
||||
@Override
|
||||
protected void doSave(@Nullable Element element) {
|
||||
// we must set empty element instead of null as indicator - ProjectManager state is ready to save
|
||||
myProjectManager.setDefaultProjectRootElement(element == null ? new Element("empty") : element);
|
||||
}
|
||||
|
||||
// we must not collapse paths here, because our solution is just a big hack
|
||||
// by default, getElementToSave() returns collapsed paths -> setDefaultProjectRootElement -> project manager writeExternal -> save -> compare old and new - diff because old has expanded, but new collapsed
|
||||
// -> needless save
|
||||
@Override
|
||||
protected boolean isCollapsePathsOnSave() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected StorageData createStorageData() {
|
||||
return new BaseStorageData(ROOT_TAG_NAME);
|
||||
}
|
||||
};
|
||||
|
||||
//noinspection deprecation
|
||||
return new StateStorageManager() {
|
||||
@Override
|
||||
public void addMacro(@NotNull String macro, @NotNull String expansion) {
|
||||
throw new UnsupportedOperationException("Method addMacro not implemented in " + getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public TrackingPathMacroSubstitutor getMacroSubstitutor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public StateStorage getStateStorage(@NotNull Storage storageSpec) {
|
||||
return storage;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType) {
|
||||
return storage;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Couple<Collection<FileBasedStorage>> getCachedFileStateStorages(@NotNull Collection<String> changed, @NotNull Collection<String> deleted) {
|
||||
return new Couple<Collection<FileBasedStorage>>(Collections.<FileBasedStorage>emptyList(), Collections.<FileBasedStorage>emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearStateStorage(@NotNull String file) {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ExternalizationSession startExternalization() {
|
||||
StateStorage.ExternalizationSession externalizationSession = storage.startExternalization();
|
||||
return externalizationSession == null ? null : new MyExternalizationSession(externalizationSession);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String expandMacros(@NotNull String file) {
|
||||
throw new UnsupportedOperationException("Method expandMacros not implemented in " + getClass());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String collapseMacros(@NotNull String path) {
|
||||
throw new UnsupportedOperationException("Method collapseMacros not implemented in " + getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public StateStorage getOldStorage(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) {
|
||||
return storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreamProvider(@Nullable StreamProvider streamProvider) {
|
||||
throw new UnsupportedOperationException("Method setStreamProvider not implemented in " + getClass());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public StreamProvider getStreamProvider() {
|
||||
throw new UnsupportedOperationException("Method getStreamProviders not implemented in " + getClass());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<String> getStorageFileNames() {
|
||||
throw new UnsupportedOperationException("Method getStorageFileNames not implemented in " + getClass());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class MyExternalizationSession implements StateStorageManager.ExternalizationSession {
|
||||
@NotNull final StateStorage.ExternalizationSession externalizationSession;
|
||||
|
||||
public MyExternalizationSession(@NotNull StateStorage.ExternalizationSession externalizationSession) {
|
||||
this.externalizationSession = externalizationSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(@NotNull Storage[] storageSpecs, @NotNull Object component, @NotNull String componentName, @NotNull Object state) {
|
||||
externalizationSession.setState(component, componentName, state, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStateInOldStorage(@NotNull Object component, @NotNull String componentName, @NotNull Object state) {
|
||||
externalizationSession.setState(component, componentName, state, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<SaveSession> createSaveSessions() {
|
||||
return ContainerUtil.createMaybeSingletonList(externalizationSession.createSaveSession());
|
||||
}
|
||||
}
|
||||
}
|
||||
-121
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* 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.components.impl.stores;
|
||||
|
||||
import com.intellij.openapi.components.PathMacroSubstitutor;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.OptionManager;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jdom.Attribute;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
final class ModuleFileData extends BaseFileConfigurableStoreImpl.BaseStorageData implements OptionManager {
|
||||
private TreeMap<String, String> options;
|
||||
private final Module myModule;
|
||||
|
||||
private boolean dirty = true;
|
||||
|
||||
public ModuleFileData(@NotNull String rootElementName, @NotNull Module module) {
|
||||
super(rootElementName);
|
||||
|
||||
myModule = module;
|
||||
options = new TreeMap<String, String>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirty() {
|
||||
return dirty;
|
||||
}
|
||||
|
||||
private ModuleFileData(@NotNull ModuleFileData storageData) {
|
||||
super(storageData);
|
||||
|
||||
myModule = storageData.myModule;
|
||||
dirty = storageData.dirty;
|
||||
options = new TreeMap<String, String>(storageData.options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) {
|
||||
super.load(rootElement, pathMacroSubstitutor, intern);
|
||||
|
||||
for (Attribute attribute : rootElement.getAttributes()) {
|
||||
String name = attribute.getName();
|
||||
if (!name.equals(BaseFileConfigurableStoreImpl.VERSION_OPTION) && !StringUtil.isEmpty(name)) {
|
||||
options.put(name, attribute.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeOptions(@NotNull Element root, @NotNull String versionString) {
|
||||
if (!options.isEmpty()) {
|
||||
for (String key : options.keySet()) {
|
||||
String value = options.get(key);
|
||||
if (value != null) {
|
||||
root.setAttribute(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
// need be last for compat reasons
|
||||
super.writeOptions(root, versionString);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageData clone() {
|
||||
return new ModuleFileData(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Set<String> getChangedComponentNames(@NotNull StorageData newStorageData, @Nullable PathMacroSubstitutor substitutor) {
|
||||
final ModuleFileData data = (ModuleFileData)newStorageData;
|
||||
if (!options.equals(data.options)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return super.getChangedComponentNames(newStorageData, substitutor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOption(@NotNull String key, @NotNull String value) {
|
||||
if (!value.equals(options.put(key, value))) {
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearOption(@NotNull String key) {
|
||||
if (options.remove(key) != null) {
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getOptionValue(@NotNull String key) {
|
||||
return options.get(key);
|
||||
}
|
||||
}
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* 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.components.impl.stores;
|
||||
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ModuleStateStorageManager extends StateStorageManagerImpl {
|
||||
@NonNls private static final String ROOT_TAG_NAME = "module";
|
||||
private final Module myModule;
|
||||
|
||||
public ModuleStateStorageManager(@NotNull TrackingPathMacroSubstitutor pathMacroManager, @NotNull Module module) {
|
||||
super(pathMacroManager, ROOT_TAG_NAME, module, module.getPicoContainer());
|
||||
|
||||
myModule = module;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath) {
|
||||
return new ModuleFileData(ROOT_TAG_NAME, myModule);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ExternalizationSession startExternalization() {
|
||||
return new StateStorageManagerExternalizationSession() {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<StateStorage.SaveSession> createSaveSessions() {
|
||||
StateStorageManagerImpl storageManager = (StateStorageManagerImpl)ComponentsPackage.getStateStore(myModule).getStateStorageManager();
|
||||
FileBasedStorage storage = ContainerUtil.getFirstItem(storageManager.getCachedFileStorages(Collections.singletonList(StoragePathMacros.MODULE_FILE)));
|
||||
if (storage != null && storage.getStorageData().isDirty()) {
|
||||
// force XmlElementStorageSaveSession creation
|
||||
getExternalizationSession(storage);
|
||||
}
|
||||
return super.createSaveSessions();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) {
|
||||
return StoragePathMacros.MODULE_FILE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected StateStorage.Listener createStorageTopicListener() {
|
||||
return myModule.getProject().getMessageBus().syncPublisher(StateStorage.PROJECT_STORAGE_TOPIC);
|
||||
}
|
||||
}
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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.components.impl.stores;
|
||||
|
||||
import com.intellij.openapi.components.PathMacroManager;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ex.ProjectEx;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
final class ModuleStoreImpl extends BaseFileConfigurableStoreImpl {
|
||||
private final Module myModule;
|
||||
|
||||
public ModuleStoreImpl(@NotNull Module module, @NotNull PathMacroManager pathMacroManager) {
|
||||
super(pathMacroManager);
|
||||
|
||||
myModule = module;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Project getProject() {
|
||||
return myModule.getProject();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean optimizeTestLoading() {
|
||||
return ((ProjectEx)myModule.getProject()).isOptimiseTestLoadSpeed();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected MessageBus getMessageBus() {
|
||||
return myModule.getMessageBus();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected StateStorageManager createStateStorageManager() {
|
||||
return new ModuleStateStorageManager(myPathMacroManager.createTrackingSubstitutor(), myModule);
|
||||
}
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.components.impl.stores;
|
||||
|
||||
import com.intellij.openapi.project.impl.ProjectStoreClassProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
class PlatformLangProjectStoreClassProvider implements ProjectStoreClassProvider {
|
||||
@NotNull
|
||||
@Override
|
||||
public Class<? extends IComponentStore> getProjectStoreClass(final boolean isDefaultProject) {
|
||||
return isDefaultProject ? DefaultProjectStoreImpl.class : ProjectWithModulesStoreImpl.class;
|
||||
}
|
||||
}
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* 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.components.impl.stores;
|
||||
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.project.impl.ProjectImpl;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ProjectStateStorageManager extends StateStorageManagerImpl {
|
||||
protected final ProjectImpl myProject;
|
||||
@NonNls protected static final String ROOT_TAG_NAME = "project";
|
||||
|
||||
public ProjectStateStorageManager(@NotNull TrackingPathMacroSubstitutor macroSubstitutor, @NotNull ProjectImpl project) {
|
||||
super(macroSubstitutor, ROOT_TAG_NAME, project, project.getPicoContainer());
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath) {
|
||||
if (fileSpec.equals(StoragePathMacros.PROJECT_FILE)) {
|
||||
return createIprStorageData(filePath);
|
||||
}
|
||||
if (fileSpec.equals(StoragePathMacros.WORKSPACE_FILE)) {
|
||||
return new ProjectStoreImpl.WsStorageData(ROOT_TAG_NAME, myProject);
|
||||
}
|
||||
return new ProjectStoreImpl.ProjectStorageData(ROOT_TAG_NAME, myProject);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected StorageData createIprStorageData(@NotNull String filePath) {
|
||||
return new ProjectStoreImpl.IprStorageData(ROOT_TAG_NAME, myProject);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) {
|
||||
boolean workspace = myProject.isWorkspaceComponent(component.getClass());
|
||||
String fileSpec = workspace ? StoragePathMacros.WORKSPACE_FILE : StoragePathMacros.PROJECT_FILE;
|
||||
StateStorage storage = getStateStorage(fileSpec, workspace ? RoamingType.DISABLED : RoamingType.PER_USER);
|
||||
if (operation == StateStorageOperation.READ && storage != null && workspace && !storage.hasState(component, componentName, Element.class, false)) {
|
||||
fileSpec = StoragePathMacros.PROJECT_FILE;
|
||||
}
|
||||
return fileSpec;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected StateStorage.Listener createStorageTopicListener() {
|
||||
return myProject.getMessageBus().syncPublisher(StateStorage.PROJECT_STORAGE_TOPIC);
|
||||
}
|
||||
}
|
||||
-661
@@ -1,661 +0,0 @@
|
||||
/*
|
||||
* 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.components.impl.stores;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.ide.highlighter.ProjectFileType;
|
||||
import com.intellij.ide.highlighter.WorkspaceFileType;
|
||||
import com.intellij.notification.Notifications;
|
||||
import com.intellij.notification.NotificationsManager;
|
||||
import com.intellij.openapi.application.*;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.components.StateStorage.SaveSession;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
||||
import com.intellij.openapi.help.HelpManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectBundle;
|
||||
import com.intellij.openapi.project.impl.ProjectImpl;
|
||||
import com.intellij.openapi.project.impl.ProjectManagerImpl;
|
||||
import com.intellij.openapi.project.impl.ProjectManagerImpl.UnableToSaveProjectNotification;
|
||||
import com.intellij.openapi.ui.MessageDialogBuilder;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.util.PathUtilRt;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.lang.CompoundRuntimeException;
|
||||
import com.intellij.util.messages.MessageBus;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProjectStore {
|
||||
private static final Logger LOG = Logger.getInstance(ProjectStoreImpl.class);
|
||||
|
||||
private static final Storage DEFAULT_STORAGE_ANNOTATION = new MyStorage();
|
||||
|
||||
@NonNls private static final String OLD_PROJECT_SUFFIX = "_old.";
|
||||
|
||||
private static int originalVersion = -1;
|
||||
|
||||
protected ProjectImpl myProject;
|
||||
@NotNull
|
||||
private StorageScheme myScheme = StorageScheme.DEFAULT;
|
||||
private String myPresentableUrl;
|
||||
|
||||
public ProjectStoreImpl(@NotNull ProjectImpl project, @NotNull PathMacroManager pathMacroManager) {
|
||||
super(pathMacroManager);
|
||||
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused") //used in upsource
|
||||
protected void setStorageScheme(@NotNull StorageScheme scheme) {
|
||||
myScheme = scheme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkVersion() {
|
||||
if (originalVersion >= 0 && originalVersion < ProjectManagerImpl.CURRENT_FORMAT_VERSION) {
|
||||
final VirtualFile projectFile = getProjectFile();
|
||||
LOG.assertTrue(projectFile != null);
|
||||
String message = ProjectBundle.message("project.convert.old.prompt", projectFile.getName(),
|
||||
ApplicationNamesInfo.getInstance().getProductName(),
|
||||
projectFile.getNameWithoutExtension() + OLD_PROJECT_SUFFIX + projectFile.getExtension());
|
||||
if (Messages.showYesNoDialog(message, CommonBundle.getWarningTitle(), Messages.getWarningIcon()) != Messages.YES) return false;
|
||||
|
||||
List<String> conversionProblems = getConversionProblemsStorage();
|
||||
if (!ContainerUtil.isEmpty(conversionProblems)) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append(ProjectBundle.message("project.convert.problems.detected"));
|
||||
for (String s : conversionProblems) {
|
||||
buffer.append('\n');
|
||||
buffer.append(s);
|
||||
}
|
||||
buffer.append(ProjectBundle.message("project.convert.problems.help"));
|
||||
if (Messages.showOkCancelDialog(myProject, buffer.toString(), ProjectBundle.message("project.convert.problems.title"),
|
||||
ProjectBundle.message("project.convert.problems.help.button"),
|
||||
CommonBundle.getCloseButtonText(), Messages.getWarningIcon()) == Messages.OK) {
|
||||
HelpManager.getInstance().invokeHelp("project.migrationProblems");
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
VirtualFile projectDir = projectFile.getParent();
|
||||
assert projectDir != null;
|
||||
|
||||
backup(projectDir, projectFile);
|
||||
|
||||
VirtualFile workspaceFile = getWorkspaceFile();
|
||||
if (workspaceFile != null) {
|
||||
backup(projectDir, workspaceFile);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void backup(final VirtualFile projectDir, final VirtualFile vile) throws IOException {
|
||||
final String oldName = vile.getNameWithoutExtension() + OLD_PROJECT_SUFFIX + vile.getExtension();
|
||||
VfsUtil.saveText(projectDir.findOrCreateChildData(this, oldName), VfsUtilCore.loadText(vile));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return originalVersion <= ProjectManagerImpl.CURRENT_FORMAT_VERSION ||
|
||||
MessageDialogBuilder.yesNo(CommonBundle.getWarningTitle(),
|
||||
ProjectBundle.message("project.load.new.version.warning", myProject.getName(), ApplicationNamesInfo.getInstance().getProductName()))
|
||||
.icon(Messages.getWarningIcon())
|
||||
.project(myProject).is();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TrackingPathMacroSubstitutor[] getSubstitutors() {
|
||||
return new TrackingPathMacroSubstitutor[] {getStateStorageManager().getMacroSubstitutor()};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean optimizeTestLoading() {
|
||||
return myProject.isOptimiseTestLoadSpeed();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Project getProject() {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProjectFilePath(@NotNull final String filePath) {
|
||||
final StateStorageManager stateStorageManager = getStateStorageManager();
|
||||
final LocalFileSystem fs = LocalFileSystem.getInstance();
|
||||
|
||||
final File file = new File(filePath);
|
||||
if (isIprPath(file)) {
|
||||
myScheme = StorageScheme.DEFAULT;
|
||||
|
||||
stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, filePath);
|
||||
|
||||
final String workspacePath = composeWsPath(filePath);
|
||||
stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, workspacePath);
|
||||
|
||||
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
VfsUtil.markDirtyAndRefresh(false, true, false, fs.refreshAndFindFileByPath(filePath), fs.refreshAndFindFileByPath(workspacePath));
|
||||
}
|
||||
}, ModalityState.defaultModalityState());
|
||||
}
|
||||
else {
|
||||
myScheme = StorageScheme.DIRECTORY_BASED;
|
||||
|
||||
final File dirStore = file.isDirectory() ? new File(file, Project.DIRECTORY_STORE_FOLDER)
|
||||
: new File(file.getParentFile(), Project.DIRECTORY_STORE_FOLDER);
|
||||
stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, new File(dirStore, "misc.xml").getPath());
|
||||
|
||||
final File ws = new File(dirStore, "workspace.xml");
|
||||
stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, ws.getPath());
|
||||
if (!ws.exists() && !file.isDirectory()) {
|
||||
useOldWsContent(filePath, ws);
|
||||
}
|
||||
|
||||
stateStorageManager.addMacro(StoragePathMacros.PROJECT_CONFIG_DIR, dirStore.getPath());
|
||||
|
||||
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
VfsUtil.markDirtyAndRefresh(false, true, true, fs.refreshAndFindFileByIoFile(dirStore));
|
||||
}
|
||||
}, ModalityState.defaultModalityState());
|
||||
}
|
||||
|
||||
myPresentableUrl = null;
|
||||
}
|
||||
|
||||
private static boolean isIprPath(final File file) {
|
||||
return FileUtilRt.extensionEquals(file.getName(), ProjectFileType.DEFAULT_EXTENSION);
|
||||
}
|
||||
|
||||
private static String composeWsPath(String filePath) {
|
||||
final int lastDot = filePath.lastIndexOf('.');
|
||||
final String filePathWithoutExt = lastDot > 0 ? filePath.substring(0, lastDot) : filePath;
|
||||
return filePathWithoutExt + WorkspaceFileType.DOT_DEFAULT_EXTENSION;
|
||||
}
|
||||
|
||||
private static void useOldWsContent(final String filePath, final File ws) {
|
||||
final File oldWs = new File(composeWsPath(filePath));
|
||||
if (oldWs.exists()) {
|
||||
try {
|
||||
final InputStream is = new FileInputStream(oldWs);
|
||||
try {
|
||||
final byte[] bytes = FileUtil.loadBytes(is, (int)oldWs.length());
|
||||
|
||||
final OutputStream os = new FileOutputStream(ws);
|
||||
try {
|
||||
os.write(bytes);
|
||||
}
|
||||
finally {
|
||||
os.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualFile getProjectBaseDir() {
|
||||
if (myProject.isDefault()) return null;
|
||||
|
||||
final String path = getProjectBasePath();
|
||||
if (path == null) return null;
|
||||
|
||||
return LocalFileSystem.getInstance().findFileByPath(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProjectBasePath() {
|
||||
if (myProject.isDefault()) return null;
|
||||
|
||||
final String path = getProjectFilePath();
|
||||
if (!StringUtil.isEmptyOrSpaces(path)) {
|
||||
return getBasePath(new File(path));
|
||||
}
|
||||
|
||||
//we are not yet initialized completely ("open directory", etc)
|
||||
StateStorage storage = getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER);
|
||||
if (!(storage instanceof FileBasedStorage)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getBasePath(((FileBasedStorage)storage).getFile());
|
||||
}
|
||||
|
||||
private String getBasePath(@NotNull File file) {
|
||||
if (myScheme == StorageScheme.DEFAULT) {
|
||||
return file.getParent();
|
||||
}
|
||||
else {
|
||||
File parentFile = file.getParentFile();
|
||||
return parentFile == null ? null : parentFile.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getProjectName() {
|
||||
if (myScheme == StorageScheme.DIRECTORY_BASED) {
|
||||
final VirtualFile baseDir = getProjectBaseDir();
|
||||
assert baseDir != null : "scheme=" + myScheme + " project file=" + getProjectFilePath();
|
||||
|
||||
final VirtualFile ideaDir = baseDir.findChild(Project.DIRECTORY_STORE_FOLDER);
|
||||
if (ideaDir != null && ideaDir.isValid()) {
|
||||
final VirtualFile nameFile = ideaDir.findChild(ProjectImpl.NAME_FILE);
|
||||
if (nameFile != null && nameFile.isValid()) {
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(nameFile.getInputStream(), CharsetToolkit.UTF8_CHARSET));
|
||||
try {
|
||||
final String name = in.readLine();
|
||||
if (name != null && !name.isEmpty()) {
|
||||
return name.trim();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
|
||||
return baseDir.getName().replace(":", "");
|
||||
}
|
||||
else {
|
||||
String temp = PathUtilRt.getFileName(((FileBasedStorage)getProjectFileStorage()).getFilePath());
|
||||
FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(temp);
|
||||
if (fileType instanceof ProjectFileType) {
|
||||
temp = temp.substring(0, temp.length() - fileType.getDefaultExtension().length() - 1);
|
||||
}
|
||||
final int i = temp.lastIndexOf(File.separatorChar);
|
||||
if (i >= 0) {
|
||||
temp = temp.substring(i + 1, temp.length() - i + 1);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public StorageScheme getStorageScheme() {
|
||||
return myScheme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPresentableUrl() {
|
||||
if (myProject.isDefault()) {
|
||||
return null;
|
||||
}
|
||||
if (myPresentableUrl == null) {
|
||||
String url = myScheme == StorageScheme.DIRECTORY_BASED ? getProjectBasePath() : getProjectFilePath();
|
||||
if (url != null) {
|
||||
myPresentableUrl = FileUtil.toSystemDependentName(url);
|
||||
}
|
||||
}
|
||||
return myPresentableUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualFile getProjectFile() {
|
||||
return myProject.isDefault() ? null : ((FileBasedStorage)getProjectFileStorage()).getVirtualFile();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getProjectFilePath() {
|
||||
return myProject.isDefault() ? "" : ((FileBasedStorage)getProjectFileStorage()).getFilePath();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private XmlElementStorage getProjectFileStorage() {
|
||||
// XmlElementStorage if default project, otherwise FileBasedStorage
|
||||
XmlElementStorage storage = (XmlElementStorage)getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER);
|
||||
assert storage != null;
|
||||
return storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VirtualFile getWorkspaceFile() {
|
||||
if (myProject.isDefault()) return null;
|
||||
final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED);
|
||||
assert storage != null;
|
||||
return storage.getVirtualFile();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getWorkspaceFilePath() {
|
||||
if (myProject.isDefault()) return null;
|
||||
final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED);
|
||||
assert storage != null;
|
||||
return storage.getFilePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadProjectFromTemplate(@NotNull ProjectImpl defaultProject) {
|
||||
defaultProject.save();
|
||||
|
||||
Element element = ((DefaultProjectStoreImpl)defaultProject.getStateStore()).getStateCopy();
|
||||
if (element != null) {
|
||||
getProjectFileStorage().setDefaultState(element);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected StateStorageManager createStateStorageManager() {
|
||||
return new ProjectStateStorageManager(myPathMacroManager.createTrackingSubstitutor(), myProject);
|
||||
}
|
||||
|
||||
static class ProjectStorageData extends BaseStorageData {
|
||||
protected final Project myProject;
|
||||
|
||||
ProjectStorageData(final String rootElementName, Project project) {
|
||||
super(rootElementName);
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
protected ProjectStorageData(ProjectStorageData storageData) {
|
||||
super(storageData);
|
||||
myProject = storageData.myProject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageData clone() {
|
||||
return new ProjectStorageData(this);
|
||||
}
|
||||
}
|
||||
|
||||
static class WsStorageData extends ProjectStorageData {
|
||||
WsStorageData(final String rootElementName, final Project project) {
|
||||
super(rootElementName, project);
|
||||
}
|
||||
|
||||
private WsStorageData(final WsStorageData storageData) {
|
||||
super(storageData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageData clone() {
|
||||
return new WsStorageData(this);
|
||||
}
|
||||
}
|
||||
|
||||
static class IprStorageData extends ProjectStorageData {
|
||||
IprStorageData(final String rootElementName, Project project) {
|
||||
super(rootElementName, project);
|
||||
}
|
||||
|
||||
IprStorageData(final IprStorageData storageData) {
|
||||
super(storageData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) {
|
||||
final String v = rootElement.getAttributeValue(VERSION_OPTION);
|
||||
//noinspection AssignmentToStaticFieldFromInstanceMethod
|
||||
originalVersion = v != null ? Integer.parseInt(v) : 0;
|
||||
|
||||
if (originalVersion != ProjectManagerImpl.CURRENT_FORMAT_VERSION) {
|
||||
convert(rootElement, originalVersion);
|
||||
}
|
||||
|
||||
super.load(rootElement, pathMacroSubstitutor, intern);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedParameters")
|
||||
protected void convert(Element root, int originalVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageData clone() {
|
||||
return new IprStorageData(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final List<Throwable> doSave(@Nullable List<SaveSession> saveSessions, @NotNull List<Pair<SaveSession, VirtualFile>> readonlyFiles, @Nullable List<Throwable> errors) {
|
||||
beforeSave(readonlyFiles);
|
||||
|
||||
super.doSave(saveSessions, readonlyFiles, errors);
|
||||
|
||||
UnableToSaveProjectNotification[] notifications =
|
||||
NotificationsManager.getNotificationsManager().getNotificationsOfType(UnableToSaveProjectNotification.class, myProject);
|
||||
if (readonlyFiles.isEmpty()) {
|
||||
if (notifications.length > 0) {
|
||||
for (UnableToSaveProjectNotification notification : notifications) {
|
||||
notification.expire();
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
if (notifications.length > 0) {
|
||||
throw new SaveCancelledException();
|
||||
}
|
||||
|
||||
ReadonlyStatusHandler.OperationStatus status;
|
||||
AccessToken token = ReadAction.start();
|
||||
try {
|
||||
status = ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(getFilesList(readonlyFiles));
|
||||
}
|
||||
finally {
|
||||
token.finish();
|
||||
}
|
||||
|
||||
if (status.hasReadonlyFiles()) {
|
||||
dropUnableToSaveProjectNotification(myProject, status.getReadonlyFiles());
|
||||
throw new SaveCancelledException();
|
||||
}
|
||||
List<Pair<SaveSession, VirtualFile>> oldList = new ArrayList<Pair<SaveSession, VirtualFile>>(readonlyFiles);
|
||||
readonlyFiles.clear();
|
||||
for (Pair<SaveSession, VirtualFile> entry : oldList) {
|
||||
errors = executeSave(entry.first, readonlyFiles, errors);
|
||||
}
|
||||
|
||||
if (errors != null) {
|
||||
CompoundRuntimeException.doThrow(errors);
|
||||
}
|
||||
|
||||
if (!readonlyFiles.isEmpty()) {
|
||||
dropUnableToSaveProjectNotification(myProject, getFilesList(readonlyFiles));
|
||||
throw new SaveCancelledException();
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
private static void dropUnableToSaveProjectNotification(@NotNull Project project, @NotNull VirtualFile[] readOnlyFiles) {
|
||||
UnableToSaveProjectNotification[] notifications =
|
||||
NotificationsManager.getNotificationsManager().getNotificationsOfType(UnableToSaveProjectNotification.class, project);
|
||||
if (notifications.length == 0) {
|
||||
Notifications.Bus.notify(new UnableToSaveProjectNotification(project, readOnlyFiles), project);
|
||||
}
|
||||
else {
|
||||
notifications[0].myFiles = readOnlyFiles;
|
||||
}
|
||||
}
|
||||
|
||||
protected void beforeSave(@NotNull List<Pair<SaveSession, VirtualFile>> readonlyFiles) {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static VirtualFile[] getFilesList(List<Pair<SaveSession, VirtualFile>> readonlyFiles) {
|
||||
final VirtualFile[] files = new VirtualFile[readonlyFiles.size()];
|
||||
for (int i = 0, size = readonlyFiles.size(); i < size; i++) {
|
||||
files[i] = readonlyFiles.get(i).second;
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
private final StateStorageChooser<PersistentStateComponent<?>> myStateStorageChooser = new StateStorageChooser<PersistentStateComponent<?>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Storage[] selectStorages(@NotNull Storage[] storages, @NotNull PersistentStateComponent<?> component, @NotNull StateStorageOperation operation) {
|
||||
if (operation == StateStorageOperation.READ) {
|
||||
List<Storage> result = new SmartList<Storage>();
|
||||
for (int i = storages.length - 1; i >= 0; i--) {
|
||||
Storage storage = storages[i];
|
||||
if (storage.scheme() == myScheme) {
|
||||
result.add(storage);
|
||||
}
|
||||
}
|
||||
|
||||
for (Storage storage : storages) {
|
||||
if (storage.scheme() == StorageScheme.DEFAULT && !result.contains(storage)) {
|
||||
result.add(storage);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toArray(new Storage[result.size()]);
|
||||
}
|
||||
else if (operation == StateStorageOperation.WRITE) {
|
||||
List<Storage> result = new SmartList<Storage>();
|
||||
for (Storage storage : storages) {
|
||||
if (storage.scheme() == myScheme) {
|
||||
result.add(storage);
|
||||
}
|
||||
}
|
||||
|
||||
if (!result.isEmpty()) {
|
||||
return result.toArray(new Storage[result.size()]);
|
||||
}
|
||||
|
||||
for (Storage storage : storages) {
|
||||
if (storage.scheme() == StorageScheme.DEFAULT) {
|
||||
result.add(storage);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toArray(new Storage[result.size()]);
|
||||
}
|
||||
else {
|
||||
return new Storage[]{};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected StateStorageChooser<PersistentStateComponent<?>> getDefaultStateStorageChooser() {
|
||||
return myStateStorageChooser;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected MessageBus getMessageBus() {
|
||||
return myProject.getMessageBus();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected <T> Storage[] getComponentStorageSpecs(@NotNull PersistentStateComponent<T> component,
|
||||
@NotNull State stateSpec,
|
||||
@NotNull StateStorageOperation operation) {
|
||||
// if we create project from default, component state written not to own storage file, but to project file,
|
||||
// we don't have time to fix it properly, so, ancient hack restored.
|
||||
Storage[] result = super.getComponentStorageSpecs(component, stateSpec, operation);
|
||||
// don't add fake storage if project file storage already listed, otherwise data will be deleted on write (because of "deprecated")
|
||||
for (Storage storage : result) {
|
||||
if (storage.file().equals(StoragePathMacros.PROJECT_FILE)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Storage[] withProjectFileStorage = new Storage[result.length + 1];
|
||||
System.arraycopy(result, 0, withProjectFileStorage, 0, result.length);
|
||||
withProjectFileStorage[result.length] = DEFAULT_STORAGE_ANNOTATION;
|
||||
return withProjectFileStorage;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ClassExplicitlyAnnotation")
|
||||
private static class MyStorage implements Storage {
|
||||
@Override
|
||||
public String id() {
|
||||
return "___Default___";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String file() {
|
||||
return StoragePathMacros.PROJECT_FILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageScheme scheme() {
|
||||
return StorageScheme.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deprecated() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoamingType roamingType() {
|
||||
return RoamingType.PER_USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends StateStorage> storageClass() {
|
||||
return StateStorage.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<StateSplitterEx> stateSplitter() {
|
||||
return StateSplitterEx.class;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
throw new UnsupportedOperationException("Method annotationType not implemented in " + getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
-99
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* 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.components.impl.stores;
|
||||
|
||||
import com.intellij.openapi.components.PathMacroManager;
|
||||
import com.intellij.openapi.components.StateStorage;
|
||||
import com.intellij.openapi.components.StateStorage.SaveSession;
|
||||
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.impl.ProjectImpl;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class ProjectWithModulesStoreImpl extends ProjectStoreImpl {
|
||||
public ProjectWithModulesStoreImpl(@NotNull ProjectImpl project, @NotNull PathMacroManager pathMacroManager) {
|
||||
super(project, pathMacroManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reinitComponent(@NotNull String componentName, @NotNull Set<StateStorage> changedStorages) {
|
||||
if (super.reinitComponent(componentName, changedStorages)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (Module module : getPersistentModules()) {
|
||||
// we have to reinit all modules for component because we don't know affected module
|
||||
getComponentStore(module).reinitComponent(componentName, changedStorages);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static IComponentStore getComponentStore(@NotNull Module module) {
|
||||
return (IComponentStore)module.getPicoContainer().getComponentInstance(IComponentStore.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TrackingPathMacroSubstitutor[] getSubstitutors() {
|
||||
List<TrackingPathMacroSubstitutor> result = new SmartList<TrackingPathMacroSubstitutor>();
|
||||
ContainerUtil.addIfNotNull(result, getStateStorageManager().getMacroSubstitutor());
|
||||
|
||||
for (Module module : getPersistentModules()) {
|
||||
ContainerUtil.addIfNotNull(result, getComponentStore(module).getStateStorageManager().getMacroSubstitutor());
|
||||
}
|
||||
|
||||
return result.toArray(new TrackingPathMacroSubstitutor[result.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReloadPossible(@NotNull Set<String> componentNames) {
|
||||
if (!super.isReloadPossible(componentNames)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Module module : getPersistentModules()) {
|
||||
if (!getComponentStore(module).isReloadPossible(componentNames)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Module[] getPersistentModules() {
|
||||
ModuleManager moduleManager = ModuleManager.getInstance(myProject);
|
||||
return moduleManager == null ? Module.EMPTY_ARRAY : moduleManager.getModules();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeSave(@NotNull List<Pair<SaveSession, VirtualFile>> readonlyFiles) {
|
||||
super.beforeSave(readonlyFiles);
|
||||
|
||||
for (Module module : getPersistentModules()) {
|
||||
getComponentStore(module).save(readonlyFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
-372
@@ -1,372 +0,0 @@
|
||||
/*
|
||||
* 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.components.impl.stores;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.components.StateStorage.SaveSession;
|
||||
import com.intellij.openapi.components.StateStorageChooserEx.Resolution;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.RoamingTypeDisabled;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.PathUtilRt;
|
||||
import com.intellij.util.ReflectionUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.picocontainer.MutablePicoContainer;
|
||||
import org.picocontainer.PicoContainer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class StateStorageManagerImpl implements StateStorageManager, Disposable {
|
||||
private static final Logger LOG = Logger.getInstance(StateStorageManagerImpl.class);
|
||||
|
||||
private final Map<String, String> myMacros = new LinkedHashMap<String, String>();
|
||||
private final Lock myStorageLock = new ReentrantLock();
|
||||
private final Map<String, StateStorage> myStorages = new THashMap<String, StateStorage>();
|
||||
private final TrackingPathMacroSubstitutor myPathMacroSubstitutor;
|
||||
private final String myRootTagName;
|
||||
private final PicoContainer myPicoContainer;
|
||||
|
||||
private StreamProvider myStreamProvider;
|
||||
|
||||
public StateStorageManagerImpl(@NotNull TrackingPathMacroSubstitutor pathMacroSubstitutor,
|
||||
@NotNull String rootTagName,
|
||||
@NotNull Disposable parentDisposable,
|
||||
@NotNull PicoContainer picoContainer) {
|
||||
myPicoContainer = picoContainer;
|
||||
myRootTagName = rootTagName;
|
||||
myPathMacroSubstitutor = pathMacroSubstitutor;
|
||||
Disposer.register(parentDisposable, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackingPathMacroSubstitutor getMacroSubstitutor() {
|
||||
return myPathMacroSubstitutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addMacro(@NotNull String macro, @NotNull String expansion) {
|
||||
assert !macro.isEmpty();
|
||||
// backward compatibility
|
||||
if (macro.charAt(0) != '$') {
|
||||
LOG.warn("Add macros instead of macro name: " + macro);
|
||||
expansion = '$' + macro + '$';
|
||||
}
|
||||
myMacros.put(macro, expansion);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected final String getMacrosValue(@NotNull String macro) {
|
||||
return myMacros.get(macro);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public StateStorage getStateStorage(@NotNull Storage storageSpec) {
|
||||
String key = storageSpec.storageClass().equals(StateStorage.class) ? storageSpec.file() : storageSpec.storageClass().getName();
|
||||
|
||||
myStorageLock.lock();
|
||||
try {
|
||||
StateStorage stateStorage = myStorages.get(key);
|
||||
if (stateStorage == null) {
|
||||
stateStorage = createStateStorage(storageSpec.storageClass(), storageSpec.file(), storageSpec.roamingType(), storageSpec.stateSplitter());
|
||||
myStorages.put(key, stateStorage);
|
||||
}
|
||||
return stateStorage;
|
||||
}
|
||||
finally {
|
||||
myStorageLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType) {
|
||||
myStorageLock.lock();
|
||||
try {
|
||||
StateStorage stateStorage = myStorages.get(fileSpec);
|
||||
if (stateStorage == null) {
|
||||
stateStorage = createStateStorage(StateStorage.class, fileSpec, roamingType, StateSplitterEx.class);
|
||||
myStorages.put(fileSpec, stateStorage);
|
||||
}
|
||||
return stateStorage;
|
||||
}
|
||||
finally {
|
||||
myStorageLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Couple<Collection<FileBasedStorage>> getCachedFileStateStorages(@NotNull Collection<String> changed, @NotNull Collection<String> deleted) {
|
||||
myStorageLock.lock();
|
||||
try {
|
||||
return Couple.of(getCachedFileStorages(changed), getCachedFileStorages(deleted));
|
||||
}
|
||||
finally {
|
||||
myStorageLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Collection<FileBasedStorage> getCachedFileStorages(@NotNull Collection<String> fileSpecs) {
|
||||
if (fileSpecs.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<FileBasedStorage> result = null;
|
||||
for (String fileSpec : fileSpecs) {
|
||||
StateStorage storage = myStorages.get(fileSpec);
|
||||
if (storage instanceof FileBasedStorage) {
|
||||
if (result == null) {
|
||||
result = new SmartList<FileBasedStorage>();
|
||||
}
|
||||
result.add((FileBasedStorage)storage);
|
||||
}
|
||||
}
|
||||
return result == null ? Collections.<FileBasedStorage>emptyList() : result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<String> getStorageFileNames() {
|
||||
myStorageLock.lock();
|
||||
try {
|
||||
return myStorages.keySet();
|
||||
}
|
||||
finally {
|
||||
myStorageLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// overridden in upsource
|
||||
protected StateStorage createStateStorage(@NotNull Class<? extends StateStorage> storageClass,
|
||||
@NotNull String fileSpec,
|
||||
@NotNull RoamingType roamingType,
|
||||
@SuppressWarnings("deprecation") @NotNull Class<? extends StateSplitter> stateSplitter) {
|
||||
if (!storageClass.equals(StateStorage.class)) {
|
||||
String key = UUID.randomUUID().toString();
|
||||
((MutablePicoContainer)myPicoContainer).registerComponentImplementation(key, storageClass);
|
||||
return (StateStorage)myPicoContainer.getComponentInstance(key);
|
||||
}
|
||||
|
||||
String filePath = expandMacros(fileSpec);
|
||||
File file = new File(filePath);
|
||||
|
||||
//noinspection deprecation
|
||||
if (!stateSplitter.equals(StateSplitter.class) && !stateSplitter.equals(StateSplitterEx.class)) {
|
||||
return new DirectoryBasedStorage(myPathMacroSubstitutor, file, ReflectionUtil.newInstance(stateSplitter), this, createStorageTopicListener());
|
||||
}
|
||||
|
||||
if (!ApplicationManager.getApplication().isHeadlessEnvironment() && PathUtilRt.getFileName(filePath).lastIndexOf('.') < 0) {
|
||||
throw new IllegalArgumentException("Extension is missing for storage file: " + filePath);
|
||||
}
|
||||
|
||||
if (roamingType == RoamingType.PER_USER && fileSpec.equals(StoragePathMacros.WORKSPACE_FILE)) {
|
||||
roamingType = RoamingType.DISABLED;
|
||||
}
|
||||
|
||||
beforeFileBasedStorageCreate();
|
||||
return new FileBasedStorage(file, fileSpec,
|
||||
roamingType, getMacroSubstitutor(fileSpec), myRootTagName, StateStorageManagerImpl.this,
|
||||
createStorageTopicListener(), myStreamProvider) {
|
||||
@Override
|
||||
@NotNull
|
||||
protected StorageData createStorageData() {
|
||||
return StateStorageManagerImpl.this.createStorageData(myFileSpec, getFilePath());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isUseXmlProlog() {
|
||||
return StateStorageManagerImpl.this.isUseXmlProlog();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearStateStorage(@NotNull String file) {
|
||||
myStorageLock.lock();
|
||||
try {
|
||||
myStorages.remove(file);
|
||||
}
|
||||
finally {
|
||||
myStorageLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected StateStorage.Listener createStorageTopicListener() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean isUseXmlProlog() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void beforeFileBasedStorageCreate() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public final StreamProvider getStreamProvider() {
|
||||
return myStreamProvider;
|
||||
}
|
||||
|
||||
protected TrackingPathMacroSubstitutor getMacroSubstitutor(@NotNull String fileSpec) {
|
||||
return myPathMacroSubstitutor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected abstract StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath);
|
||||
|
||||
private static final Pattern MACRO_PATTERN = Pattern.compile("(\\$[^\\$]*\\$)");
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public synchronized String expandMacros(@NotNull String file) {
|
||||
Matcher matcher = MACRO_PATTERN.matcher(file);
|
||||
while (matcher.find()) {
|
||||
String m = matcher.group(1);
|
||||
if (!myMacros.containsKey(m)) {
|
||||
throw new IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file);
|
||||
}
|
||||
}
|
||||
|
||||
String expanded = file;
|
||||
for (Map.Entry<String, String> entry : myMacros.entrySet()) {
|
||||
expanded = StringUtil.replace(expanded, entry.getKey(), entry.getValue());
|
||||
}
|
||||
return expanded;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String collapseMacros(@NotNull String path) {
|
||||
String result = path;
|
||||
for (Map.Entry<String, String> entry : myMacros.entrySet()) {
|
||||
result = StringUtil.replace(result, entry.getValue(), entry.getKey());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ExternalizationSession startExternalization() {
|
||||
return new StateStorageManagerExternalizationSession();
|
||||
}
|
||||
|
||||
protected class StateStorageManagerExternalizationSession implements ExternalizationSession {
|
||||
private final Map<StateStorage, StateStorage.ExternalizationSession> mySessions = new LinkedHashMap<StateStorage, StateStorage.ExternalizationSession>();
|
||||
|
||||
@Override
|
||||
public void setState(@NotNull Storage[] storageSpecs, @NotNull Object component, @NotNull String componentName, @NotNull Object state) {
|
||||
StateStorageChooserEx stateStorageChooser = component instanceof StateStorageChooserEx ? (StateStorageChooserEx)component : null;
|
||||
for (Storage storageSpec : storageSpecs) {
|
||||
Resolution resolution = stateStorageChooser == null ? Resolution.DO : stateStorageChooser.getResolution(storageSpec, StateStorageOperation.WRITE);
|
||||
if (resolution == Resolution.SKIP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
StateStorage stateStorage = getStateStorage(storageSpec);
|
||||
StateStorage.ExternalizationSession session = getExternalizationSession(stateStorage);
|
||||
if (session != null) {
|
||||
// empty element as null state, so, will be deleted
|
||||
session.setState(component, componentName, storageSpec.deprecated() || resolution == Resolution.CLEAR ? new Element("empty") : state, storageSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStateInOldStorage(@NotNull Object component, @NotNull String componentName, @NotNull Object state) {
|
||||
StateStorage stateStorage = getOldStorage(component, componentName, StateStorageOperation.WRITE);
|
||||
if (stateStorage != null) {
|
||||
StateStorage.ExternalizationSession session = getExternalizationSession(stateStorage);
|
||||
if (session != null) {
|
||||
session.setState(component, componentName, state, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected final StateStorage.ExternalizationSession getExternalizationSession(@NotNull StateStorage stateStorage) {
|
||||
StateStorage.ExternalizationSession session = mySessions.get(stateStorage);
|
||||
if (session == null) {
|
||||
session = stateStorage.startExternalization();
|
||||
if (session != null) {
|
||||
mySessions.put(stateStorage, session);
|
||||
}
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<SaveSession> createSaveSessions() {
|
||||
if (mySessions.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<SaveSession> saveSessions = null;
|
||||
Collection<StateStorage.ExternalizationSession> externalizationSessions = mySessions.values();
|
||||
for (StateStorage.ExternalizationSession session : externalizationSessions) {
|
||||
SaveSession saveSession = session.createSaveSession();
|
||||
if (saveSession != null) {
|
||||
if (saveSessions == null) {
|
||||
if (externalizationSessions.size() == 1) {
|
||||
return Collections.singletonList(saveSession);
|
||||
}
|
||||
saveSessions = new SmartList<SaveSession>();
|
||||
}
|
||||
saveSessions.add(saveSession);
|
||||
}
|
||||
}
|
||||
return ContainerUtil.notNullize(saveSessions);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public StateStorage getOldStorage(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) {
|
||||
String oldStorageSpec = getOldStorageSpec(component, componentName, operation);
|
||||
//noinspection deprecation
|
||||
return oldStorageSpec == null ? null : getStateStorage(oldStorageSpec, component instanceof RoamingTypeDisabled ? RoamingType.DISABLED : RoamingType.PER_USER);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation);
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreamProvider(@Nullable StreamProvider streamProvider) {
|
||||
myStreamProvider = streamProvider;
|
||||
}
|
||||
}
|
||||
@@ -19,13 +19,14 @@ import com.intellij.application.options.PathMacrosImpl
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.components.impl.ApplicationPathMacroManager
|
||||
import com.intellij.openapi.components.impl.stores.*
|
||||
import com.intellij.openapi.components.impl.stores.StateStorageManager
|
||||
import com.intellij.openapi.components.impl.stores.StorageData
|
||||
import com.intellij.openapi.components.impl.stores.StoreUtil
|
||||
import com.intellij.openapi.components.impl.stores.StreamProvider
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.CharsetToolkit
|
||||
import com.intellij.testFramework.LightPlatformTestCase
|
||||
import com.intellij.util.messages.MessageBus
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil
|
||||
import gnu.trove.THashMap
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
@@ -40,7 +41,6 @@ public class ApplicationStoreTest : LightPlatformTestCase() {
|
||||
private var testAppConfig: File? = null
|
||||
private var componentStore: MyComponentStore? = null
|
||||
|
||||
throws(Exception::class)
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
@@ -56,7 +56,6 @@ public class ApplicationStoreTest : LightPlatformTestCase() {
|
||||
componentStore = MyComponentStore(testAppConfig!!.getAbsolutePath())
|
||||
}
|
||||
|
||||
throws(Exception::class)
|
||||
override fun tearDown() {
|
||||
try {
|
||||
Disposer.dispose(componentStore!!)
|
||||
@@ -119,7 +118,6 @@ public class ApplicationStoreTest : LightPlatformTestCase() {
|
||||
assertThat(oldFile.exists(), equalTo(false))
|
||||
}
|
||||
|
||||
throws(IOException::class)
|
||||
private fun saveConfig(fileName: String, Language("XML") data: String): File {
|
||||
val file = File(testAppConfig, fileName)
|
||||
FileUtil.writeToFile(file, data)
|
||||
@@ -160,16 +158,12 @@ public class ApplicationStoreTest : LightPlatformTestCase() {
|
||||
init {
|
||||
val macroSubstitutor = ApplicationPathMacroManager().createTrackingSubstitutor()
|
||||
stateStorageManager = object : StateStorageManagerImpl(macroSubstitutor, "application", this, ApplicationManager.getApplication().getPicoContainer()) {
|
||||
override fun createStorageData(fileSpec: String, filePath: String): StorageData {
|
||||
return StorageData("application")
|
||||
}
|
||||
override fun createStorageData(fileSpec: String, filePath: String) = StorageData("application")
|
||||
|
||||
override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String? {
|
||||
return null
|
||||
}
|
||||
override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation) = null
|
||||
|
||||
override fun getMacroSubstitutor(fileSpec: String): TrackingPathMacroSubstitutor? {
|
||||
if (fileSpec == StoragePathMacros.APP_CONFIG + "/" + PathMacrosImpl.EXT_FILE_NAME + ".xml") {
|
||||
if (fileSpec == "${StoragePathMacros.APP_CONFIG}/${PathMacrosImpl.EXT_FILE_NAME}.xml") {
|
||||
return null
|
||||
}
|
||||
return super.getMacroSubstitutor(fileSpec)
|
||||
@@ -179,16 +173,12 @@ public class ApplicationStoreTest : LightPlatformTestCase() {
|
||||
stateStorageManager.addMacro(StoragePathMacros.APP_CONFIG, testAppConfigPath)
|
||||
}
|
||||
|
||||
override fun getStateStorageManager(): StateStorageManager {
|
||||
return stateStorageManager
|
||||
}
|
||||
override fun getStateStorageManager() = stateStorageManager
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
|
||||
override fun getMessageBus(): MessageBus {
|
||||
return ApplicationManager.getApplication().getMessageBus()
|
||||
}
|
||||
override fun getMessageBus() = ApplicationManager.getApplication().getMessageBus()
|
||||
}
|
||||
|
||||
abstract class Foo {
|
||||
@@ -208,9 +198,7 @@ public class ApplicationStoreTest : LightPlatformTestCase() {
|
||||
|
||||
State(name = "HttpConfigurable", storages = arrayOf(Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", deprecated = true), Storage(file = StoragePathMacros.APP_CONFIG + "/proxy.settings.xml")))
|
||||
class ActualStorageLast : Foo(), PersistentStateComponent<ActualStorageLast> {
|
||||
override fun getState(): ActualStorageLast? {
|
||||
return this
|
||||
}
|
||||
override fun getState() = this
|
||||
|
||||
override fun loadState(state: ActualStorageLast) {
|
||||
XmlSerializerUtil.copyBean(state, this)
|
||||
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* 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.components.impl;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.components.impl.stores.StateStorageManagerImpl;
|
||||
import com.intellij.openapi.components.impl.stores.StorageData;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.testFramework.LightPlatformTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author mike
|
||||
*/
|
||||
public class StateStorageManagerImplTest extends LightPlatformTestCase {
|
||||
private StateStorageManagerImpl myStateStorageManager;
|
||||
|
||||
@Override
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
TrackingPathMacroSubstitutor substitutor = PathMacroManager.getInstance(getProject()).createTrackingSubstitutor();
|
||||
myStateStorageManager = new StateStorageManagerImpl(substitutor, "foo", myTestRootDisposable, ApplicationManager.getApplication().getPicoContainer()) {
|
||||
@NotNull
|
||||
@Override
|
||||
protected StorageData createStorageData(@NotNull String fileSpec, @NotNull String filePath) {
|
||||
throw new UnsupportedOperationException("Method createStorageData not implemented in " + getClass());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected String getOldStorageSpec(@NotNull Object component, @NotNull String componentName, @NotNull StateStorageOperation operation) {
|
||||
throw new UnsupportedOperationException("Method getOldStorageSpec not implemented in " + getClass());
|
||||
}
|
||||
};
|
||||
myStateStorageManager.addMacro("$MACRO1$", "/temp/m1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() throws Exception {
|
||||
Disposer.dispose(myStateStorageManager);
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testCreateFileStateStorageMacroSubstituted() {
|
||||
StateStorage data = myStateStorageManager.getStateStorage("$MACRO1$/test.xml", RoamingType.PER_USER);
|
||||
assertThat(data, is(notNullValue()));
|
||||
}
|
||||
|
||||
public void testCreateStateStorageAssertionThrownWhenUnknownMacro() {
|
||||
try {
|
||||
myStateStorageManager.getStateStorage("$UNKNOWN_MACRO$/test.xml", RoamingType.PER_USER);
|
||||
fail("Exception expected");
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
assertEquals("Unknown macro: $UNKNOWN_MACRO$ in storage file spec: $UNKNOWN_MACRO$/test.xml", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testCreateFileStateStorageMacroSubstitutedWhenExpansionHas$() {
|
||||
myStateStorageManager.addMacro("$DOLLAR_MACRO$", "/temp/d$");
|
||||
StateStorage data = myStateStorageManager.getStateStorage("$DOLLAR_MACRO$/test.xml", RoamingType.PER_USER);
|
||||
assertThat(data, is(notNullValue()));
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.components.impl
|
||||
|
||||
import com.intellij.configurationStore.StateStorageManagerImpl
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.PathMacroManager
|
||||
import com.intellij.openapi.components.RoamingType
|
||||
import com.intellij.openapi.components.StateStorage
|
||||
import com.intellij.openapi.components.StateStorageOperation
|
||||
import com.intellij.openapi.components.impl.stores.StorageData
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.testFramework.LightPlatformTestCase
|
||||
import junit.framework.TestCase
|
||||
import org.hamcrest.CoreMatchers.`is`
|
||||
import org.hamcrest.CoreMatchers.notNullValue
|
||||
import org.junit.Assert.assertThat
|
||||
|
||||
/**
|
||||
* @author mike
|
||||
*/
|
||||
public class StateStorageManagerImplTest : LightPlatformTestCase() {
|
||||
private var myStateStorageManager: StateStorageManagerImpl? = null
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
val substitutor = PathMacroManager.getInstance(LightPlatformTestCase.getProject()).createTrackingSubstitutor()
|
||||
myStateStorageManager = object : StateStorageManagerImpl(substitutor, "foo", myTestRootDisposable, ApplicationManager.getApplication().getPicoContainer()) {
|
||||
override fun createStorageData(fileSpec: String, filePath: String): StorageData {
|
||||
throw UnsupportedOperationException("Method createStorageData not implemented in " + javaClass)
|
||||
}
|
||||
|
||||
override fun getOldStorageSpec(component: Any, componentName: String, operation: StateStorageOperation): String? {
|
||||
throw UnsupportedOperationException("Method getOldStorageSpec not implemented in " + javaClass)
|
||||
}
|
||||
}
|
||||
myStateStorageManager!!.addMacro("\$MACRO1$", "/temp/m1")
|
||||
}
|
||||
|
||||
override fun tearDown() {
|
||||
try {
|
||||
val storageManager = myStateStorageManager
|
||||
if (storageManager != null) {
|
||||
Disposer.dispose(storageManager)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
super.tearDown()
|
||||
}
|
||||
}
|
||||
|
||||
public fun testCreateFileStateStorageMacroSubstituted() {
|
||||
val data = myStateStorageManager!!.getStateStorage("\$MACRO1$/test.xml", RoamingType.PER_USER)
|
||||
assertThat<StateStorage>(data, `is`(notNullValue()))
|
||||
}
|
||||
|
||||
public fun testCreateStateStorageAssertionThrownWhenUnknownMacro() {
|
||||
try {
|
||||
myStateStorageManager!!.getStateStorage("\$UNKNOWN_MACRO$/test.xml", RoamingType.PER_USER)
|
||||
TestCase.fail("Exception expected")
|
||||
}
|
||||
catch (e: IllegalArgumentException) {
|
||||
TestCase.assertEquals("Unknown macro: \$UNKNOWN_MACRO$ in storage file spec: \$UNKNOWN_MACRO$/test.xml", e.getMessage())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public fun `testCreateFileStateStorageMacroSubstitutedWhenExpansionHas$`() {
|
||||
myStateStorageManager!!.addMacro("\$DOLLAR_MACRO$", "/temp/d$")
|
||||
val data = myStateStorageManager!!.getStateStorage("\$DOLLAR_MACRO$/test.xml", RoamingType.PER_USER)
|
||||
assertThat<StateStorage>(data, `is`(notNullValue()))
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,11 @@ import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ContentIterator;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileVisitor;
|
||||
import com.intellij.openapi.vfs.VirtualFileWithId;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.Consumer;
|
||||
@@ -145,6 +148,32 @@ public abstract class FileBasedIndex implements BaseComponent {
|
||||
return processAllKeys(indexId, processor, scope.getProject());
|
||||
}
|
||||
|
||||
public static void iterateRecursively(@Nullable final VirtualFile root,
|
||||
@NotNull final ContentIterator processor,
|
||||
@Nullable final ProgressIndicator indicator,
|
||||
@Nullable final Set<VirtualFile> visitedRoots,
|
||||
@Nullable final ProjectFileIndex projectFileIndex) {
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
VfsUtilCore.visitChildrenRecursively(root, new VirtualFileVisitor() {
|
||||
@Override
|
||||
public boolean visitFile(@NotNull VirtualFile file) {
|
||||
if (visitedRoots != null && !root.equals(file) && file.isDirectory() && !visitedRoots.add(file)) {
|
||||
return false; // avoid visiting files more than once, e.g. additional indexed roots intersect sometimes
|
||||
}
|
||||
if (projectFileIndex != null && projectFileIndex.isExcluded(file)) {
|
||||
return false;
|
||||
}
|
||||
if (indicator != null) indicator.checkCanceled();
|
||||
|
||||
processor.processFile(file);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface ValueProcessor<V> {
|
||||
/**
|
||||
* @param value a value to process
|
||||
|
||||
+14
@@ -18,18 +18,24 @@ package com.intellij.codeInsight.completion.impl;
|
||||
import com.intellij.codeInsight.completion.CompletionResult;
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet;
|
||||
import com.intellij.codeInsight.completion.PrefixMatcher;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.codeStyle.MinusculeMatcher;
|
||||
import com.intellij.util.containers.FList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class BetterPrefixMatcher extends PrefixMatcher {
|
||||
private final PrefixMatcher myOriginal;
|
||||
@Nullable private final CamelHumpMatcher myHumpMatcher;
|
||||
private final int myMinMatchingDegree;
|
||||
|
||||
public BetterPrefixMatcher(PrefixMatcher original, int minMatchingDegree) {
|
||||
super(original.getPrefix());
|
||||
myOriginal = original;
|
||||
myHumpMatcher = original instanceof CamelHumpMatcher ? (CamelHumpMatcher)original : null;
|
||||
myMinMatchingDegree = minMatchingDegree;
|
||||
}
|
||||
|
||||
@@ -47,6 +53,14 @@ public class BetterPrefixMatcher extends PrefixMatcher {
|
||||
|
||||
@Override
|
||||
public boolean prefixMatches(@NotNull String name) {
|
||||
if (myHumpMatcher != null) {
|
||||
FList<TextRange> fragments = myHumpMatcher.matchingFragments(name);
|
||||
if (fragments == null || !MinusculeMatcher.isStartMatch(fragments)) {
|
||||
return false;
|
||||
}
|
||||
return myHumpMatcher.matchingDegree(name, fragments) >= myMinMatchingDegree;
|
||||
}
|
||||
|
||||
if (!myOriginal.prefixMatches(name) || !myOriginal.isStartMatch(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+18
-8
@@ -1,4 +1,3 @@
|
||||
|
||||
package com.intellij.codeInsight.completion.impl;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
@@ -15,6 +14,7 @@ import com.intellij.psi.codeStyle.NameUtil;
|
||||
import com.intellij.util.containers.FList;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
/**
|
||||
@@ -139,15 +139,25 @@ public class CamelHumpMatcher extends PrefixMatcher {
|
||||
|
||||
@Override
|
||||
public int matchingDegree(String string) {
|
||||
FList<TextRange> ranges = myCaseInsensitiveMatcher.matchingFragments(string);
|
||||
if (ranges != null && !ranges.isEmpty()) {
|
||||
int matchStart = ranges.get(0).getStartOffset();
|
||||
int underscoreEnd = skipUnderscores(string);
|
||||
if (matchStart > 0 && matchStart <= underscoreEnd) {
|
||||
return myCaseInsensitiveMatcher.matchingDegree(string.substring(matchStart), true) - 1;
|
||||
return matchingDegree(string, matchingFragments(string));
|
||||
}
|
||||
|
||||
public FList<TextRange> matchingFragments(String string) {
|
||||
return myMatcher.matchingFragments(string);
|
||||
}
|
||||
|
||||
public int matchingDegree(String string, @Nullable FList<TextRange> fragments) {
|
||||
int underscoreEnd = skipUnderscores(string);
|
||||
if (underscoreEnd > 0) {
|
||||
FList<TextRange> ciRanges = myCaseInsensitiveMatcher.matchingFragments(string);
|
||||
if (ciRanges != null && !ciRanges.isEmpty()) {
|
||||
int matchStart = ciRanges.get(0).getStartOffset();
|
||||
if (matchStart > 0 && matchStart <= underscoreEnd) {
|
||||
return myCaseInsensitiveMatcher.matchingDegree(string.substring(matchStart), true) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return myMatcher.matchingDegree(string, true);
|
||||
return myMatcher.matchingDegree(string, true, fragments);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -22,6 +22,7 @@ import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiCompiledElement;
|
||||
import com.intellij.psi.PsiElement;
|
||||
@@ -31,6 +32,7 @@ import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.proximity.PsiProximityComparator;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.FList;
|
||||
import com.intellij.util.indexing.FindSymbolParameters;
|
||||
import com.intellij.util.indexing.IdFilter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -373,7 +375,8 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
return null; // no matches appears valid result for "bad" pattern
|
||||
}
|
||||
}
|
||||
return matcher.matches(name) ? new MatchResult(name, matcher.matchingDegree(name), matcher.isStartMatch(name)) : null;
|
||||
FList<TextRange> fragments = matcher.matchingFragments(name);
|
||||
return fragments != null ? new MatchResult(name, matcher.matchingDegree(name, false, fragments), MinusculeMatcher.isStartMatch(fragments)) : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -2652,32 +2652,6 @@ public class FileBasedIndexImpl extends FileBasedIndex {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
private static void iterateRecursively(@Nullable final VirtualFile root,
|
||||
@NotNull final ContentIterator processor,
|
||||
@Nullable final ProgressIndicator indicator,
|
||||
@Nullable final Set<VirtualFile> visitedRoots,
|
||||
@Nullable final ProjectFileIndex projectFileIndex) {
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
VfsUtilCore.visitChildrenRecursively(root, new VirtualFileVisitor() {
|
||||
@Override
|
||||
public boolean visitFile(@NotNull VirtualFile file) {
|
||||
if (visitedRoots != null && !root.equals(file) && file.isDirectory() && !visitedRoots.add(file)) {
|
||||
return false; // avoid visiting files more than once, e.g. additional indexed roots intersect sometimes
|
||||
}
|
||||
if (projectFileIndex != null && projectFileIndex.isExcluded(file)) {
|
||||
return false;
|
||||
}
|
||||
if (indicator != null) indicator.checkCanceled();
|
||||
|
||||
processor.processFile(file);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings({"WhileLoopSpinsOnField", "SynchronizeOnThis"})
|
||||
private static class StorageGuard {
|
||||
private int myHolds = 0;
|
||||
|
||||
@@ -239,7 +239,16 @@ public class LoadingDecorator {
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return myContent != null ? myContent.getMinimumSize() : super.getMinimumSize();
|
||||
return myContent != null && !isMinimumSizeSet()
|
||||
? myContent.getMinimumSize()
|
||||
: super.getMinimumSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return myContent != null && !isPreferredSizeSet()
|
||||
? myContent.getPreferredSize()
|
||||
: super.getPreferredSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -204,7 +204,6 @@ public class ExportSettingsAction extends AnAction implements DumbAware {
|
||||
storage.scheme() == StorageScheme.DEFAULT &&
|
||||
!StringUtil.isEmpty(storage.file()) &&
|
||||
storage.file().startsWith(StoragePathMacros.APP_CONFIG)) {
|
||||
File file = new File(storageManager.expandMacros(storage.file()));
|
||||
|
||||
File additionalExportFile = null;
|
||||
if (!StringUtil.isEmpty(stateAnnotation.additionalExportFile())) {
|
||||
@@ -219,6 +218,7 @@ public class ExportSettingsAction extends AnAction implements DumbAware {
|
||||
}
|
||||
}
|
||||
|
||||
File file = new File(storageManager.expandMacros(storage.file()));
|
||||
boolean fileExists = !onlyExisting || file.exists();
|
||||
if (fileExists || additionalExportFile != null) {
|
||||
File[] files;
|
||||
|
||||
@@ -74,6 +74,7 @@ import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.intellij.openapi.util.text.StringUtil.isEmptyOrSpaces;
|
||||
@@ -326,7 +327,7 @@ public abstract class PluginManagerMain implements Disposable {
|
||||
@Override
|
||||
public void run() {
|
||||
final List<IdeaPluginDescriptor> list = ContainerUtil.newArrayList();
|
||||
final List<String> errors = ContainerUtil.newSmartList();
|
||||
final Map<String, String> errors = ContainerUtil.newLinkedHashMap();
|
||||
ProgressIndicator indicator = new EmptyProgressIndicator();
|
||||
|
||||
List<String> hosts = RepositoryHelper.getPluginHosts();
|
||||
@@ -348,7 +349,7 @@ public abstract class PluginManagerMain implements Disposable {
|
||||
catch (IOException e) {
|
||||
LOG.info(host, e);
|
||||
if (host != ApplicationInfoEx.getInstanceEx().getBuiltinPluginsUrl()) {
|
||||
errors.add(String.format("'%s' for '%s'", e.getMessage(), host));
|
||||
errors.put(host, String.format("'%s' for '%s'", e.getMessage(), host));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -369,7 +370,9 @@ public abstract class PluginManagerMain implements Disposable {
|
||||
}
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
String message = IdeBundle.message("error.list.of.plugins.was.not.loaded", StringUtil.join(errors, ", "));
|
||||
String message = IdeBundle.message("error.list.of.plugins.was.not.loaded",
|
||||
StringUtil.join(errors.keySet(), ", "),
|
||||
StringUtil.join(errors.values(), ",\n"));
|
||||
String title = IdeBundle.message("title.plugins");
|
||||
String ok = CommonBundle.message("button.retry"), cancel = CommonBundle.getCancelButtonText();
|
||||
if (Messages.showOkCancelDialog(message, title, ok, cancel, Messages.getErrorIcon()) == Messages.OK) {
|
||||
|
||||
-2
@@ -26,8 +26,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
* @see com.intellij.openapi.project.ex.ProjectEx#getStateStore()
|
||||
*/
|
||||
public interface IProjectStore extends IComponentStore {
|
||||
boolean checkVersion();
|
||||
|
||||
void setProjectFilePath(@NotNull String filePath);
|
||||
|
||||
@Nullable
|
||||
|
||||
+9
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -32,12 +32,12 @@ import com.intellij.openapi.project.ex.ProjectManagerEx;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.projectImport.ProjectOpenProcessor;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public interface MergeVersion {
|
||||
@@ -120,12 +120,12 @@ public interface MergeVersion {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Runnable prepareToReportChangedProjectFiles(@NotNull final Project project, final Collection<VirtualFile> files) {
|
||||
final Set<VirtualFile> vfs = new HashSet<VirtualFile>();
|
||||
for (VirtualFile vf : files) {
|
||||
if (vf != null && ! vf.isDirectory()) {
|
||||
if (ProjectCoreUtil.isProjectOrWorkspaceFile(vf) || isProjectFile(vf)) {
|
||||
vfs.add(vf);
|
||||
public static Runnable prepareToReportChangedProjectFiles(@NotNull final Project project, @NotNull Collection<VirtualFile> files) {
|
||||
final Set<VirtualFile> vfs = new THashSet<VirtualFile>();
|
||||
for (VirtualFile file : files) {
|
||||
if (file != null && !file.isDirectory()) {
|
||||
if (ProjectCoreUtil.isProjectOrWorkspaceFile(file) || isProjectFile(file)) {
|
||||
vfs.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,8 +168,7 @@ public interface MergeVersion {
|
||||
@Override
|
||||
public byte[] getBytes() throws IOException {
|
||||
VirtualFile file = getFile();
|
||||
if (file != null) return file.contentsToByteArray();
|
||||
return myDocument.getText().getBytes();
|
||||
return file != null ? file.contentsToByteArray() : myDocument.getText().getBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -191,6 +191,7 @@ final class SettingsEditor extends AbstractEditor implements DataProvider {
|
||||
mySettings.select(configurable);
|
||||
}
|
||||
};
|
||||
myEditor.setPreferredSize(JBUI.size(800, 600));
|
||||
myLoadingDecorator = new LoadingDecorator(myEditor, this, 10, true);
|
||||
myBanner = new Banner(myEditor.getResetAction());
|
||||
mySearchPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||
|
||||
+2
-9
@@ -79,8 +79,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
public class ProjectManagerImpl extends ProjectManagerEx implements PersistentStateComponent<Element>, ExportableApplicationComponent {
|
||||
private static final Logger LOG = Logger.getInstance(ProjectManagerImpl.class);
|
||||
|
||||
public static final int CURRENT_FORMAT_VERSION = 4;
|
||||
|
||||
private static final Key<List<ProjectManagerListener>> LISTENERS_IN_PROJECT_KEY = Key.create("LISTENERS_IN_PROJECT_KEY");
|
||||
private static final Key<MultiMap<StateStorage, VirtualFile>> CHANGED_FILES_KEY = Key.create("CHANGED_FILES_KEY");
|
||||
|
||||
@@ -427,13 +425,10 @@ public class ProjectManagerImpl extends ProjectManagerEx implements PersistentSt
|
||||
}
|
||||
}
|
||||
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
if (!application.isUnitTestMode() && !((ProjectEx)project).getStateStore().checkVersion()) {
|
||||
if (!addToOpened(project)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addToOpened(project)) return false;
|
||||
|
||||
fireProjectOpened(project);
|
||||
DumbService.getInstance(project).queueTask(new DumbModeTask() {
|
||||
@Override
|
||||
@@ -1003,9 +998,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements PersistentSt
|
||||
@Override
|
||||
public void loadState(Element state) {
|
||||
myDefaultProjectRootElement = state.getChild("defaultProject");
|
||||
if (myDefaultProjectRootElement != null) {
|
||||
myDefaultProjectRootElement.detach();
|
||||
}
|
||||
if (myDefaultProjectRootElement != null) myDefaultProjectRootElement.detach();
|
||||
myDefaultProjectConfigurationChanged = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -517,7 +517,7 @@ ide.postpone.action=Postpone
|
||||
title.plugins=Plugins
|
||||
title.plugins.changed=Plugins Changed
|
||||
plugin.status.not.specified=(not specified)
|
||||
error.list.of.plugins.was.not.loaded=Unable to update the list of plugins due to the following error: {0}
|
||||
error.list.of.plugins.was.not.loaded=List of plugins was not loaded for following hosts: {0}\n\nDue to the following errors:\n{1}
|
||||
action.download.and.install.plugin=Download and Install
|
||||
action.update.plugin=Update Plugin
|
||||
error.plugin.download.failed=Plugin download failed
|
||||
|
||||
@@ -327,7 +327,7 @@
|
||||
<projectService serviceInterface="com.intellij.openapi.roots.impl.LibraryScopeCache"
|
||||
serviceImplementation="com.intellij.openapi.roots.impl.LibraryScopeCache"/>
|
||||
|
||||
<moduleService serviceInterface="com.intellij.openapi.components.impl.stores.IComponentStore" serviceImplementation="com.intellij.openapi.components.impl.stores.ModuleStoreImpl"/>
|
||||
<moduleService serviceInterface="com.intellij.openapi.components.impl.stores.IComponentStore" serviceImplementation="com.intellij.configurationStore.ModuleStoreImpl"/>
|
||||
<moduleService serviceInterface="com.intellij.openapi.components.PathMacroManager" serviceImplementation="com.intellij.openapi.components.impl.ModulePathMacroManager"/>
|
||||
|
||||
<projectViewPane implementation="com.intellij.ide.scratch.ScratchProjectViewPane"/>
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
<appStarter implementation="com.intellij.help.impl.KeymapGenerator"/>
|
||||
|
||||
<applicationService serviceInterface="com.intellij.openapi.components.impl.stores.IComponentStore"
|
||||
serviceImplementation="com.intellij.openapi.components.impl.stores.ApplicationStoreImpl"/>
|
||||
serviceImplementation="com.intellij.configurationStore.ApplicationStoreImpl"/>
|
||||
<applicationService serviceInterface="com.intellij.openapi.components.PathMacroManager"
|
||||
serviceImplementation="com.intellij.openapi.components.impl.ApplicationPathMacroManager"/>
|
||||
serviceImplementation="com.intellij.configurationStore.ApplicationPathMacroManager"/>
|
||||
|
||||
<applicationService serviceImplementation="com.intellij.ide.GeneralSettings"/>
|
||||
<applicationService serviceInterface="com.intellij.ide.util.PropertiesComponent"
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</component>
|
||||
<component>
|
||||
<interface-class>com.intellij.openapi.project.impl.ProjectStoreClassProvider</interface-class>
|
||||
<implementation-class>com.intellij.openapi.components.impl.stores.PlatformProjectStoreClassProvider</implementation-class>
|
||||
<implementation-class>com.intellij.configurationStore.PlatformProjectStoreClassProvider</implementation-class>
|
||||
</component>
|
||||
</application-components>
|
||||
<project-components>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</component>
|
||||
<component>
|
||||
<interface-class>com.intellij.openapi.project.impl.ProjectStoreClassProvider</interface-class>
|
||||
<implementation-class>com.intellij.openapi.components.impl.stores.PlatformLangProjectStoreClassProvider</implementation-class>
|
||||
<implementation-class>com.intellij.configurationStore.PlatformLangProjectStoreClassProvider</implementation-class>
|
||||
</component>
|
||||
</application-components>
|
||||
<project-components>
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ public class StorageData extends StorageDataBase {
|
||||
myRootElementName = rootElementName;
|
||||
}
|
||||
|
||||
StorageData(@NotNull StorageData storageData) {
|
||||
protected StorageData(@NotNull StorageData storageData) {
|
||||
myRootElementName = storageData.myRootElementName;
|
||||
myStates = new StateMap(storageData.myStates);
|
||||
}
|
||||
|
||||
@@ -36,11 +36,6 @@ import java.util.Set;
|
||||
* @author peter
|
||||
*/
|
||||
public class MockProjectStore implements IProjectStore {
|
||||
@Override
|
||||
public boolean checkVersion() {
|
||||
throw new UnsupportedOperationException("Method checkVersion is not yet implemented in " + getClass().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProjectFilePath(@NotNull final String filePath) {
|
||||
throw new UnsupportedOperationException("Method setProjectFilePath is not yet implemented in " + getClass().getName());
|
||||
|
||||
+1
-1
@@ -1943,7 +1943,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
|
||||
@Override
|
||||
public void assertPreferredCompletionItems(final int selected, @NotNull @NonNls final String... expected) {
|
||||
final LookupImpl lookup = getLookup();
|
||||
Assert.assertNotNull(lookup);
|
||||
Assert.assertNotNull("No lookup is shown", lookup);
|
||||
|
||||
final JList list = lookup.getList();
|
||||
List<String> strings = getLookupElementStrings();
|
||||
|
||||
@@ -162,11 +162,14 @@ public class MinusculeMatcher implements Matcher {
|
||||
}
|
||||
|
||||
public int matchingDegree(@NotNull String name, boolean valueStartCaseMatch) {
|
||||
FList<TextRange> iterable = matchingFragments(name);
|
||||
if (iterable == null) return Integer.MIN_VALUE;
|
||||
if (iterable.isEmpty()) return 0;
|
||||
return matchingDegree(name, valueStartCaseMatch, matchingFragments(name));
|
||||
}
|
||||
|
||||
final TextRange first = iterable.getHead();
|
||||
public int matchingDegree(@NotNull String name, boolean valueStartCaseMatch, @Nullable FList<TextRange> fragments) {
|
||||
if (fragments == null) return Integer.MIN_VALUE;
|
||||
if (fragments.isEmpty()) return 0;
|
||||
|
||||
final TextRange first = fragments.getHead();
|
||||
boolean startMatch = first.getStartOffset() == 0;
|
||||
|
||||
int matchingCase = 0;
|
||||
@@ -175,7 +178,7 @@ public class MinusculeMatcher implements Matcher {
|
||||
int integral = 0; // -sum of matching-char-count * hump-index over all matched humps; favors longer fragments matching earlier words
|
||||
int humpIndex = 1;
|
||||
int nextHumpStart = 0;
|
||||
for (TextRange range : iterable) {
|
||||
for (TextRange range : fragments) {
|
||||
for (int i = range.getStartOffset(); i < range.getEndOffset(); i++) {
|
||||
boolean isHumpStart = false;
|
||||
while (nextHumpStart <= i) {
|
||||
@@ -198,7 +201,7 @@ public class MinusculeMatcher implements Matcher {
|
||||
if (c == myPattern[p]) {
|
||||
if (isUpperCase[p]) matchingCase += 50; // strongly prefer user's uppercase matching uppercase: they made an effort to press Shift
|
||||
else if (i == 0 && startMatch) matchingCase += 15; // the very first letter case distinguishes classes in Java etc
|
||||
else if (isHumpStart) matchingCase += 1; // if a lowercase matches lowercase hump start, that also means something
|
||||
else if (isHumpStart) matchingCase += 1; // if a lowercase matches lowercase hump start, that also means something
|
||||
} else if (isHumpStart) {
|
||||
// disfavor hump starts where pattern letter case doesn't match name case
|
||||
matchingCase -= 1;
|
||||
@@ -209,25 +212,24 @@ public class MinusculeMatcher implements Matcher {
|
||||
int startIndex = first.getStartOffset();
|
||||
boolean afterSeparator = StringUtil.indexOfAny(name, myHardSeparators, 0, startIndex) >= 0;
|
||||
boolean wordStart = startIndex == 0 || isWordStart(name, startIndex) && !isWordStart(name, startIndex - 1);
|
||||
boolean finalMatch = iterable.get(iterable.size() - 1).getEndOffset() == name.length();
|
||||
boolean finalMatch = fragments.get(fragments.size() - 1).getEndOffset() == name.length();
|
||||
|
||||
return (wordStart ? 1000 : 0) +
|
||||
integral * 10 +
|
||||
return (wordStart ? 1000 : 0) +
|
||||
integral * 10 +
|
||||
matchingCase * (startMatch && valueStartCaseMatch ? 10 : 1) +
|
||||
(afterSeparator ? 0 : 2) +
|
||||
(afterSeparator ? 0 : 2) +
|
||||
(startMatch ? 1 : 0) +
|
||||
(finalMatch ? 1 : 0);
|
||||
}
|
||||
|
||||
public boolean isStartMatch(@NotNull String name) {
|
||||
Iterable<TextRange> fragments = matchingFragments(name);
|
||||
if (fragments != null) {
|
||||
Iterator<TextRange> iterator = fragments.iterator();
|
||||
if (!iterator.hasNext() || iterator.next().getStartOffset() == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
FList<TextRange> fragments = matchingFragments(name);
|
||||
return fragments != null && isStartMatch(fragments);
|
||||
}
|
||||
|
||||
public static boolean isStartMatch(@NotNull Iterable<TextRange> fragments) {
|
||||
Iterator<TextRange> iterator = fragments.iterator();
|
||||
return !iterator.hasNext() || iterator.next().getStartOffset() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -319,7 +319,7 @@ public class VcsUtil {
|
||||
return VcsContextFactory.SERVICE.getInstance().createFilePathOn(file);
|
||||
}
|
||||
|
||||
public static FilePath getFilePath(File file) {
|
||||
public static FilePath getFilePath(@NotNull File file) {
|
||||
return VcsContextFactory.SERVICE.getInstance().createFilePathOn(file);
|
||||
}
|
||||
|
||||
@@ -331,11 +331,11 @@ public class VcsUtil {
|
||||
return VcsContextFactory.SERVICE.getInstance().createFilePathOnNonLocal(path, isDirectory);
|
||||
}
|
||||
|
||||
public static FilePath getFilePath(File file, boolean isDirectory) {
|
||||
public static FilePath getFilePath(@NotNull File file, boolean isDirectory) {
|
||||
return VcsContextFactory.SERVICE.getInstance().createFilePathOn(file, isDirectory);
|
||||
}
|
||||
|
||||
public static FilePath getFilePathForDeletedFile(String path, boolean isDirectory) {
|
||||
public static FilePath getFilePathForDeletedFile(@NotNull String path, boolean isDirectory) {
|
||||
return VcsContextFactory.SERVICE.getInstance().createFilePathOnDeleted(new File(path), isDirectory);
|
||||
}
|
||||
|
||||
|
||||
+9
-24
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2015 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,34 +29,15 @@ public class EquivalenceChecker {
|
||||
private EquivalenceChecker() {}
|
||||
|
||||
public static boolean statementsAreEquivalent(@Nullable PsiStatement statement1, @Nullable PsiStatement statement2) {
|
||||
statement1 = ControlFlowUtils.stripBraces(statement1);
|
||||
statement2 = ControlFlowUtils.stripBraces(statement2);
|
||||
if (statement1 == null) {
|
||||
return statement2 == null;
|
||||
} else if (statement2 == null) {
|
||||
return false;
|
||||
}
|
||||
if (statement1.getClass() != statement2.getClass()) {
|
||||
if (statement1 instanceof PsiBlockStatement && !(statement2 instanceof PsiBlockStatement)) {
|
||||
final PsiBlockStatement blockStatement = (PsiBlockStatement)statement1;
|
||||
final PsiStatement[] statements = blockStatement.getCodeBlock().getStatements();
|
||||
if (statements.length != 1) {
|
||||
return false;
|
||||
}
|
||||
statement1 = statements[0];
|
||||
}
|
||||
else if (!(statement1 instanceof PsiBlockStatement) && statement2 instanceof PsiBlockStatement) {
|
||||
final PsiBlockStatement blockStatement = (PsiBlockStatement)statement2;
|
||||
final PsiStatement[] statements = blockStatement.getCodeBlock().getStatements();
|
||||
if (statements.length != 1) {
|
||||
return false;
|
||||
}
|
||||
statement2 = statements[0];
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
if (statement1.getClass() != statement2.getClass()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (statement1 instanceof PsiAssertStatement) {
|
||||
return assertStatementsAreEquivalent((PsiAssertStatement)statement1, (PsiAssertStatement)statement2);
|
||||
@@ -698,8 +679,12 @@ public class EquivalenceChecker {
|
||||
if (classReference1 == null || classReference2 == null) {
|
||||
return false;
|
||||
}
|
||||
final String text = classReference1.getText();
|
||||
if (!text.equals(classReference2.getText())) {
|
||||
final PsiElement target1 = classReference1.resolve();
|
||||
if (target1 == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement target2 = classReference2.resolve();
|
||||
if (!target1.equals(target2)) {
|
||||
return false;
|
||||
}
|
||||
final PsiExpression[] arrayDimensions1 =
|
||||
|
||||
+19
@@ -28,4 +28,23 @@ class S {
|
||||
void m() {
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
class A {
|
||||
void f() {
|
||||
new X();
|
||||
}
|
||||
|
||||
class X {}
|
||||
}
|
||||
class BB extends A {
|
||||
void f() {
|
||||
new X();
|
||||
}
|
||||
|
||||
class X {}
|
||||
}
|
||||
class CC extends A {
|
||||
void <warning descr="Method 'f()' is identical to its super method">f</warning>() {
|
||||
new X();
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
package org.jetbrains.settingsRepository
|
||||
|
||||
import com.intellij.configurationStore.ComponentStoreImpl
|
||||
import com.intellij.configurationStore.SchemeManagerFactoryBase
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.WriteAction
|
||||
import com.intellij.openapi.application.impl.ApplicationImpl
|
||||
import com.intellij.openapi.components.impl.stores.ComponentStoreImpl
|
||||
import com.intellij.openapi.components.impl.stores.FileBasedStorage
|
||||
import com.intellij.openapi.components.impl.stores.IComponentStore
|
||||
import com.intellij.openapi.components.impl.stores.StoreUtil
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</component>
|
||||
<component>
|
||||
<interface-class>com.intellij.openapi.project.impl.ProjectStoreClassProvider</interface-class>
|
||||
<implementation-class>com.intellij.openapi.components.impl.stores.PlatformLangProjectStoreClassProvider</implementation-class>
|
||||
<implementation-class>com.intellij.configurationStore.PlatformLangProjectStoreClassProvider</implementation-class>
|
||||
</component>
|
||||
</application-components>
|
||||
<project-components>
|
||||
|
||||
@@ -15,12 +15,15 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.editorActions;
|
||||
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
|
||||
/**
|
||||
* @author Dennis.Ushakov
|
||||
*/
|
||||
public class EscapeEntitiesActionTest extends LightCodeInsightFixtureTestCase {
|
||||
private static final String NDASH = new String(new byte[]{-30, -128, -109}, CharsetToolkit.UTF8_CHARSET);
|
||||
|
||||
public void testSimpleHtml() {
|
||||
doTest("<<<", "html", "<<<");
|
||||
}
|
||||
@@ -30,11 +33,11 @@ public class EscapeEntitiesActionTest extends LightCodeInsightFixtureTestCase {
|
||||
}
|
||||
|
||||
public void testWide() {
|
||||
doTest("\u2013", "html", "–");
|
||||
doTest(NDASH, "html", "–");
|
||||
}
|
||||
|
||||
public void testAttributeValue() {
|
||||
doTest("<a alt='\u2013'></a>", "html", "<a alt='–'></a>");
|
||||
doTest("<a alt='" + NDASH + "'></a>", "html", "<a alt='–'></a>");
|
||||
}
|
||||
|
||||
public void testTag() {
|
||||
|
||||
Reference in New Issue
Block a user