1 package com
.intellij
.openapi
.project
.impl
;
3 import com
.intellij
.diagnostic
.PluginException
;
4 import com
.intellij
.ide
.plugins
.IdeaPluginDescriptor
;
5 import com
.intellij
.ide
.plugins
.PluginManager
;
6 import com
.intellij
.ide
.startup
.StartupManagerEx
;
7 import com
.intellij
.notification
.NotificationsManager
;
8 import com
.intellij
.openapi
.application
.Application
;
9 import com
.intellij
.openapi
.application
.ApplicationManager
;
10 import com
.intellij
.openapi
.application
.ApplicationNamesInfo
;
11 import com
.intellij
.openapi
.application
.PathMacros
;
12 import com
.intellij
.openapi
.application
.ex
.ApplicationEx
;
13 import com
.intellij
.openapi
.application
.ex
.ApplicationManagerEx
;
14 import com
.intellij
.openapi
.components
.ProjectComponent
;
15 import com
.intellij
.openapi
.components
.TrackingPathMacroSubstitutor
;
16 import com
.intellij
.openapi
.components
.impl
.ComponentManagerImpl
;
17 import com
.intellij
.openapi
.components
.impl
.ProjectPathMacroManager
;
18 import com
.intellij
.openapi
.components
.impl
.stores
.IComponentStore
;
19 import com
.intellij
.openapi
.components
.impl
.stores
.IProjectStore
;
20 import com
.intellij
.openapi
.components
.impl
.stores
.UnknownMacroNotification
;
21 import com
.intellij
.openapi
.diagnostic
.Logger
;
22 import com
.intellij
.openapi
.extensions
.ExtensionPointName
;
23 import com
.intellij
.openapi
.extensions
.Extensions
;
24 import com
.intellij
.openapi
.project
.Project
;
25 import com
.intellij
.openapi
.project
.ProjectBundle
;
26 import com
.intellij
.openapi
.project
.ProjectManagerAdapter
;
27 import com
.intellij
.openapi
.project
.ex
.ProjectEx
;
28 import com
.intellij
.openapi
.project
.ex
.ProjectManagerEx
;
29 import com
.intellij
.openapi
.ui
.Messages
;
30 import com
.intellij
.openapi
.ui
.ex
.MessagesEx
;
31 import com
.intellij
.openapi
.util
.Condition
;
32 import com
.intellij
.openapi
.util
.Key
;
33 import com
.intellij
.openapi
.util
.text
.StringUtil
;
34 import com
.intellij
.openapi
.vfs
.VirtualFile
;
35 import org
.jetbrains
.annotations
.NonNls
;
36 import org
.jetbrains
.annotations
.NotNull
;
37 import org
.jetbrains
.annotations
.Nullable
;
38 import org
.picocontainer
.*;
39 import org
.picocontainer
.defaults
.CachingComponentAdapter
;
40 import org
.picocontainer
.defaults
.ConstructorInjectionComponentAdapter
;
42 import java
.io
.IOException
;
43 import java
.text
.MessageFormat
;
45 import java
.util
.concurrent
.atomic
.AtomicBoolean
;
51 public class ProjectImpl
extends ComponentManagerImpl
implements ProjectEx
{
52 private static final Logger LOG
= Logger
.getInstance("#com.intellij.project.impl.ProjectImpl");
54 private ProjectManagerImpl myManager
;
56 private MyProjectManagerListener myProjectManagerListener
;
58 private AtomicBoolean mySavingInProgress
= new AtomicBoolean(false);
60 @NonNls private static final String PROJECT_LAYER
= "project-components";
62 public boolean myOptimiseTestLoadSpeed
;
63 @NonNls public static final String TEMPLATE_PROJECT_NAME
= "Default (Template) Project";
64 @NonNls private static final String DEPRECATED_MESSAGE
= "Deprecated method usage: {0}.\n" +
65 "This method will cease to exist in IDEA 7.0 final release.\n" +
66 "Please contact plugin developers for plugin update.";
68 private final Condition myDisposedCondition
= new Condition() {
69 public boolean value(final Object o
) {
73 private final String myName
;
75 public static Key
<Long
> CREATION_TIME
= Key
.create("ProjectImpl.CREATION_TIME");
77 protected ProjectImpl(ProjectManagerImpl manager
, String filePath
, boolean isOptimiseTestLoadSpeed
, String projectName
) {
78 super(ApplicationManager
.getApplication());
79 putUserData(CREATION_TIME
, System
.nanoTime());
81 getPicoContainer().registerComponentInstance(Project
.class, this);
83 getStateStore().setProjectFilePath(filePath
);
85 myOptimiseTestLoadSpeed
= isOptimiseTestLoadSpeed
;
88 myName
= isDefault() ? TEMPLATE_PROJECT_NAME
: projectName
== null ?
getStateStore().getProjectName() : projectName
;
91 protected void boostrapPicoContainer() {
92 Extensions
.instantiateArea(PluginManager
.AREA_IDEA_PROJECT
, this, null);
93 super.boostrapPicoContainer();
94 final MutablePicoContainer picoContainer
= getPicoContainer();
96 final ProjectStoreClassProvider projectStoreClassProvider
= (ProjectStoreClassProvider
)picoContainer
.getComponentInstanceOfType(ProjectStoreClassProvider
.class);
99 picoContainer
.registerComponentImplementation(ProjectPathMacroManager
.class);
100 picoContainer
.registerComponent(new ComponentAdapter() {
101 ComponentAdapter myDelegate
;
104 public ComponentAdapter
getDelegate() {
105 if (myDelegate
== null) {
107 final Class storeClass
= projectStoreClassProvider
.getProjectStoreClass(isDefault());
108 myDelegate
= new CachingComponentAdapter(
109 new ConstructorInjectionComponentAdapter(storeClass
, storeClass
, null, true));
115 public Object
getComponentKey() {
116 return IComponentStore
.class;
119 public Class
getComponentImplementation() {
120 return getDelegate().getComponentImplementation();
123 public Object
getComponentInstance(final PicoContainer container
) throws PicoInitializationException
, PicoIntrospectionException
{
124 return getDelegate().getComponentInstance(container
);
127 public void verify(final PicoContainer container
) throws PicoIntrospectionException
{
128 getDelegate().verify(container
);
131 public void accept(final PicoVisitor visitor
) {
132 visitor
.visitComponentAdapter(this);
133 getDelegate().accept(visitor
);
140 public IProjectStore
getStateStore() {
141 return (IProjectStore
)super.getStateStore();
144 public boolean isOpen() {
145 return ProjectManagerEx
.getInstanceEx().isProjectOpened(this);
148 public Condition
getDisposed() {
149 return myDisposedCondition
;
152 public boolean isInitialized() {
153 return isOpen() && !isDisposed() && StartupManagerEx
.getInstanceEx(this).startupActivityPassed();
156 public void loadProjectComponents() {
157 final Application app
= ApplicationManager
.getApplication();
158 final IdeaPluginDescriptor
[] plugins
= app
.getPlugins();
159 for (IdeaPluginDescriptor plugin
: plugins
) {
160 if (PluginManager
.shouldSkipPlugin(plugin
)) continue;
161 loadComponentsConfiguration(plugin
.getProjectComponents(), plugin
, isDefault());
167 public String
getProjectFilePath() {
169 MessageFormat
.format(DEPRECATED_MESSAGE
, "ProjectImpl.getProjectFilePath()"),
171 return getStateStore().getProjectFilePath();
177 public VirtualFile
getProjectFile() {
179 MessageFormat
.format(DEPRECATED_MESSAGE
, "ProjectImpl.getProjectFile()"),
181 return getStateStore().getProjectFile();
185 public VirtualFile
getBaseDir() {
186 return getStateStore().getProjectBaseDir();
190 public String
getName() {
196 public String
getPresentableUrl() {
197 return getStateStore().getPresentableUrl();
202 public String
getLocationHash() {
203 String str
= getPresentableUrl();
204 if (str
== null) str
= getName();
206 return getName() + Integer
.toHexString(str
.hashCode());
211 public String
getLocation() {
212 return getStateStore().getLocation();
217 public VirtualFile
getWorkspaceFile() {
219 MessageFormat
.format(DEPRECATED_MESSAGE
, "ProjectImpl.getWorkspaceFile()"),
221 return getStateStore().getWorkspaceFile();
224 public boolean isOptimiseTestLoadSpeed() {
225 return myOptimiseTestLoadSpeed
;
228 public void setOptimiseTestLoadSpeed(final boolean optimiseTestLoadSpeed
) {
229 myOptimiseTestLoadSpeed
= optimiseTestLoadSpeed
;
235 getMessageBus().syncPublisher(ProjectLifecycleListener
.TOPIC
).projectComponentsInitialized(this);
236 myProjectManagerListener
= new MyProjectManagerListener();
237 myManager
.addProjectManagerListener(this, myProjectManagerListener
);
241 if (ApplicationManagerEx
.getApplicationEx().isDoNotSave()) return; //no need to save
243 if (mySavingInProgress
.compareAndSet(false, true)) {
247 catch (IComponentStore
.SaveCancelledException e
) {
250 catch (PluginException e
) {
251 PluginManager
.disablePlugin(e
.getPluginId().getIdString());
252 MessagesEx
.error(this, "The plugin " +
254 " failed to save settings and has been disabled. Please restart " +
255 ApplicationNamesInfo
.getInstance().getFullProductName() +
256 (ApplicationManagerEx
.getApplicationEx().isInternal() ?
"\n" + StringUtil
.getThrowableText(e
) : ""));
258 catch (IOException e
) {
259 MessagesEx
.error(this, ProjectBundle
.message("project.save.error", ApplicationManagerEx
.getApplicationEx().isInternal()
260 ? StringUtil
.getThrowableText(e
)
261 : e
.getMessage())).showLater();
263 mySavingInProgress
.set(false);
268 public synchronized void dispose() {
269 ApplicationEx application
= ApplicationManagerEx
.getApplicationEx();
270 assert application
.isHeadlessEnvironment() || application
.isUnitTestMode() || application
.isDispatchThread() || application
.isInModalProgressThread();
271 LOG
.assertTrue(!isDisposed());
272 if (myProjectManagerListener
!= null) {
273 myManager
.removeProjectManagerListener(this, myProjectManagerListener
);
277 Extensions
.disposeArea(this);
279 myProjectManagerListener
= null;
283 if (!application
.isDisposed()) {
284 application
.getMessageBus().syncPublisher(ProjectLifecycleListener
.TOPIC
).afterProjectClosed(this);
288 private void projectOpened() {
289 final ProjectComponent
[] components
= getComponents(ProjectComponent
.class);
290 for (ProjectComponent component
: components
) {
292 component
.projectOpened();
294 catch (Throwable e
) {
301 private void projectClosed() {
302 List
<ProjectComponent
> components
= new ArrayList
<ProjectComponent
>(Arrays
.asList(getComponents(ProjectComponent
.class)));
303 Collections
.reverse(components
);
304 for (ProjectComponent component
: components
) {
306 component
.projectClosed();
308 catch (Throwable e
) {
314 public <T
> T
[] getExtensions(final ExtensionPointName
<T
> extensionPointName
) {
315 return Extensions
.getArea(this).getExtensionPoint(extensionPointName
).getExtensions();
318 public String
getDefaultName() {
319 if (isDefault()) return TEMPLATE_PROJECT_NAME
;
321 return getStateStore().getProjectName();
324 private class MyProjectManagerListener
extends ProjectManagerAdapter
{
325 public void projectOpened(Project project
) {
326 LOG
.assertTrue(project
== ProjectImpl
.this);
327 ProjectImpl
.this.projectOpened();
330 public void projectClosed(Project project
) {
331 LOG
.assertTrue(project
== ProjectImpl
.this);
332 ProjectImpl
.this.projectClosed();
336 protected MutablePicoContainer
createPicoContainer() {
337 return Extensions
.getArea(this).getPicoContainer();
340 public boolean isDefault() {
344 public void checkUnknownMacros() {
345 final IProjectStore stateStore
= getStateStore();
347 final TrackingPathMacroSubstitutor
[] substitutors
= stateStore
.getSubstitutors();
348 final Set
<String
> unknownMacros
= new HashSet
<String
>();
349 for (final TrackingPathMacroSubstitutor substitutor
: substitutors
) {
350 unknownMacros
.addAll(substitutor
.getUnknownMacros(null));
353 if (!unknownMacros
.isEmpty()) {
354 if (ProjectMacrosUtil
.checkMacros(this, new HashSet
<String
>(unknownMacros
))) {
355 final PathMacros pathMacros
= PathMacros
.getInstance();
356 final Set
<String
> macros2invalidate
= new HashSet
<String
>(unknownMacros
);
357 for (Iterator it
= macros2invalidate
.iterator(); it
.hasNext();) {
358 final String macro
= (String
)it
.next();
359 final String value
= pathMacros
.getValue(macro
);
360 if (null == value
|| value
.trim().length() == 0) {
365 if (!macros2invalidate
.isEmpty()) {
366 final Set
<String
> components
= new HashSet
<String
>();
367 for (TrackingPathMacroSubstitutor substitutor
: substitutors
) {
368 components
.addAll(substitutor
.getComponents(macros2invalidate
));
371 if (stateStore
.isReloadPossible(components
)) {
372 ApplicationManager
.getApplication().runWriteAction(new Runnable() {
374 stateStore
.reinitComponents(components
, true);
378 for (final TrackingPathMacroSubstitutor substitutor
: substitutors
) {
379 substitutor
.invalidateUnknownMacros(macros2invalidate
);
382 final UnknownMacroNotification
[] notifications
=
383 NotificationsManager
.getNotificationsManager().getNotificationsOfType(UnknownMacroNotification
.class, this);
384 for (final UnknownMacroNotification notification
: notifications
) {
385 if (macros2invalidate
.containsAll(notification
.getMacros())) notification
.expire();
389 if (Messages
.showYesNoDialog(this, "Component could not be reloaded. Reload project?", "Configuration changed",
390 Messages
.getQuestionIcon()) == 0) {
391 ProjectManagerEx
.getInstanceEx().reloadProject(this);
400 public String
toString() {
402 + (isDisposed() ?
"(Disposed) " : "")
403 + (isDefault() ?
"(Default) " : "'" + getLocation()+"'")