sticky documentation popup [take 1]
[fedora-idea.git] / platform / platform-impl / src / com / intellij / ide / RecentProjectsManagerBase.java
blobe26c87c2a15ea01fcc21769541a26055831ae49f
1 /*
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;
37 import java.io.File;
38 import java.util.ArrayList;
39 import java.util.Iterator;
40 import java.util.List;
42 /**
43 * @author yole
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();
66 return myState;
69 public void loadState(final State state) {
70 myState = 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();
86 if (s == null) {
87 i.remove();
88 } else {
89 final File file = new File(s);
90 if (file.isDirectory()) {
91 if (!new File(file, ProjectUtil.DIRECTORY_BASED_PROJECT_DIR).exists()) {
92 i.remove();
94 } else if (!file.exists()) {
95 i.remove();
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);
109 else {
110 Iterator<String> i = myState.recentPaths.iterator();
111 while (i.hasNext()) {
112 String p = i.next();
113 if (path.equalsIgnoreCase(p)) {
114 i.remove();
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;
128 } else {
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
136 * @return
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)) {
149 continue outer;
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) {
163 list.add(action);
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());
173 if (rc == 0) {
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);
190 @Nullable
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;
199 removePath(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]);
207 if (path != null) {
208 myState.lastPath = path;
209 removePath(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();