Skip to content

Commit 23d353b

Browse files
author
mgricken
committed
Implemented feature request 3081586:
Store Preferences within Projects There now is an "Advanced" button on the "Project Properties" dialog that takes the user to a secondary window. In that window, the user can list (by name, using predictive input) those preferences that should be saved in the project file. By default, "Indent Level" and "Language Level" will be saved. Note that for simplicity, the actual values are still configured in the "Preferences" window (Edit menu). This list only names the preferences whose values should be stored in the project file when the project is saved, and restored when the project is loaded again. git-svn-id: file:///tmp/test-svn/trunk@5408 fe72c1cf-3628-48e9-8b72-1c46755d3cff
1 parent 9b3324f commit 23d353b

14 files changed

+1537
-555
lines changed

drjava/src/edu/rice/cs/drjava/model/AbstractGlobalModel.java

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import java.util.List;
6969
import java.util.Vector;
7070
import java.util.WeakHashMap;
71+
import java.util.Map;
7172

7273
import javax.swing.*;
7374
import javax.swing.event.DocumentListener;
@@ -83,6 +84,8 @@
8384

8485
import edu.rice.cs.drjava.DrJava;
8586
import edu.rice.cs.drjava.DrJavaRoot;
87+
import edu.rice.cs.drjava.config.Option;
88+
import edu.rice.cs.drjava.config.OptionParser;
8689
import edu.rice.cs.drjava.config.OptionConstants;
8790
import edu.rice.cs.drjava.config.OptionEvent;
8891
import edu.rice.cs.drjava.config.OptionListener;
@@ -391,6 +394,7 @@ public void setFileGroupingState(FileGroupingState state) {
391394
_notifier.projectRunnableChanged();
392395
_notifier.projectBuildDirChanged();
393396
_notifier.projectWorkDirChanged();
397+
394398
// _notifier.projectModified(); // not currently used
395399
}
396400

@@ -406,10 +410,11 @@ public void setFileGroupingState(FileGroupingState state) {
406410

407411
protected FileGroupingState
408412
makeProjectFileGroupingState(File pr, String main, File bd, File wd, File project, File[] srcFiles, File[] auxFiles,
409-
File[] excludedFiles, Iterable<AbsRelFile> cp, File cjf, int cjflags, boolean refresh, String manifest) {
413+
File[] excludedFiles, Iterable<AbsRelFile> cp, File cjf, int cjflags, boolean refresh,
414+
String manifest, Map<OptionParser,String> storedPreferences) {
410415

411416
return new ProjectFileGroupingState(pr, main, bd, wd, project, srcFiles, auxFiles, excludedFiles, cp, cjf, cjflags,
412-
refresh, manifest);
417+
refresh, manifest, storedPreferences);
413418
}
414419

