diff --git a/source/options.txt b/source/options.txt
index 86ea267..45c674d 100644
--- a/source/options.txt
+++ b/source/options.txt
@@ -18,6 +18,13 @@
######################### User Preferences ###########################
############################################################################
+# How many recently opened files should be displayed?
+thdl.number.of.recently.opened.files.to.show = 4
+
+# How many characters maximum do you want to show on the File menu for
+# a recently opened file?
+thdl.max.chars.in.recently.opened.file.name = 40
+
# Set this to the full path of the user preferences file, or to the
# empty string if you wish to use the default values, which are
# system-specific.
diff --git a/source/org/thdl/tib/input/Jskad.java b/source/org/thdl/tib/input/Jskad.java
index 047694d..83389ed 100644
--- a/source/org/thdl/tib/input/Jskad.java
+++ b/source/org/thdl/tib/input/Jskad.java
@@ -126,25 +126,10 @@ public class Jskad extends JPanel implements DocumentListener {
/** Do not use this JPanel constructor. */
private Jskad(LayoutManager lm, boolean isDB) { super(lm, isDB); }
- /** Tells ThdlOptions about the recently opened files. */
- // DLC FIXME: this doesn't keep the second-most recently opened item second if you have just three items.
- private static void storeRecentlyOpenedFilePreferences() {
- int N = ThdlOptions.getIntegerOption("thdl.number.of.recently.opened.files.to.show", 4);
- int n = 0;
- // We store 2*N files in the preferences in case some are deleted.
- for (int k = recentlyOpenedFiles.size(); k > 0 && n < 2*N; k--) {
- File f = (File)recentlyOpenedFiles.elementAt(k - 1);
- if (f.isFile()) {
- ThdlOptions.setUserPreference("thdl.recently.opened.file." + n++,
- f.getAbsolutePath());
- }
- }
- }
-
/** Saves user preferences to disk if possible. */
private void savePreferencesAction() {
try {
- storeRecentlyOpenedFilePreferences();
+ RecentlyOpenedFilesDatabase.storeRecentlyOpenedFilePreferences();
if (!ThdlOptions.saveUserPreferences()) {
JOptionPane.showMessageDialog(Jskad.this,
@@ -178,43 +163,14 @@ public class Jskad extends JPanel implements DocumentListener {
/** pane displaying Jskad's single HTML help file */
private static HTMLPane helpPane;
- /** Returns the n
th most recently opened file, given
- that we care about N
recently opened files in
- total. When n
is zero, the most recently opened
- file is returned. This file does exist. Returns null if we
- haven't kept track of enough files to say. */
- private static File getNthRecentlyOpenedFile(int n, int N) {
- for (int i = n; i < N*2; i++) {
- String x = ThdlOptions.getStringOption("thdl.recently.opened.file." + i);
- if (null == x)
- return null;
- File f = new File(x);
- if (f.isFile())
- return f;
- }
- return null;
- }
-
- /** a vector with the most recently opened file at its end. */
- private static Vector recentlyOpenedFiles = new Vector();
/** the File menu */
private JMenu fileMenu = null;
- private static void addMostRecentlyOpenedFile(File fileChosen) {
- // the last element is the most recently opened.
- int index = recentlyOpenedFiles.indexOf(fileChosen);
- if (index > -1) {
- recentlyOpenedFiles.remove(index);
- }
- recentlyOpenedFiles.add(fileChosen);
- }
-
/** Updates state information now that we know that fileChosen is
the most recently opened file. */
private static void noteMostRecentlyOpenedFile(File fileChosen) {
- addMostRecentlyOpenedFile(fileChosen);
- storeRecentlyOpenedFilePreferences();
-
+ RecentlyOpenedFilesDatabase.setMostRecentlyOpenedFile(fileChosen);
+
int i, sz = jskads.size();
for (i = 0; i < sz; i++) {
((Jskad)jskads.elementAt(i)).updateRecentlyOpenedFilesMenuItems();
@@ -225,21 +181,20 @@ public class Jskad extends JPanel implements DocumentListener {
int ic = fileMenu.getItemCount();
while (fileMenu.getItemCount() > 8)
fileMenu.remove(7);
- int N = ThdlOptions.getIntegerOption("thdl.number.of.recently.opened.files.to.show", 4);
+ int N = RecentlyOpenedFilesDatabase.getNumberOfFilesToShow();
// Avoid adding duplicate entries:
- int maximum = recentlyOpenedFiles.size();
- if (N > maximum) N = maximum;
boolean addedSeparator = false;
for (int i = 0; i < N; i++) {
final File recentlyOpenedFile
- = getNthRecentlyOpenedFile(N-i-1, N);
+ = RecentlyOpenedFilesDatabase.getNthRecentlyOpenedFile(N-i-1);
if (null != recentlyOpenedFile) {
if (!addedSeparator) {
fileMenu.insertSeparator(6);
addedSeparator = true;
}
- JMenuItem item = new JMenuItem((N-i) + " " + recentlyOpenedFile.getAbsolutePath());
+ JMenuItem item = new JMenuItem((N-i) + " "
+ + RecentlyOpenedFilesDatabase.getLabel(recentlyOpenedFile));
item.addActionListener(new ThdlActionListener() {
public void theRealActionPerformed(ActionEvent e) {
openFile(recentlyOpenedFile);
@@ -274,7 +229,11 @@ public class Jskad extends JPanel implements DocumentListener {
= ThdlOptions.getStringOption("thdl.Jskad.working.directory",
null);
fileChooser
- = new JFileChooser(whereToStart.equals("") ? null : whereToStart);
+ = new JFileChooser((whereToStart == null)
+ ? null
+ : (whereToStart.equals("")
+ ? null
+ : whereToStart));
rtfFilter = new RTFFilter();
txtFilter = new TXTFilter();
fileChooser.addChoosableFileFilter(rtfFilter);
@@ -339,14 +298,6 @@ public class Jskad extends JPanel implements DocumentListener {
});
fileMenu.add(saveAsItem);
- // Add the N most recently opened files.
- int N = ThdlOptions.getIntegerOption("thdl.number.of.recently.opened.files.to.show", 4);
- int maxCharsToShow
- = ThdlOptions.getIntegerOption("thdl.max.chars.in.recently.opened.file.name", 35);
- for (int i = 0; i < 2*N; i++) {
- addMostRecentlyOpenedFile(getNthRecentlyOpenedFile(i, N));
- }
-
if (parentObject instanceof JFrame) {
JMenuItem exitItem = new JMenuItem("Exit");
exitItem.addActionListener(new ThdlActionListener() {
@@ -941,8 +892,12 @@ public class Jskad extends JPanel implements DocumentListener {
String whereToStart
= ThdlOptions.getStringOption("thdl.Jskad.working.directory",
null);
- fileChooser
- = new JFileChooser(whereToStart.equals("") ? null : whereToStart);
+ fileChooser
+ = new JFileChooser((whereToStart == null)
+ ? null
+ : (whereToStart.equals("")
+ ? null
+ : whereToStart));
fileChooser.addChoosableFileFilter(rtfFilter);
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
diff --git a/source/org/thdl/tib/input/RecentlyOpenedFilesDatabase.java b/source/org/thdl/tib/input/RecentlyOpenedFilesDatabase.java
new file mode 100644
index 0000000..07ae259
--- /dev/null
+++ b/source/org/thdl/tib/input/RecentlyOpenedFilesDatabase.java
@@ -0,0 +1,155 @@
+/*
+The contents of this file are subject to the THDL Open Community License
+Version 1.0 (the "License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License on the THDL web site
+(http://www.thdl.org/).
+
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+License for the specific terms governing rights and limitations under the
+License.
+
+The Initial Developer of this software is the Tibetan and Himalayan Digital
+Library (THDL). Portions created by the THDL are Copyright 2003 THDL.
+All Rights Reserved.
+
+Contributor(s): ______________________________________.
+*/
+
+package org.thdl.tib.input;
+
+import org.thdl.util.ThdlOptions;
+
+import java.util.Vector;
+import java.io.File;
+
+/** A database of the files most recently opened in Jskad. The client
+ must call {@link #storeRecentlyOpenedFilePreferences()} before
+ exiting.
+ @author David Chandler
+*/
+class RecentlyOpenedFilesDatabase {
+
+ /** Tells ThdlOptions about the recently opened files. Call this before program exit. */
+ // DLC FIXME: this doesn't keep the second-most recently opened item second if you have just three items.
+ public static void storeRecentlyOpenedFilePreferences() {
+ int n = 0;
+ // We store 2*N files in the preferences in case some are deleted.
+ for (int k = 0; k < recentlyOpenedFiles.size() && n < 2*N; k++) {
+ File f = (File)recentlyOpenedFiles.elementAt(k);
+ if (f.isFile()) {
+ ThdlOptions.setUserPreference("thdl.recently.opened.file." + n++,
+ f.getAbsolutePath());
+ }
+ }
+ }
+
+ /** the number of recently opened files to display on the File
+ menu */
+ private static int N;
+
+ /** the maximum number of characters to display in a label shown
+ to the user for a recently opened file */
+ private static int maxCharsToShow;
+
+ /** Returns the maximum number of recently opened files that the
+ user wishes to see in the File menu. */
+ public static int getNumberOfFilesToShow() {
+ if (uninitialized) init();
+ return N;
+ }
+
+ /** false iff we are in the process of initializing or have
+ already initialized */
+ private static boolean uninitialized = true;
+
+ /** Reads the user's preferences and fills in {@link
+ #recentlyOpenedFiles} based on them. */
+ private static void init() {
+ if (uninitialized) {
+ uninitialized = false; // must come first!
+
+ maxCharsToShow
+ = ThdlOptions.getIntegerOption("thdl.max.chars.in.recently.opened.file.name", 40);
+ N = ThdlOptions.getIntegerOption("thdl.number.of.recently.opened.files.to.show", 4);
+
+ // Add the N most recently opened files.
+
+ if (maxCharsToShow < 5)
+ maxCharsToShow = 5;
+ for (int i = 2*N - 1; i >= 0; i--) {
+ setMostRecentlyOpenedFile(getNthRecentlyOpenedFileFromPreferences(i));
+ }
+ }
+ }
+
+ /** Returns the n
th most recently opened file, given
+ that we care about N
recently opened files in
+ total. When n
is zero, the most recently opened
+ file is returned. This file does exist. Returns null if we
+ haven't kept track of enough files to say. */
+ public static File getNthRecentlyOpenedFile(int n) {
+ if (uninitialized) init();
+ while (n < recentlyOpenedFiles.size()) {
+ File f = (File)recentlyOpenedFiles.elementAt(n);
+ if (f.isFile())
+ return f;
+ ++n;
+ }
+ return null;
+ }
+
+ /** Returns the nth most recently opened, existing file listed in
+ the user's preferences. Returns null if their preferences do
+ not contain n+1 existing files. */
+ private static File getNthRecentlyOpenedFileFromPreferences(int n) {
+ if (uninitialized) init();
+ for (int i = n; i < N*2; i++) {
+ String x = ThdlOptions.getStringOption("thdl.recently.opened.file." + i);
+ if (null == x)
+ return null;
+ File f = new File(x);
+ if (f.isFile())
+ return f;
+ }
+ return null;
+ }
+
+ /** Notes the fact that fileChosen was the file most recently
+ opened by Jskad. */
+ public static void setMostRecentlyOpenedFile(File fileChosen) {
+ if (null != fileChosen) {
+ if (uninitialized) init();
+ // the first element is the most recently opened.
+ int index = recentlyOpenedFiles.indexOf(fileChosen);
+ if (index > -1) {
+ recentlyOpenedFiles.remove(index);
+ }
+ recentlyOpenedFiles.add(0, fileChosen);
+ }
+ }
+
+ /** a vector with the most recently opened file at its
+ beginning, the least recently opened at its end. */
+ private static Vector recentlyOpenedFiles = new Vector();
+
+ /** Prints debugging information to System.err. */
+ public static void printDebuggingInfo() {
+ if (uninitialized) init();
+ System.err.println("");
+ for (int i = 0; i < recentlyOpenedFiles.size(); i++)
+ System.err.println("File " + i + " (where 0 is most recent) is " + ((File)recentlyOpenedFiles.elementAt(i)).getAbsolutePath());
+ System.err.println("");
+ }
+
+ /** Returns a user-friendly label for f that is not longer than
+ the user's preferences allow. */
+ public static String getLabel(File f) {
+ if (uninitialized) init();
+ String path = f.getAbsolutePath();
+ int l;
+ if ((l = path.length()) <= maxCharsToShow)
+ return path;
+ return "..." + path.substring(l - maxCharsToShow + 3);
+ }
+}