You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2015/04/14 19:41:30 UTC
svn commit: r1673479 - in
/pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools: PDFReader.java
util/ util/RecentFiles.java
Author: tilman
Date: Tue Apr 14 17:41:29 2015
New Revision: 1673479
URL: http://svn.apache.org/r1673479
Log:
PDFBOX-2748: add reusable "recent files" feature to PDFReader, as suggested by Khyrul Bashar
Added:
pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/util/
pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/util/RecentFiles.java (with props)
Modified:
pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/PDFReader.java
Modified: pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/PDFReader.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/PDFReader.java?rev=1673479&r1=1673478&r2=1673479&view=diff
==============================================================================
--- pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/PDFReader.java (original)
+++ pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/PDFReader.java Tue Apr 14 17:41:29 2015
@@ -20,11 +20,15 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
+
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
@@ -44,6 +48,7 @@ import javax.swing.AbstractAction;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.apache.pdfbox.printing.PDFPrinter;
import org.apache.pdfbox.rendering.PDFRenderer;
+import org.apache.pdfbox.tools.util.RecentFiles;
import org.apache.pdfbox.tools.gui.PageWrapper;
import org.apache.pdfbox.tools.gui.ReaderBottomPanel;
import org.apache.pdfbox.pdmodel.PDDocument;
@@ -61,6 +66,7 @@ public class PDFReader extends JFrame
private JMenu fileMenu;
private JMenuBar menuBar;
private JMenuItem openMenuItem;
+ private JMenu recentFileSubmenu;
private JMenuItem printMenuItem;
private JMenu viewMenu;
private JMenuItem nextPageItem;
@@ -77,6 +83,7 @@ public class PDFReader extends JFrame
private int currentPage = 0;
private int numberOfPages = 0;
private String currentFilename = null;
+ private String currentFilePath = null;
private static final String PASSWORD = "-password";
@@ -88,6 +95,8 @@ public class PDFReader extends JFrame
private static final String FIRST_PAGE = "first_page";
private static final String LAST_PAGE = "last_page";
+ private RecentFiles recentFiles;
+
/**
* Constructor.
*/
@@ -101,6 +110,7 @@ public class PDFReader extends JFrame
{
menuBar = new JMenuBar();
fileMenu = new JMenu();
+ recentFileSubmenu = new JMenu();
openMenuItem = new JMenuItem();
saveAsImageMenuItem = new JMenuItem();
exitMenuItem = new JMenuItem();
@@ -143,6 +153,20 @@ public class PDFReader extends JFrame
fileMenu.add(openMenuItem);
+ try
+ {
+ recentFiles = new RecentFiles(this.getClass(), 5);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ recentFileSubmenu.setText("Open recent Files");
+ recentFileSubmenu.setEnabled(false);
+ addRecentFileItems();
+ fileMenu.add(recentFileSubmenu);
+ fileMenu.addSeparator();
printMenuItem.setText("Print");
printMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
@@ -325,9 +349,77 @@ public class PDFReader extends JFrame
setBounds((screenSize.width - 700) / 2, (screenSize.height - 600) / 2, 700, 600);
}
+ private void addRecentFileItems()
+ {
+ Action recentMenuAction = new AbstractAction()
+ {
+ @Override
+ public void actionPerformed(ActionEvent actionEvent)
+ {
+ String filePath = (String) ((JComponent) actionEvent.getSource()).getClientProperty("path");
+ try
+ {
+ openPDFFile(filePath, "");
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+
+ MouseListener mouseListener = new MouseListener()
+ {
+ @Override
+ public void mouseClicked(MouseEvent mouseEvent)
+ {
+ }
+
+ @Override
+ public void mousePressed(MouseEvent mouseEvent)
+ {
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent mouseEvent)
+ {
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent mouseEvent)
+ {
+ String filePath = (String) ((JComponent) mouseEvent.getSource()).getClientProperty("path");
+ bottomStatusPanel.getStatusLabel().setText(filePath);
+ }
+
+ @Override
+ public void mouseExited(MouseEvent mouseEvent)
+ {
+ bottomStatusPanel.getStatusLabel().setText("");
+ }
+ };
+
+ if (!recentFiles.isEmpty())
+ {
+ recentFileSubmenu.removeAll();
+ ArrayList<String> files = recentFiles.getFiles();
+ for (int i = files.size() - 1; i >= 0; i--)
+ {
+ String path = files.get(i);
+ String name = new File(path).getName();
+ JMenuItem recentFileMenuItem = new JMenuItem(name);
+ recentFileMenuItem.putClientProperty("path", path);
+ recentFileMenuItem.addActionListener(recentMenuAction);
+ recentFileMenuItem.addMouseListener(mouseListener);
+ recentFileSubmenu.add(recentFileMenuItem);
+ }
+ recentFileSubmenu.setEnabled(true);
+ }
+ }
+
private void updateTitle()
{
- setTitle(BASETITLE + ": " + currentFilename + " " +
+ setTitle(BASETITLE + ": " + currentFilename + " " +
"(" + (currentPage + 1) + "/" + numberOfPages + ")");
}
@@ -401,7 +493,9 @@ public class PDFReader extends JFrame
if (document != null)
{
document.close();
+ recentFiles.addFile(currentFilePath);
}
+ recentFiles.close();
}
catch (IOException io)
{
@@ -451,9 +545,12 @@ public class PDFReader extends JFrame
{
document.close();
documentPanel.removeAll();
+ recentFiles.addFile(currentFilePath);
}
File file = new File(filename);
+ currentFilePath = file.getPath();
+ recentFiles.removeFile(file.getPath());
parseDocument(file, password);
pages = document.getPages();
numberOfPages = document.getNumberOfPages();
@@ -461,6 +558,7 @@ public class PDFReader extends JFrame
currentPage = 0;
updateTitle();
showPage(0);
+ addRecentFileItems();
}
private void showPage(int pageNumber) throws IOException
Added: pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/util/RecentFiles.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/util/RecentFiles.java?rev=1673479&view=auto
==============================================================================
--- pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/util/RecentFiles.java (added)
+++ pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/util/RecentFiles.java Tue Apr 14 17:41:29 2015
@@ -0,0 +1,188 @@
+package org.apache.pdfbox.tools.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.prefs.Preferences;
+
+/**
+ * A class to save recent file history in preference using java Preference api.
+ */
+public class RecentFiles
+{
+ private static final String KEY = "recent_files_";
+ private static final String PATH_KEY = "recent_files_%d_%d";
+ private static final String PIECES_LENGTH_KEY = "recent_files_%d_length";
+ private static final String HISTORY_LENGTH = "history_length";
+
+ private final Preferences pref;
+ private Queue<String> filePaths;
+ private final int maximum;
+
+ /**
+ * Constructor.
+ *
+ * @param className the class for which this Recentfiles object is created and it will be used
+ * to create preference instance.
+ * @param maximumFile the number of recent files to remember.
+ */
+ public RecentFiles(Class className, int maximumFile)
+ {
+ this.maximum = maximumFile;
+ this.pref = Preferences.userNodeForPackage(className);
+ filePaths = readHistoryFromPref();
+ if (filePaths == null)
+ {
+ filePaths = new ConcurrentLinkedDeque<String>();
+ }
+ }
+
+ /**
+ * Clear the previous recent file history.
+ */
+ public void removeAll()
+ {
+ filePaths.clear();
+ }
+
+ /**
+ * Check if file history is empty.
+ *
+ * @return if history is empty return true otherwise return false.
+ */
+ public boolean isEmpty()
+ {
+ return filePaths.isEmpty();
+ }
+
+ /**
+ * Add a new file in recent file history.
+ *
+ * @param path path to the file. this path means File#getPath() method returned String.
+ */
+ public void addFile(String path)
+ {
+ if (filePaths.size() >= maximum + 1 && path != null)
+ {
+ filePaths.remove();
+ }
+
+ filePaths.add(path);
+ }
+
+ /**
+ * Remove a file from recent file history.
+ *
+ * @param path path string to the file. this path means File#getPath() method returned String.
+ */
+ public void removeFile(String path)
+ {
+ if (filePaths.contains(path))
+ {
+ filePaths.remove(path);
+ }
+ }
+
+ /**
+ * This gives the file in descending order where order is according to the time it is added.
+ * This checks for file's existence in file history.
+ *
+ * @return return the file paths in an ArrayList.
+ */
+ public ArrayList<String> getFiles()
+ {
+ if (!isEmpty())
+ {
+ ArrayList<String> files = new ArrayList<String>();
+ for (String path : filePaths)
+ {
+ File file = new File(path);
+ if (file.exists())
+ {
+ files.add(path);
+ }
+ }
+ if (files.size() > maximum)
+ {
+ files.remove(0);
+ }
+ return files;
+ }
+ return null;
+ }
+
+ /**
+ * This method save the present recent file history in the preference. To get the recent file
+ * history in next session this method must be called.
+ *
+ * @throws IOException if saving in preference doesn't success.
+ */
+ public void close() throws IOException
+ {
+ writeHistoryToPref(filePaths);
+ }
+
+ private String[] breakString(String fullPath)
+ {
+ int allowedStringLength = Preferences.MAX_VALUE_LENGTH;
+ ArrayList<String> pieces = new ArrayList<String>();
+ int beginIndex = 0;
+ int remainingLength = fullPath.length();
+ int endIndex = 0;
+ while (remainingLength > 0)
+ {
+ endIndex += remainingLength >= allowedStringLength ? allowedStringLength : remainingLength;
+ pieces.add(fullPath.substring(beginIndex, endIndex));
+ beginIndex = endIndex;
+ remainingLength = fullPath.length() - endIndex;
+ }
+ return pieces.toArray(new String[pieces.size()]);
+ }
+
+ private void writeHistoryToPref(Queue<String> filePaths)
+ {
+ if (filePaths.size() == 0)
+ {
+ return;
+ }
+ Preferences node = pref.node(KEY);
+ node.putInt(HISTORY_LENGTH, filePaths.size());
+ int fileCount = 1;
+ for (String path : filePaths)
+ {
+ String[] pieces = breakString(path);
+ node.putInt(String.format(PIECES_LENGTH_KEY, fileCount), pieces.length);
+ for (int i = 0; i < pieces.length; i++)
+ {
+ node.put(String.format(PATH_KEY, fileCount, i), pieces[i]);
+ }
+ fileCount++;
+ }
+ }
+
+ private Queue<String> readHistoryFromPref()
+ {
+ Preferences node = pref.node(KEY);
+ int historyLength = node.getInt(HISTORY_LENGTH, 0);
+ if (historyLength == 0)
+ {
+ return null;
+ }
+ Queue<String> history = new ConcurrentLinkedDeque<String>();
+
+ for (int i = 1; i <= historyLength; i++)
+ {
+ int totalPieces = node.getInt(String.format(PIECES_LENGTH_KEY, i), 0);
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int j = 0; j < totalPieces; j++)
+ {
+ String piece = node.get(String.format(PATH_KEY, i, j), "");
+ stringBuilder.append(piece);
+ }
+ history.add(stringBuilder.toString());
+ }
+ return history;
+ }
+}
Propchange: pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/util/RecentFiles.java
------------------------------------------------------------------------------
svn:eol-style = native