415420
/** @return true if the class path state has been changed. */
@@ -530,6 +535,11 @@ public void setProjectRoot(File f) {
530535
/** @return the build directory for the project (assuming one exists). */
531536
public File getBuildDirectory() { return _state.getBuildDirectory(); }
532537

538+
/** @return the stored preferences. */
539+
public Map<OptionParser,String> getPreferencesStoredInProject() { return _state.getPreferencesStoredInProject(); }
540+
541+
public void setPreferencesStoredInProject(Map<OptionParser,String> sp) { _state.setPreferencesStoredInProject(sp); }
542+
533543
/** Sets the class with the project's main method. Degenerate version overridden in DefaultGlobalModel. */
534544
public void setBuildDirectory(File f) {
535545
_state.setBuildDirectory(f);
@@ -598,6 +608,7 @@ class ProjectFileGroupingState implements FileGroupingState {
598608
volatile File _createJarFile;
599609
volatile int _createJarFlags;
600610
volatile boolean _autoRefreshStatus;
611+
final Map<OptionParser,String> _storedPreferences = new HashMap<OptionParser,String>();
601612

602613
volatile String _manifest = null;
603614

@@ -606,12 +617,17 @@ class ProjectFileGroupingState implements FileGroupingState {
606617
/** Degenerate constructor for a new project; only the file project name is known. */
607618
ProjectFileGroupingState(File project) {
608619
this(project.getParentFile(), null, null, null, project, new File[0], new File[0], new File[0],
609-
IterUtil.<AbsRelFile>empty(), null, 0, false, null);
620+
IterUtil.<AbsRelFile>empty(), null, 0, false, null, new HashMap<OptionParser,String>());
621+
HashMap<OptionParser,String> defaultStoredPreferences = new HashMap<OptionParser,String>();
622+
// by default, put INDENT_LEVEL AND LANGUAGE_LEVEL into the project file
623+
defaultStoredPreferences.put(INDENT_LEVEL, DrJava.getConfig().getOptionMap().getString(INDENT_LEVEL));
624+
defaultStoredPreferences.put(LANGUAGE_LEVEL, DrJava.getConfig().getOptionMap().getString(LANGUAGE_LEVEL));
625+
setPreferencesStoredInProject(defaultStoredPreferences);
610626
}
611627

612628
ProjectFileGroupingState(File pr, String main, File bd, File wd, File project, File[] srcFiles, File[] auxFiles,
613629
File[] excludedFiles, Iterable<AbsRelFile> cp, File cjf, int cjflags, boolean refreshStatus,
614-
String customManifest) {
630+
String customManifest, Map<OptionParser,String> storedPreferences) {
615631
_projRoot = pr;
616632
_mainClass = main;
617633
_buildDir = bd;
@@ -633,6 +649,7 @@ class ProjectFileGroupingState implements FileGroupingState {
633649
_createJarFlags = cjflags;
634650
_autoRefreshStatus = refreshStatus;
635651
_manifest = customManifest;
652+
setPreferencesStoredInProject(storedPreferences);
636653
}
637654

638655
public boolean isProjectActive() { return true; }
@@ -820,6 +837,21 @@ public boolean isExcludedFile(File f) {
820837
public boolean getAutoRefreshStatus() { return _autoRefreshStatus; }
821838
public void setAutoRefreshStatus(boolean status) { _autoRefreshStatus = status; }
822839

840+
/** @return the stored preferences. */
841+
public Map<OptionParser,String> getPreferencesStoredInProject() {
842+
return new HashMap<OptionParser,String>(_storedPreferences);
843+
}
844+
845+
public void setPreferencesStoredInProject(Map<OptionParser,String> sp) {
846+
// remove previous listeners
847+
removePreviousListeners();
848+
849+
_storedPreferences.clear();
850+
_storedPreferences.putAll(sp);
851+
852+
// add new listeners
853+
addNewListeners(sp);
854+
}
823855

824856
// This only starts the process. It is all done asynchronously.
825857
public void cleanBuildDirectory() {
@@ -923,6 +955,37 @@ public void setExtraClassPath(Iterable<AbsRelFile> cp) {
923955
public void setCustomManifest(String manifest) { _manifest = manifest; }
924956
}
925957

958+
@SuppressWarnings("unchecked")
959+
protected void removePreviousListeners() {
960+
for(Map.Entry<OptionParser, OptionListener<?>> e: LISTENERS_TO_REMOVE.entrySet()) {
961+
// all keys should be full Option instances, not just OptionParser instances
962+
if (e.getKey() instanceof Option) {
963+
DrJava.getConfig().removeOptionListener((Option)e.getKey(), e.getValue());
964+
}
965+
}
966+
LISTENERS_TO_REMOVE.clear();
967+
}
968+
969+
@SuppressWarnings("unchecked")
970+
protected void addNewListeners(Map<OptionParser,String> newValues) {
971+
for(OptionParser key: newValues.keySet()) {
972+
// all keys should be full Option instances, not just OptionParser instances
973+
if (key instanceof Option) {
974+
DrJava.getConfig().addOptionListener((Option)key, STORED_PREFERENCES_LISTENER);
975+
LISTENERS_TO_REMOVE.put(key, STORED_PREFERENCES_LISTENER);
976+
}
977+
}
978+
}
979+
980+
protected static final HashMap<OptionParser, OptionListener<? extends Object>> LISTENERS_TO_REMOVE =
981+
new HashMap<OptionParser, OptionListener<? extends Object>>();
982+
983+
public final OptionListener<? extends Object> STORED_PREFERENCES_LISTENER = new OptionListener<Object>() {
984+
public void optionChanged(OptionEvent<Object> oce) {
985+
setProjectChanged(true);
986+
}
987+
};
988+
926989
protected FileGroupingState makeFlatFileGroupingState() { return new FlatFileGroupingState(); }
927990

928991
class FlatFileGroupingState implements FileGroupingState {
@@ -1007,7 +1070,9 @@ public void removeExcludedFile(File f) { }
10071070
public void setExcludedFiles(File[] fs) { }
10081071
public boolean getAutoRefreshStatus() {return false;}
10091072
public void setAutoRefreshStatus(boolean b) { }
1010-
1073+
public void setPreferencesStoredInProject(Map<OptionParser,String> sp) { /* do nothing */ }
1074+
public Map<OptionParser,String> getPreferencesStoredInProject() { return new HashMap<OptionParser,String>(); }
1075+
10111076
public void cleanBuildDirectory() { }
10121077

10131078
public List<File> getClassFiles() { return new LinkedList<File>(); }
@@ -1592,6 +1657,7 @@ else if ( doc.isAuxiliaryFile()) {
15921657
* @param file where to save the project
15931658
* @param info
15941659
*/
1660+
@SuppressWarnings("unchecked")
15951661
public ProjectProfile _makeProjectProfile(File file, HashMap<OpenDefinitionsDocument, DocumentInfoGetter> info)
15961662
throws IOException {
15971663
ProjectProfile builder = new ProjectProfile(file);
@@ -1663,6 +1729,14 @@ else if (doc.isAuxiliaryFile()) {
16631729
//add custom manifest
16641730
builder.setCustomManifest(_state.getCustomManifest());
16651731

1732+
// update preference values here
1733+
Map<OptionParser,String> sp = _state.getPreferencesStoredInProject();
1734+
for(OptionParser key: sp.keySet()) {
1735+
sp.put(key, DrJava.getConfig().getOptionMap().getString(key));
1736+
}
1737+
builder.setPreferencesStoredInProject(sp);
1738+
_state.setPreferencesStoredInProject(sp);
1739+
16661740
return builder;
16671741
}
16681742

@@ -1693,7 +1767,9 @@ public void saveProject(File file, HashMap<OpenDefinitionsDocument, DocumentInfo
16931767
builder.getSourceFiles(), builder.getAuxiliaryFiles(),
16941768
builder.getExcludedFiles(),
16951769
builder.getClassPaths(), builder.getCreateJarFile(),
1696-
builder.getCreateJarFlags(), builder.getAutoRefreshStatus(), builder.getCustomManifest()));
1770+
builder.getCreateJarFlags(), builder.getAutoRefreshStatus(),
1771+
builder.getCustomManifest(),
1772+
builder.getPreferencesStoredInProject()));
16971773
}
16981774

16991775
/** Writes the project profile in the old project format. Assumes DrJava is in project mode.
@@ -1715,7 +1791,9 @@ public void exportOldProject(File file, HashMap<OpenDefinitionsDocument,Document
17151791
builder.getSourceFiles(), builder.getAuxiliaryFiles(),
17161792
builder.getExcludedFiles(),
17171793
builder.getClassPaths(), builder.getCreateJarFile(),
1718-
builder.getCreateJarFlags(), builder.getAutoRefreshStatus(), builder.getCustomManifest()));
1794+
builder.getCreateJarFlags(), builder.getAutoRefreshStatus(),
1795+
builder.getCustomManifest(),
1796+
builder.getPreferencesStoredInProject()));
17191797
}
17201798

17211799
public void reloadProject(File file, HashMap<OpenDefinitionsDocument, DocumentInfoGetter> info) throws IOException {
@@ -1760,6 +1838,7 @@ private void _loadProject(final ProjectFileIR ir) throws IOException {
17601838
int createJarFlags = ir.getCreateJarFlags();
17611839
final boolean autoRefresh = ir.getAutoRefreshStatus();
17621840
final String manifest = ir.getCustomManifest();
1841+
final Map<OptionParser,String> storedPreferences = ir.getPreferencesStoredInProject();
17631842

17641843
// clear browser, breakpoint, and bookmark histories
17651844

@@ -1808,7 +1887,7 @@ public boolean accept(OpenDefinitionsDocument d) {
18081887

18091888
setFileGroupingState(makeProjectFileGroupingState(projectRoot, mainClass, buildDir, workDir, projectFile, srcFiles,
18101889
auxFiles, excludedFiles, projectClassPaths, createJarFile,
1811-
createJarFlags, autoRefresh, manifest));
1890+
createJarFlags, autoRefresh, manifest, storedPreferences));
18121891

18131892
resetInteractions(getWorkingDirectory()); // Reset interactions pane in new working directory
18141893

@@ -1926,6 +2005,9 @@ public void closeProject(boolean suppressReset) {
19262005
makeListNavigator(getDocumentNavigator()));
19272006
setFileGroupingState(makeFlatFileGroupingState());
19282007

2008+
// remove previous listeners
2009+
removePreviousListeners();
2010+
19292011
if (! suppressReset) resetInteractions(getWorkingDirectory());
19302012
_notifier.projectClosed();
19312013
setActiveDocument(getDocumentNavigator().getDocuments().get(0));

drjava/src/edu/rice/cs/drjava/model/DummyGlobalModel.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
import java.io.File;
4242
import java.io.IOException;
43+
import java.util.Map;
4344
import java.util.HashMap;
4445
import java.util.List;
4546

@@ -64,6 +65,7 @@
6465
import edu.rice.cs.drjava.model.junit.JUnitModel;
6566
import edu.rice.cs.drjava.project.DocumentInfoGetter;
6667
import edu.rice.cs.drjava.project.MalformedProjectFileException;
68+
import edu.rice.cs.drjava.config.OptionParser;
6769

6870
/** Concrete implementation of GlobalModel that always throws UnsupportedOperationExceptions.
6971
* @version $Id$
@@ -191,6 +193,12 @@ public void setAutoRefreshStatus(boolean status) {
191193
public boolean getAutoRefreshStatus() {
192194
throw new UnsupportedOperationException("Tried to call getAutoRefreshStatus on a Dummy"); }
193195

196+
public Map<OptionParser,String> getPreferencesStoredInProject() {
197+
throw new UnsupportedOperationException("Tried to call getPreferencesStoredInProject on a Dummy"); }
198+
199+
public void setPreferencesStoredInProject(Map<OptionParser,String> sp) {
200+
throw new UnsupportedOperationException("Tried to call setPreferencesStoredInProject on a Dummy"); }
201+
194202
public void saveAllFiles(FileSaveSelector com) throws IOException {
195203
throw new UnsupportedOperationException("Tried to call saveAllFiles on a Dummy");
196204
}

drjava/src/edu/rice/cs/drjava/model/FileGroupingState.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@
3838

3939
import java.io.File;
4040
import java.util.List;
41+
import java.util.Map;
4142
import edu.rice.cs.util.AbsRelFile;
43+
import edu.rice.cs.drjava.config.OptionParser;
4244

4345
/** This state pattern is used by the global model to store any information pertaining to the currently open project.
4446
* The state pattern is used because most project information is not needed in list view. (Elspeth Rocks)
@@ -170,7 +172,12 @@ public interface FileGroupingState {
170172
public boolean getAutoRefreshStatus();
171173

172174
public void setAutoRefreshStatus(boolean b);
173-
175+
176+
/** @return the stored preferences. */
177+
public Map<OptionParser,String> getPreferencesStoredInProject();
178+
179+
public void setPreferencesStoredInProject(Map<OptionParser,String> sp);
180+
174181
/** Sets the custom manifest on the project */
175182
public void setCustomManifest(String manifest);
176183

drjava/src/edu/rice/cs/drjava/model/GlobalModel.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import java.io.IOException;
4242
import java.util.HashMap;
4343
import java.util.List;
44+
import java.util.Map;
4445

4546
import edu.rice.cs.util.AbsRelFile;
4647
import edu.rice.cs.drjava.model.compiler.CompilerModel;
@@ -61,6 +62,7 @@
6162
import edu.rice.cs.util.swing.DocumentIterator;
6263
import edu.rice.cs.util.text.AbstractDocumentInterface;
6364
import edu.rice.cs.util.text.ConsoleDocument;
65+
import edu.rice.cs.drjava.config.OptionParser;
6466

6567
/** Handles the bulk of DrJava's program logic. The UI components interface with the GlobalModel through its
6668
* public methods, and GlobalModel responds via the GlobalModelListener interface. This removes the dependency
@@ -461,6 +463,12 @@ public InteractionsScriptModel loadHistoryAsScript(FileOpenSelector selector)
461463
/** Sets autorefresh status of the project */
462464
public void setAutoRefreshStatus(boolean b);
463465

466+
/** @return the stored preferences. */
467+
public Map<OptionParser,String> getPreferencesStoredInProject();
468+
469+
/** Set the preferences stored in the project. */
470+
public void setPreferencesStoredInProject(Map<OptionParser,String> sp);
471+
464472
/** @return the working directory for the Master JVM. */
465473
public File getMasterWorkingDirectory();
466474

drjava/src/edu/rice/cs/drjava/project/ProjectFileIR.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@
3838

3939
import java.io.*;
4040
import java.util.List;
41+
import java.util.Map;
4142

43+
import edu.rice.cs.drjava.config.OptionParser;
4244
import edu.rice.cs.drjava.model.FileRegion;
4345
import edu.rice.cs.drjava.model.debug.DebugBreakpointData;
4446
import edu.rice.cs.drjava.model.debug.DebugWatchData;
@@ -102,6 +104,9 @@ public interface ProjectFileIR {
102104

103105
public boolean getAutoRefreshStatus();
104106

107+
/** @return the stored preferences. */
108+
public Map<OptionParser,String> getPreferencesStoredInProject();
109+
105110
public void setSourceFiles(List<DocFile> sf);
106111
public void setAuxiliaryFiles(List<DocFile> aux);
107112
public void setExcludedFiles(List<DocFile> ef);
@@ -117,6 +122,7 @@ public interface ProjectFileIR {
117122
public void setBreakpoints(List<? extends DebugBreakpointData> bps);
118123
public void setWatches(List<? extends DebugWatchData> ws);
119124
public void setAutoRefreshStatus(boolean b);
125+
public void setPreferencesStoredInProject(Map<OptionParser,String> sp);
120126

121127
/**
122128
* The version of dr java that created this project (as determined from its serialization as a .pjt or .drjava or .xml file)

0 commit comments

Comments
 (0)