Skip to content

Commit 8e023f7

Browse files
committed
1 parent c112815 commit 8e023f7

File tree

4 files changed

+294
-0
lines changed

4 files changed

+294
-0
lines changed

src/main/java/org/scijava/AbstractGateway.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.scijava.event.EventHistory;
4242
import org.scijava.event.EventService;
4343
import org.scijava.io.IOService;
44+
import org.scijava.io.RecentFileService;
4445
import org.scijava.log.LogService;
4546
import org.scijava.menu.MenuService;
4647
import org.scijava.module.ModuleService;
@@ -175,6 +176,11 @@ public PluginService plugin() {
175176
return get(PluginService.class);
176177
}
177178

179+
@Override
180+
public RecentFileService recentFile() {
181+
return get(RecentFileService.class);
182+
}
183+
178184
@Override
179185
public ScriptService script() {
180186
return get(ScriptService.class);

src/main/java/org/scijava/Gateway.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.scijava.event.EventHistory;
4141
import org.scijava.event.EventService;
4242
import org.scijava.io.IOService;
43+
import org.scijava.io.RecentFileService;
4344
import org.scijava.log.LogService;
4445
import org.scijava.menu.MenuService;
4546
import org.scijava.module.ModuleService;
@@ -173,6 +174,8 @@ public interface Gateway extends RichPlugin {
173174

174175
PluginService plugin();
175176

177+
RecentFileService recentFile();
178+
176179
ScriptService script();
177180

178181
StatusService status();
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2014 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.io;
33+
34+
import java.util.Collections;
35+
import java.util.HashMap;
36+
import java.util.List;
37+
import java.util.Map;
38+
39+
import org.scijava.MenuEntry;
40+
import org.scijava.MenuPath;
41+
import org.scijava.command.CommandInfo;
42+
import org.scijava.command.CommandService;
43+
import org.scijava.event.EventHandler;
44+
import org.scijava.event.EventService;
45+
import org.scijava.io.event.IOEvent;
46+
import org.scijava.menu.MenuConstants;
47+
import org.scijava.module.ModuleInfo;
48+
import org.scijava.module.ModuleService;
49+
import org.scijava.plugin.Parameter;
50+
import org.scijava.plugin.Plugin;
51+
import org.scijava.service.AbstractService;
52+
import org.scijava.service.Service;
53+
import org.scijava.util.FileUtils;
54+
import org.scijava.util.Prefs;
55+
56+
// TODO - DefaultRecentFileService, DefaultWindowService, and DefaultLUTService
57+
// all build menus dynamically (see createInfo()). We may be able to abstract a
58+
// helper class out of these that can be used by them and future services.
59+
60+
/**
61+
* Default service for managing the Recently Used Files menu.
62+
* <p>
63+
* Behavior: There is a limited number of files presented (maxFilesShown),
64+
* regardless of the list length. When a file is opened, its path is added to
65+
* the top of the list. If an image has been saved as a new file, its path is
66+
* added to the top of the list.
67+
* </p>
68+
* <ul>
69+
* <li>add(String path)</li>
70+
* <li>remove(String path)</li>
71+
* </ul>
72+
*
73+
* @author Grant Harris
74+
* @author Curtis Rueden
75+
*/
76+
@Plugin(type = Service.class)
77+
public final class DefaultRecentFileService extends AbstractService implements
78+
RecentFileService
79+
{
80+
81+
// -- Constants --
82+
83+
/** Maximum pathname length shown. */
84+
private static final int MAX_DISPLAY_LENGTH = 40;
85+
86+
private static final String RECENT_MENU_NAME = "Open Recent";
87+
88+
private static final String RECENT_FILES_KEY = "recentfiles";
89+
90+
// -- Fields --
91+
92+
@Parameter
93+
private EventService eventService;
94+
95+
@Parameter
96+
private ModuleService moduleService;
97+
98+
@Parameter
99+
private CommandService commandService;
100+
101+
private List<String> recentFiles;
102+
private Map<String, ModuleInfo> recentModules;
103+
104+
// -- RecentFileService methods --
105+
106+
@Override
107+
public void add(final String path) {
108+
final boolean present = recentModules.containsKey(path);
109+
110+
// add path to recent files list
111+
if (present) recentFiles.remove(path);
112+
recentFiles.add(path);
113+
114+
// persist the updated list
115+
Prefs.putList(recentFiles, RECENT_FILES_KEY);
116+
117+
if (present) {
118+
// path already present; update linked module info
119+
final ModuleInfo info = recentModules.get(path);
120+
// TODO - update module weights
121+
info.update(eventService);
122+
}
123+
else {
124+
// new path; create linked module info
125+
final ModuleInfo info = createInfo(path);
126+
recentModules.put(path, info);
127+
128+
// register the module with the module service
129+
moduleService.addModule(info);
130+
}
131+
}
132+
133+
@Override
134+
public boolean remove(final String path) {
135+
// remove path from recent files list
136+
final boolean success = recentFiles.remove(path);
137+
138+
// persist the updated list
139+
Prefs.putList(recentFiles, RECENT_FILES_KEY);
140+
141+
// remove linked module info
142+
final ModuleInfo info = recentModules.remove(path);
143+
if (info != null) moduleService.removeModule(info);
144+
145+
return success;
146+
}
147+
148+
@Override
149+
public void clear() {
150+
recentFiles.clear();
151+
Prefs.clear(RECENT_FILES_KEY);
152+
153+
// unregister the modules with the module service
154+
moduleService.removeModules(recentModules.values());
155+
156+
recentModules.clear();
157+
}
158+
159+
@Override
160+
public List<String> getRecentFiles() {
161+
return Collections.unmodifiableList(recentFiles);
162+
}
163+
164+
// -- Service methods --
165+
166+
@Override
167+
public void initialize() {
168+
recentFiles = Prefs.getList(RECENT_FILES_KEY);
169+
recentModules = new HashMap<String, ModuleInfo>();
170+
for (final String path : recentFiles) {
171+
recentModules.put(path, createInfo(path));
172+
}
173+
174+
// register the modules with the module service
175+
moduleService.addModules(recentModules.values());
176+
}
177+
178+
// -- Event handlers --
179+
180+
@EventHandler
181+
protected void onEvent(final IOEvent event) {
182+
add(event.getDescriptor());
183+
}
184+
185+
// -- Helper methods --
186+
187+
/** Creates a {@link ModuleInfo} to reopen data at the given path. */
188+
private ModuleInfo createInfo(final String path) {
189+
// CTR FIXME: Avoid circular dependency between ij-core and ij-commands.
190+
final String commandClassName = "imagej.plugins.commands.io.OpenFile";
191+
final CommandInfo info = new CommandInfo(commandClassName);
192+
193+
// hard code path to open as a preset
194+
final HashMap<String, Object> presets = new HashMap<String, Object>();
195+
presets.put("inputFile", path);
196+
info.setPresets(presets);
197+
198+
// set menu path
199+
final MenuPath menuPath = new MenuPath();
200+
menuPath.add(new MenuEntry(MenuConstants.FILE_LABEL));
201+
menuPath.add(new MenuEntry(RECENT_MENU_NAME));
202+
final MenuEntry leaf = new MenuEntry(shortPath(path));
203+
menuPath.add(leaf);
204+
info.setMenuPath(menuPath);
205+
206+
// set menu position
207+
leaf.setWeight(0); // TODO - do this properly
208+
209+
// use the same icon as File > Open
210+
final CommandInfo fileOpen = commandService.getCommand(commandClassName);
211+
if (fileOpen != null) {
212+
final String iconPath = fileOpen.getIconPath();
213+
info.setIconPath(iconPath);
214+
}
215+
216+
return info;
217+
}
218+
219+
/** Shortens the given path to ensure it conforms to a maximum length. */
220+
private String shortPath(final String path) {
221+
// TODO - shorten path name as needed
222+
return FileUtils.limitPath(path, MAX_DISPLAY_LENGTH);
223+
}
224+
225+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* #%L
3+
* SciJava Common shared library for SciJava software.
4+
* %%
5+
* Copyright (C) 2009 - 2014 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.io;
33+
34+
import java.util.List;
35+
36+
import org.scijava.service.SciJavaService;
37+
38+
/**
39+
* Interface for services that manage the Recently Used Files menu.
40+
*
41+
* @author Grant Harris
42+
* @author Curtis Rueden
43+
*/
44+
public interface RecentFileService extends SciJavaService {
45+
46+
int MAX_FILES_SHOWN = 10;
47+
48+
/** Adds or refreshes a path on the list of recent files. */
49+
void add(String path);
50+
51+
/** Removes a path from the list of recent files. */
52+
boolean remove(String path);
53+
54+
/** Clears the list of recent files. */
55+
void clear();
56+
57+
/** Gets the list of recent files. */
58+
List<String> getRecentFiles();
59+
60+
}

0 commit comments

Comments
 (0)