2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.ide
;
18 import com
.intellij
.ide
.impl
.ProjectUtil
;
19 import com
.intellij
.openapi
.actionSystem
.AnAction
;
20 import com
.intellij
.openapi
.actionSystem
.AnActionEvent
;
21 import com
.intellij
.openapi
.actionSystem
.PlatformDataKeys
;
22 import com
.intellij
.openapi
.actionSystem
.Separator
;
23 import com
.intellij
.openapi
.application
.ApplicationManager
;
24 import com
.intellij
.openapi
.components
.PersistentStateComponent
;
25 import com
.intellij
.openapi
.project
.Project
;
26 import com
.intellij
.openapi
.project
.ProjectManager
;
27 import com
.intellij
.openapi
.project
.ProjectManagerAdapter
;
28 import com
.intellij
.openapi
.project
.DumbAware
;
29 import com
.intellij
.openapi
.ui
.Messages
;
30 import com
.intellij
.openapi
.util
.Ref
;
31 import com
.intellij
.openapi
.util
.SystemInfo
;
32 import com
.intellij
.util
.ArrayUtil
;
33 import com
.intellij
.util
.messages
.MessageBus
;
34 import org
.jetbrains
.annotations
.NotNull
;
35 import org
.jetbrains
.annotations
.Nullable
;
38 import java
.util
.ArrayList
;
39 import java
.util
.Iterator
;
40 import java
.util
.List
;
45 public abstract class RecentProjectsManagerBase
implements PersistentStateComponent
<RecentProjectsManagerBase
.State
> {
46 public static RecentProjectsManagerBase
getInstance() {
47 return ApplicationManager
.getApplication().getComponent(RecentProjectsManagerBase
.class);
50 public static class State
{
51 public List
<String
> recentPaths
= new ArrayList
<String
>();
52 public String lastPath
;
55 protected State myState
= new State();
57 private static final int MAX_RECENT_PROJECTS
= 15;
59 public RecentProjectsManagerBase(ProjectManager projectManager
, MessageBus messageBus
) {
60 projectManager
.addProjectManagerListener(new MyProjectManagerListener());
61 messageBus
.connect().subscribe(AppLifecycleListener
.TOPIC
, new MyAppLifecycleListener());
64 public State
getState() {
65 validateRecentProjects();
69 public void loadState(final State state
) {
71 if (myState
.lastPath
!= null && !new File(myState
.lastPath
).exists()) {
72 myState
.lastPath
= null;
74 if (myState
.lastPath
!= null) {
75 File lastFile
= new File(myState
.lastPath
);
76 if (lastFile
.isDirectory() && !new File(lastFile
, ProjectUtil
.DIRECTORY_BASED_PROJECT_DIR
).exists()) {
77 myState
.lastPath
= null;
82 private void validateRecentProjects() {
83 for (Iterator i
= myState
.recentPaths
.iterator(); i
.hasNext();) {
84 String s
= (String
)i
.next();
89 final File file
= new File(s
);
90 if (file
.isDirectory()) {
91 if (!new File(file
, ProjectUtil
.DIRECTORY_BASED_PROJECT_DIR
).exists()) {
94 } else if (!file
.exists()) {
99 while (myState
.recentPaths
.size() > MAX_RECENT_PROJECTS
) {
100 myState
.recentPaths
.remove(myState
.recentPaths
.size() - 1);
104 private void removePath(final String path
) {
105 if (path
== null) return;
106 if (SystemInfo
.isFileSystemCaseSensitive
) {
107 myState
.recentPaths
.remove(path
);
110 Iterator
<String
> i
= myState
.recentPaths
.iterator();
111 while (i
.hasNext()) {
113 if (path
.equalsIgnoreCase(p
)) {
120 public String
getLastProjectPath() {
121 return myState
.lastPath
;
124 public void updateLastProjectPath() {
125 Project
[] openProjects
= ProjectManager
.getInstance().getOpenProjects();
126 if (openProjects
.length
== 0) {
127 myState
.lastPath
= null;
129 myState
.lastPath
= getProjectPath(openProjects
[openProjects
.length
- 1]);
134 * @param addClearListItem - used for detecting whether the "Clear List" action should be added
135 * to the end of the returned list of actions
138 public AnAction
[] getRecentProjectsActions(boolean addClearListItem
) {
139 validateRecentProjects();
141 Project
[] openProjects
= ProjectManager
.getInstance().getOpenProjects();
143 ArrayList
<AnAction
> actions
= new ArrayList
<AnAction
>();
144 outer
: for (String recentPath
: myState
.recentPaths
) {
146 for (Project openProject
: openProjects
) {
147 final String path
= getProjectPath(openProject
);
148 if (path
== null || recentPath
.equals(path
)) {
153 actions
.add(new ReopenProjectAction(recentPath
));
157 if (actions
.size() == 0) {
158 return new AnAction
[0];
161 ArrayList
<AnAction
> list
= new ArrayList
<AnAction
>();
162 for (AnAction action
: actions
) {
165 if (addClearListItem
) {
166 AnAction clearListAction
= new AnAction(IdeBundle
.message("action.clear.list")) {
167 public void actionPerformed(AnActionEvent e
) {
168 final int rc
= Messages
.showOkCancelDialog(e
.getData(PlatformDataKeys
.PROJECT
),
169 "Would you like to clear the list of recent projects?",
170 "Clear Recent Projects List",
171 Messages
.getQuestionIcon());
174 myState
.recentPaths
.clear();
178 list
.add(Separator
.getInstance());
179 list
.add(clearListAction
);
182 return list
.toArray(new AnAction
[list
.size()]);
185 public String
[] getRecentProjectPaths() {
186 validateRecentProjects();
187 return ArrayUtil
.toStringArray(myState
.recentPaths
);
191 protected abstract String
getProjectPath(Project project
);
193 protected abstract void doOpenProject(String projectPath
, Project projectToClose
);
195 private class MyProjectManagerListener
extends ProjectManagerAdapter
{
196 public void projectOpened(final Project project
) {
197 String path
= getProjectPath(project
);
198 myState
.lastPath
= path
;
200 myState
.recentPaths
.add(0, path
);
203 public void projectClosed(final Project project
) {
204 Project
[] openProjects
= ProjectManager
.getInstance().getOpenProjects();
205 if (openProjects
.length
> 0) {
206 String path
= getProjectPath(openProjects
[openProjects
.length
- 1]);
208 myState
.lastPath
= path
;
210 myState
.recentPaths
.add(0, path
);
216 private class ReopenProjectAction
extends AnAction
implements DumbAware
{
217 private final String myProjectPath
;
219 public ReopenProjectAction(String projectPath
) {
220 myProjectPath
= projectPath
;
221 getTemplatePresentation().setText(projectPath
, false);
224 public void actionPerformed(AnActionEvent e
) {
225 doOpenProject(myProjectPath
, PlatformDataKeys
.PROJECT
.getData(e
.getDataContext()));
229 private class MyAppLifecycleListener
extends AppLifecycleListener
.Adapter
{
230 public void appFrameCreated(final String
[] commandLineArgs
, @NotNull final Ref
<Boolean
> willOpenProject
) {
231 if (GeneralSettings
.getInstance().isReopenLastProject() && getLastProjectPath() != null) {
232 willOpenProject
.set(Boolean
.TRUE
);
236 public void appStarting(final Project projectFromCommandLine
) {
237 if (projectFromCommandLine
!= null) return;
238 GeneralSettings generalSettings
= GeneralSettings
.getInstance();
239 if (generalSettings
.isReopenLastProject()) {
240 String lastProjectPath
= getLastProjectPath();
241 if (lastProjectPath
!= null) {
242 doOpenProject(lastProjectPath
, null);
247 public void projectFrameClosed() {
248 updateLastProjectPath();
251 public void projectOpenFailed() {
252 updateLastProjectPath();