001: /*
002: * FindBugs - Find Bugs in Java programs
003: * Copyright (C) 2006, University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307, USA
018: */
019:
020: package edu.umd.cs.findbugs.gui2;
021:
022: import java.awt.Rectangle;
023: import java.io.File;
024: import java.io.IOException;
025: import java.util.ArrayList;
026: import java.util.LinkedList;
027: import java.util.prefs.BackingStoreException;
028: import java.util.prefs.Preferences;
029:
030: import edu.umd.cs.findbugs.SystemProperties;
031:
032: /**
033: * Saves all the stuff that should be saved for each run,
034: * like recent projects, previous comments, the current docking layout
035: * and the sort order
036: *
037: * For project related things, look in ProjectSettings
038: * @author Dan
039: *
040: */
041: /*GUISaveState uses the Preferences API, dont look for a file anywhere,
042: there isn't one, well... there might be, but its all system dependent where it is and how its stored*/
043: public class GUISaveState {
044:
045: private static GUISaveState instance;
046: // private static final String PREVCOMMENTS="Previous Comments";
047: private static final String SORTERTABLELENGTH = "Sorter Length";
048: private static final String PREVCOMMENTSSIZE = "Previous Comments Size";
049: private static final String PREFERENCESDIRECTORY = "Preference Directory";
050: private static final String DOCKINGLAYOUT = "Docking Layout";
051: private static final String FRAME_BOUNDS = "Frame Bounds";
052:
053: private static final int MAXNUMRECENTPROJECTS = 5;
054: private static final int MAXNUMRECENTANALYSES = MAXNUMRECENTPROJECTS;
055: private static final Sortables[] DEFAULT_COLUMN_HEADERS = new Sortables[] {
056: Sortables.CATEGORY, Sortables.BUGCODE, Sortables.TYPE,
057: Sortables.DIVIDER, Sortables.PRIORITY };
058:
059: private static final String[] RECENTPROJECTKEYS = new String[MAXNUMRECENTPROJECTS];//{"Project1","Project2","Project3","Project4","Project5"};//Make MAXNUMRECENTPROJECTS of these
060: private static final String[] RECENTANALYSISKEYS = new String[MAXNUMRECENTPROJECTS];
061: static {
062: for (int x = 0; x < RECENTPROJECTKEYS.length; x++) {
063: RECENTPROJECTKEYS[x] = "Project" + x;
064: RECENTANALYSISKEYS[x] = "Analysis" + x;
065: }
066: }
067: private static final int MAXNUMPREVCOMMENTS = 10;
068: private static final String[] COMMENTKEYS = new String[MAXNUMPREVCOMMENTS];
069: static {
070: for (int x = 0; x < COMMENTKEYS.length; x++) {
071: COMMENTKEYS[x] = "Comment" + x;
072: }
073: }
074: private static final String NUMPROJECTS = "NumberOfProjectsToLoad";
075: private static final String NUMANALYSES = "NumberOfAnalysesToLoad";
076: private static final String STARTERDIRECTORY = "Starter Directory";
077:
078: private static final String SPLIT_MAIN = "MainSplit";
079: private static final String SPLIT_TREE_COMMENTS = "TreeCommentsSplit";
080: private static final String SPLIT_TOP = "TopSplit";
081: private static final String SPLIT_SUMMARY = "SummarySplit";
082:
083: private int splitMain;
084: private int splitTreeComments;
085: private int splitTop;
086: private int splitSummary;
087:
088: private File starterDirectoryForLoadBugs;
089: /**
090: * List of previous comments by the user.
091: */
092: private LinkedList<String> previousComments;
093: private boolean useDefault = false;
094: private SorterTableColumnModel starterTable;
095: private ArrayList<File> recentFiles;
096: //private ArrayList<File> recentAnalyses;
097: private byte[] dockingLayout;
098: private Rectangle frameBounds;
099:
100: private static final String TAB_SIZE = "TabSize";
101: private int tabSize; //Tab size in the source code display.
102: private static final String FONT_SIZE = "FontSize";
103: private float fontSize; //Font size of entire GUI.
104:
105: public int getTabSize() {
106: return tabSize;
107: }
108:
109: public void setTabSize(int tabSize) {
110: this .tabSize = tabSize;
111: }
112:
113: public byte[] getDockingLayout() {
114: return dockingLayout;
115: }
116:
117: public void setDockingLayout(byte[] dockingLayout) {
118: this .dockingLayout = dockingLayout;
119: }
120:
121: private static String[] generateSorterKeys(int numSorters) {
122: String[] result = new String[numSorters];
123: for (int x = 0; x < result.length; x++) {
124: result[x] = "Sorter" + x;
125: }
126: return result;
127: }
128:
129: SorterTableColumnModel getStarterTable() {
130: if (useDefault || (starterTable == null))
131: starterTable = new SorterTableColumnModel(
132: GUISaveState.DEFAULT_COLUMN_HEADERS);
133:
134: return starterTable;
135: }
136:
137: private GUISaveState() {
138: recentFiles = new ArrayList<File>();
139: // projectsToLocations=new HashMap<String,String>();
140: previousComments = new LinkedList<String>();
141: }
142:
143: public static synchronized GUISaveState getInstance() {
144: if (instance == null)
145: instance = new GUISaveState();
146: return instance;
147: }
148:
149: /**
150: * This should be the method called to add a reused file for the recent menu.
151: */
152: public void fileReused(File f) {
153: if (!recentFiles.contains(f)) {
154: throw new IllegalStateException(
155: "Selected a recent project that doesn't exist?");
156: } else {
157: recentFiles.remove(f);
158: recentFiles.add(f);
159: }
160: }
161:
162: /**
163: * This should be the method used to add a file for the recent menu.
164: * @param f
165: */
166: public void addRecentFile(File f) {
167: recentFiles.add(f);
168: }
169:
170: /**
171: * Returns the list of recent files.
172: * @return
173: */
174: public ArrayList<File> getRecentFiles() {
175: return recentFiles;
176: }
177:
178: /**
179: * Call to remove a file from the list.
180: * @param f
181: */
182: public void fileNotFound(File f) {
183: if (!recentFiles.contains(f)) {
184: throw new IllegalStateException(
185: "Well no wonder it wasn't found, its not in the list.");
186: } else
187: recentFiles.remove(f);
188:
189: }
190:
191: /**
192: * The file to start the loading of Bugs from.
193: * @return Returns the starterDirectoryForLoadBugs.
194: */
195: public File getStarterDirectoryForLoadBugs() {
196: return starterDirectoryForLoadBugs;
197: }
198:
199: /**
200: * @param f The starterDirectoryForLoadBugs to set.
201: */
202: public void setStarterDirectoryForLoadBugs(File f) {
203: this .starterDirectoryForLoadBugs = f;
204: }
205:
206: public static void loadInstance() {
207: GUISaveState newInstance = new GUISaveState();
208: newInstance.recentFiles = new ArrayList<File>();
209: Preferences p = Preferences
210: .userNodeForPackage(GUISaveState.class);
211:
212: newInstance.tabSize = p.getInt(TAB_SIZE, 4);
213:
214: newInstance.fontSize = p.getFloat(FONT_SIZE, 12.0f);
215:
216: newInstance.starterDirectoryForLoadBugs = new File(p.get(
217: GUISaveState.STARTERDIRECTORY, SystemProperties
218: .getProperty("user.dir")));
219:
220: int prevCommentsSize = p.getInt(GUISaveState.PREVCOMMENTSSIZE,
221: 0);
222:
223: for (int x = 0; x < prevCommentsSize; x++) {
224: String comment = p.get(GUISaveState.COMMENTKEYS[x], "");
225: newInstance.previousComments.add(comment);
226: }
227:
228: int size = Math.min(MAXNUMRECENTPROJECTS, p.getInt(
229: GUISaveState.NUMPROJECTS, 0));
230: for (int x = 0; x < size; x++) {
231: newInstance.recentFiles.add(new File(p.get(
232: GUISaveState.RECENTPROJECTKEYS[x], "")));
233: }
234:
235: int sorterSize = p.getInt(GUISaveState.SORTERTABLELENGTH, -1);
236: if (sorterSize != -1) {
237: Sortables[] sortColumns = new Sortables[sorterSize];
238: String[] sortKeys = GUISaveState
239: .generateSorterKeys(sorterSize);
240: for (int x = 0; x < sorterSize; x++) {
241: sortColumns[x] = Sortables.getSortableByPrettyName(p
242: .get(sortKeys[x], "*none*"));
243: if (sortColumns[x] == null) {
244: if (MainFrame.DEBUG)
245: System.err
246: .println("Sort order was corrupted, using default sort order");
247: newInstance.useDefault = true;
248: }
249: }
250: if (!newInstance.useDefault)
251: newInstance.starterTable = new SorterTableColumnModel(
252: sortColumns);
253: } else
254: newInstance.useDefault = true;
255:
256: newInstance.dockingLayout = p.getByteArray(DOCKINGLAYOUT,
257: new byte[0]);
258:
259: String boundsString = p.get(FRAME_BOUNDS, null);
260: Rectangle r = new Rectangle(0, 0, 800, 650);
261: if (boundsString != null) {
262: String[] a = boundsString.split(",", 4);
263: if (a.length > 0)
264: try {
265: r.x = Math.max(0, Integer.parseInt(a[0]));
266: } catch (NumberFormatException nfe) {
267: assert true;
268: }
269: if (a.length > 1)
270: try {
271: r.y = Math.max(0, Integer.parseInt(a[1]));
272: } catch (NumberFormatException nfe) {
273: assert true;
274: }
275: if (a.length > 2)
276: try {
277: r.width = Math.max(40, Integer.parseInt(a[2]));
278: } catch (NumberFormatException nfe) {
279: assert true;
280: }
281: if (a.length > 3)
282: try {
283: r.height = Math.max(40, Integer.parseInt(a[3]));
284: } catch (NumberFormatException nfe) {
285: assert true;
286: }
287: }
288: newInstance.frameBounds = r;
289:
290: newInstance.splitMain = p.getInt(SPLIT_MAIN, 400);
291: newInstance.splitSummary = p.getInt(SPLIT_SUMMARY, 85);
292: newInstance.splitTop = p.getInt(SPLIT_TOP, -1);
293: newInstance.splitTreeComments = p.getInt(SPLIT_TREE_COMMENTS,
294: 250);
295:
296: instance = newInstance;
297: }
298:
299: public void save() {
300: Preferences p = Preferences
301: .userNodeForPackage(GUISaveState.class);
302:
303: p.putInt(TAB_SIZE, tabSize);
304:
305: p.putFloat(FONT_SIZE, fontSize);
306:
307: try {
308: p.put(STARTERDIRECTORY, starterDirectoryForLoadBugs
309: .getCanonicalPath());
310: } catch (IOException e) {
311: Debug.println(e);
312: }
313: int sorterLength = MainFrame.getInstance().getSorter()
314: .getColumnCount();
315: ArrayList<Sortables> sortables = MainFrame.getInstance()
316: .getSorter().getOrder();
317: p.putInt(GUISaveState.SORTERTABLELENGTH, sorterLength);
318:
319: String[] sorterKeys = GUISaveState
320: .generateSorterKeys(sorterLength);
321: for (int x = 0; x < sorterKeys.length; x++) {
322: p.put(sorterKeys[x], sortables.get(x).prettyName);
323: }
324:
325: p
326: .putInt(GUISaveState.PREVCOMMENTSSIZE, previousComments
327: .size());
328:
329: for (int x = 0; x < previousComments.size(); x++) {
330: String comment = previousComments.get(x);
331: p.put(GUISaveState.COMMENTKEYS[x], comment);
332: }
333:
334: int size = recentFiles.size();
335: while (recentFiles.size() > MAXNUMRECENTPROJECTS) {
336: recentFiles.remove(0);
337: }
338:
339: p.putInt(GUISaveState.NUMPROJECTS, Math.min(size,
340: MAXNUMRECENTPROJECTS));
341: for (int x = 0; x < Math.min(size, MAXNUMRECENTPROJECTS); x++) {
342: File file = recentFiles.get(x);
343: p.put(GUISaveState.RECENTPROJECTKEYS[x], file
344: .getAbsolutePath());
345: }
346:
347: p.putByteArray(DOCKINGLAYOUT, dockingLayout);
348:
349: p.put(FRAME_BOUNDS, frameBounds.x + "," + frameBounds.y + ","
350: + frameBounds.width + "," + frameBounds.height);
351:
352: p.putInt(SPLIT_MAIN, splitMain);
353: p.putInt(SPLIT_SUMMARY, splitSummary);
354: p.putInt(SPLIT_TOP, splitTop);
355: p.putInt(SPLIT_TREE_COMMENTS, splitTreeComments);
356: }
357:
358: static void clear() {
359: Preferences p = Preferences
360: .userNodeForPackage(GUISaveState.class);
361: try {
362: p.clear();
363: } catch (BackingStoreException e) {
364: Debug.println(e);
365: }
366: instance = new GUISaveState();
367: }
368:
369: /**
370: * @return Returns the previousComments.
371: */
372: public LinkedList<String> getPreviousComments() {
373: return previousComments;
374: }
375:
376: /**
377: * @param previousComments The previousComments to set.
378: */
379: public void setPreviousComments(LinkedList<String> previousComments) {
380: this .previousComments = previousComments;
381: }
382:
383: /**
384: * @return Returns the frame bounds Rectangle.
385: */
386: public Rectangle getFrameBounds() {
387: return frameBounds;
388: }
389:
390: /**
391: * @param frameBounds The frame bourds Rectangle to set.
392: */
393: public void setFrameBounds(Rectangle frameBounds) {
394: this .frameBounds = frameBounds;
395: }
396:
397: /**
398: * @return Returns the fontSize.
399: */
400: public float getFontSize() {
401: return fontSize;
402: }
403:
404: /**
405: * @param fontSize The fontSize to set.
406: */
407: public void setFontSize(float fontSize) {
408: this .fontSize = fontSize;
409: }
410:
411: /**
412: * @return Returns the location of the main divider.
413: */
414: public int getSplitMain() {
415: return splitMain;
416: }
417:
418: /**
419: * @param splitMain The location of the main divider to set.
420: */
421: public void setSplitMain(int splitMain) {
422: this .splitMain = splitMain;
423: }
424:
425: /**
426: * @return Returns the location of the summary divider.
427: */
428: public int getSplitSummary() {
429: return splitSummary;
430: }
431:
432: /**
433: * @param splitSummary The location of the summar divider to set.
434: */
435: public void setSplitSummary(int splitSummary) {
436: this .splitSummary = splitSummary;
437: }
438:
439: /**
440: * @return Returns the location of the top divider.
441: */
442: public int getSplitTop() {
443: return splitTop;
444: }
445:
446: /**
447: * @param splitTop The location of the top divider to set.
448: */
449: public void setSplitTop(int splitTop) {
450: this .splitTop = splitTop;
451: }
452:
453: /**
454: * @return Returns the location of the tree-comments divider.
455: */
456: public int getSplitTreeComments() {
457: return splitTreeComments;
458: }
459:
460: /**
461: * @param splitTreeComments The location of the tree-comments divider to set.
462: */
463: public void setSplitTreeComments(int splitTreeComments) {
464: this.splitTreeComments = splitTreeComments;
465: }
466: }
|