Save the state of a JFileChooser - java

A user has asked that I preserve the state of the JFileChooser across application restarts. Specifically, he has asked that I preserve the state of the Details / List view type selection. Two applicable questions:
How can I start the JFileChooser in the Details view?
Start a JFileChooser with files ordered by date
These both show methods of starting the JFileChooser with specific default behavior. The piece that is missing is a way to determine what behavior the user had active (view type, sort order) when the JFileChooser window is closed, so that it can be saved and restored later. Any ideas?

You can use the Properties API or Preferences API to save/restore user data.
At start up you would read the users data and set the file chooser property.
To listener for user changes to the view type you can add a PropertyChangeListener to the file chooser and listen for the viewType event. Then you would update the user data with the new value.
You can add a RowSorterListener to the RowSorter to listen for changes in the sort order. You would then need to save the sort order. I don't know the best way to store the sort data.

Based on feedback, I have created the following class. I believe that this gives all the functionality I am looking for. This class depends on this SwingUtils class.
You will also need to update access restriction rules (at least in Eclipse) to allow access to sun/swing/FilePane as described in
Access restriction: Is not accessible due to restriction on required library ..\jre\lib\rt.jar
Edit: Cleanup resource leak
After coming back to work from a long vacation, I realized that the code I initially provided could leak JFileChooser instances, and so I have reworked it to provide an AutoCloseable entity that can be used in a try-with-resources statement. Sorry for the churn.
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.prefs.Preferences;
import javax.swing.Action;
import javax.swing.JFileChooser;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.RowSorter.SortKey;
import javax.swing.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.swing.FilePane;
import darrylbu.util.SwingUtils;
#SuppressWarnings("restriction")
public class JFileChooserPersisterFactory {
private static final String VIEW_TYPE_LIST = "viewTypeList"; //$NON-NLS-1$
private static final String VIEW_TYPE_DETAILS = "viewTypeDetails"; //$NON-NLS-1$
private static final String CHOOSER_CLOSING_PROPERTY = "JFileChooserDialogIsClosingProperty"; //$NON-NLS-1$
private static final String VIEW_TYPE_PROPERTY = "viewType"; //$NON-NLS-1$
private static final String IS_DETAILS = "isDetails"; //$NON-NLS-1$
private static final String SORT_ORDER = "sortOrder"; //$NON-NLS-1$
private JFileChooserPersisterFactory() {
}
public static JFileChooserPersister createJFileChooserPersister() {
JFileChooserPersisterImpl persister = new JFileChooserPersisterImpl();
persister.init();
return persister;
}
public interface JFileChooserPersister extends AutoCloseable {
JFileChooser getJFileChooser();
#Override
void close();
}
private static class JFileChooserPersisterImpl implements JFileChooserPersister {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Preferences persistentPrefs = Preferences.userNodeForPackage(getClass());
private final JFileChooser chooser;
private boolean isDetails;
private OnChooserClosing chooserClosingListener;
private FilePane filePane;
private OnViewTypeChanged viewTypeChangedListener;
public JFileChooserPersisterImpl() {
chooser = new JFileChooser();
}
public void init() {
restoreSettings();
registerForViewTypeChangeEvents();
chooserClosingListener = new OnChooserClosing();
chooser.addPropertyChangeListener(CHOOSER_CLOSING_PROPERTY, chooserClosingListener);
}
#Override
public JFileChooser getJFileChooser() {
return chooser;
}
private void persistSettings() {
persistentPrefs.putBoolean(IS_DETAILS, isDetails);
if (isDetails) persistSortOrder();
}
private void persistSortOrder() {
byte[] serializedSortOrder = serializeSortOrder();
if (serializedSortOrder != null)
persistentPrefs.putByteArray(SORT_ORDER, serializedSortOrder);
}
private byte[] serializeSortOrder() {
List<? extends SortKey> keys = getRowSorter().getSortKeys();
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(byteStream)) {
out.writeObject(new SortOrderInfo(keys));
return byteStream.toByteArray();
} catch (IOException e) {
logger.error("Could not serialize JFileChooser row sort order.", e); //$NON-NLS-1$
}
return null;
}
private void restoreSettings() {
isDetails = persistentPrefs.getBoolean(IS_DETAILS, false);
if (isDetails) {
setToDetailsView();
applyInitialSortOrder();
} else {
setToListView();
}
}
private void setToDetailsView() {
Action details = chooser.getActionMap().get(VIEW_TYPE_DETAILS);
details.actionPerformed(null);
}
private void setToListView() {
Action details = chooser.getActionMap().get(VIEW_TYPE_LIST);
details.actionPerformed(null);
}
private void applyInitialSortOrder() {
byte[] serializedSortOrder = persistentPrefs.getByteArray(SORT_ORDER, null);
if (serializedSortOrder == null) return;
ByteArrayInputStream byteStream = new ByteArrayInputStream(serializedSortOrder);
try (ObjectInputStream in = new ObjectInputStream(byteStream)) {
setSortInfo((SortOrderInfo) in.readObject());
} catch (IOException | ClassNotFoundException e) {
logger.error("Could not deserialize JFileChooser row sort order.", e); //$NON-NLS-1$
}
}
private void setSortInfo(SortOrderInfo info) {
info.setSortOrder(getRowSorter());
}
private RowSorter<?> getRowSorter() {
JTable table = SwingUtils.getDescendantsOfType(JTable.class, chooser).get(0);
RowSorter<?> rowSorter = table.getRowSorter();
return rowSorter;
}
private void registerForViewTypeChangeEvents() {
filePane = SwingUtils.getDescendantsOfType(FilePane.class, chooser).get(0);
viewTypeChangedListener = new OnViewTypeChanged();
filePane.addPropertyChangeListener(VIEW_TYPE_PROPERTY, viewTypeChangedListener);
}
private final class OnChooserClosing implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
persistSettings();
}
}
private class OnViewTypeChanged implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
isDetails = ((int) evt.getNewValue()) == FilePane.VIEWTYPE_DETAILS;
}
}
public static class SortOrderInfo implements Serializable {
private static final long serialVersionUID = -5393878644049680645L;
private final List<ColumnSortInfo> keyInfo = new ArrayList<>();
public SortOrderInfo(List<? extends SortKey> keys) {
for (SortKey sortKey : keys) {
keyInfo.add(new ColumnSortInfo(sortKey));
}
}
public void setSortOrder(RowSorter<?> rowSorter) {
rowSorter.setSortKeys(makeSortKeys());
}
private List<SortKey> makeSortKeys() {
List<SortKey> keys = new ArrayList<>();
for (ColumnSortInfo info : keyInfo) {
keys.add(info.makeSortKey());
}
return keys;
}
public static class ColumnSortInfo implements Serializable {
private static final long serialVersionUID = 5406885180955729893L;
private final SortOrder sortOrder;
private final int column;
public ColumnSortInfo(SortKey sortKey) {
column = sortKey.getColumn();
sortOrder = sortKey.getSortOrder();
}
public SortKey makeSortKey() {
return new SortKey(column, sortOrder);
}
}
}
#Override
public void close() {
chooser.removePropertyChangeListener(CHOOSER_CLOSING_PROPERTY, chooserClosingListener);
filePane.removePropertyChangeListener(VIEW_TYPE_PROPERTY, viewTypeChangedListener);
}
}
}

Related

How to test a Java Library in Eclipse

I'm looking for a way to test a java library. I never worked before with libraries written by me, and I'm trying to understand how to debug a java project without a main method. In particular, I took a java library that handles barcodes and I'm trying to change its contents. In the example version there is only a bar code, while I need to implement other types of bar codes. Since in the decompiled library imported into Eclipse there is no Main method to debug the content and see any errors. Operationally how can I do in Eclipse that execute the code, instead of each time exporting the jar file and replacing it in the classpath that containing the original library?
I looked for something online, but I didn't find an example tha t explains how to do.
import com.crystaldecisions.reports.common.CrystalResourcesFactory;
import com.crystaldecisions.reports.common.value.FormulaValue;
import com.crystaldecisions.reports.common.value.FormulaValueType;
import com.crystaldecisions.reports.common.value.StringValue;
import com.crystaldecisions.reports.formulas.FormulaFunction;
import com.crystaldecisions.reports.formulas.FormulaFunctionArgumentDefinition;
import com.crystaldecisions.reports.formulas.FormulaFunctionCallException;
import com.crystaldecisions.reports.formulas.FormulaValueReference;
import com.crystaldecisions.reports.formulas.SimpleFormulaFunctionArgumentDefinition;
public abstract class CodeEAN13Base
implements FormulaFunction
{
FormulaFunctionArgumentDefinition[] myArguments = { SimpleFormulaFunctionArgumentDefinition.string };
protected CrystalResourcesFactory resCrystal;
public CodeEAN13Base()
{
this.resCrystal = new CrystalResourcesFactory("Messages");
}
protected final String doTranslation(String inputData,String opz)
// protected final String doTranslation(String inputData)
{
String returnVal = "";
// returnVal = returnVal + translateCharWrapper(inputData);
returnVal = returnVal + translateCharWrapper(inputData,opz);
return returnVal;
}
#Override
public final FormulaValue evaluate(FormulaValueReference[] arguments)
throws FormulaFunctionCallException
{
StringValue dataStringArg = (StringValue)arguments[0].getFormulaValue();
StringValue opzArg =(StringValue)arguments[1].getFormulaValue();
String dataString = dataStringArg.getString();
String opz=opzArg.getString();
String returnVal = doTranslation(dataString,opz);
return StringValue.fromString(returnVal);
}
#Override
public final FormulaFunctionArgumentDefinition[] getArguments()
{
return this.myArguments;
}
#Override
public final FormulaValueType getReturnType()
{
return FormulaValueType.string;
}
protected abstract String translate(String inputData,String opz)
throws InvalidBarcodeDataException;
//protected abstract String translate(String inputData)
//throws InvalidBarcodeDataException;
// private String translateCharWrapper(String inputData)
private String translateCharWrapper(String inputData,String opz)
{
String returnString;
try
{
// returnString = translate(inputData);
returnString = translate(inputData,opz);
} catch (InvalidBarcodeDataException e) {
returnString = "";
}
return returnString;
}
#Override
public void validateArgumentValues(FormulaValueReference[] arguments)
throws FormulaFunctionCallException
{}
}

Xpages: How to ensure my cacheBean only loads once

Still struggling with properly making a cacheBean. I think I want the bean to be a singleton, from what I have read. Will only need
one instance of it. Use it to get often used keywords and so on.
http://blog.defrog.nl/2013/02/prefered-way-for-referencing-beans-from.html
I used this pattern to make my CacheBean (and used a utility method).
If I make this a managedBean by putting it into Faces-config, then I can easily get the value of models
<xp:text escape="true" id="computedField1"
value="#{CacheBean.models}"></xp:text>
The JSF takes care of instantiating the bean for me.
But I don't want it to reload the same values (like models) over and over. I thought that to get that to happen I needed to make
a POJO and grab the currentInstance of the bean, as in the url.
However, when I made this change (taking the bean out of the faces-config file, I cannot seem to get a handle on the properties.
This won't even compile:
<xp:text escape="true" id="computedField1"
value="#{Cache.getCurrentInstance().models}">
</xp:text>
What am I doing wrong?
================================
package com.scoular.cache;
import java.io.Serializable;
import org.openntf.domino.xsp.XspOpenLogUtil;
import com.scoular.Utils;
public class CacheBean implements Serializable {
private static final long serialVersionUID = -2665922853615670023L;
public static final String BEAN_NAME = "CacheBean";
private String pcDataDBpath;
private Vector<Object> models = new Vector<Object>();
public CacheBean() {
initConfigData();
}
private void initConfigData() {
try {
loadModels();
loadDBPaths();
} catch (Exception e) {
XspOpenLogUtil.logError(e);
}
}
// Getters and Setters
public static CacheBean getInstance(String beanName) {
return (CacheBean) Utils.getVariableValue(beanName);
}
public static CacheBean getInstance() {
return getInstance(BEAN_NAME);
}
public String getPcDataDBpath() {
return pcDataDBpath;
}
public void setPcDataDBpath(String pcDataDBpath) {
this.pcDataDBpath = pcDataDBpath;
}
public void loadDBPaths() {
Session session = Factory.getSession();
Database tmpDB = session.getCurrentDatabase();
pcAppDBpath = (tmpDB.getServer() + "!!" + "scoApps\\PC\\PCApp.nsf");
pcDataDBpath = (tmpDB.getServer() + "!!" + "scoApps\\PC\\PCData.nsf");
compDirDBpath = (tmpDB.getServer() + "!!" + "compdir.nsf");
}
public void loadModels() {
try {
Session session = Factory.getSession();
Database tmpDB = session.getCurrentDatabase();
Database PCDataDB = session.getDatabase(tmpDB.getServer(), "scoApps\\PC\\PCData.nsf");
ViewNavigator vn = PCDataDB.getView("dbLookupModels").createViewNav();
ViewEntry entry = vn.getFirst();
while (entry != null) {
Vector<Object> thisCat = entry.getColumnValues();
if (entry.isCategory()) {
String thisCatString = thisCat.elementAt(0).toString();
models.addElement(thisCatString);
}
entry = vn.getNextCategory();
}
} catch (Exception e) {
XspOpenLogUtil.logError(e);
}
}
p
ackage com.scoular;
import javax.faces.context.FacesContext;
public class Utils {
public static Object getVariableValue(String varName) {
FacesContext context = FacesContext.getCurrentInstance();
return context.getApplication().getVariableResolver().resolveVariable(context, varName);
}
}
When the bean has the right scope you can access the bean directly if is created.
private static final String BEAN_NAME = "CacheBean";
//access to the bean
public static CacheBean get() {
return (CacheBean) JSFUtil.resolveVariable(BEAN_NAME);
}
//in my JSFUtil class I have the method
public static Object resolveVariable(String variable) {
return FacesContext.getCurrentInstance().getApplication().getVariableResolver().resolveVariable(FacesContext.getCurrentInstance(), variable);
}
so in a Java Class you can call
CacheBean.get().models
in EL you can use
CacheBean.models
I can tell you why it's not compiling at least.
value="#{Cache.getCurrentInstance().models}"
That's EL. So there should not be a get or a (). You want
value="#{Cache.currentInstance.models}"
And check your var name as I thought you were using CacheBean and not Cache.

How can we store the timestamp into the list when log4j messages are stored into the list and fetched into a swt table created

I also need to store the time stamp inside the list when the log message is pushed into the list.So how can we get the timestamp and push into the list.I am pushing the logs into the list as follows
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.RollingFileAppender;
//import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.LoggingEvent;
public class Listappender extends RollingFileAppender {
private List<LoggingEvent> events = new ArrayList<LoggingEvent>();
static List<String> clone = new ArrayList<String>();
#Override
public synchronized void doAppend(LoggingEvent event) {
//System.out.println("hi....");
//events.clear();
events.add(event);
super.doAppend(event);
clone.clear();
clone.add((String) event.getMessage());
//getEvents();
/*
for (int j = 0; j < events.size(); j++){
System.out.println(events.get(j));
System.out.println(j);
}*/
}
public List<String> getEntries()
{
return clone;
}
}
See how to create timestamp Java Timestamp - How can I create a Timestamp with the date 23/09/2007?
And you can simply do this
clone.add(timestamp.toString() + event.getMessage());
Just keep the LoggingEvent s in a list. You don't have to get the message and save it in a different list. The LoggingEvent has a public final long getTimeStamp() method to supply the time. Try using this code:
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.RollingFileAppender;
import org.apache.log4j.spi.LoggingEvent;
public class ListAppender extends RollingFileAppender {
private final List<LoggingEvent> events = new ArrayList<LoggingEvent>();
#Override
public synchronized void doAppend(LoggingEvent event) {
events.add(event);
super.doAppend(event);
}
public synchronized List<LoggingEvent> getLoggingEvents() {
List<LoggingEvent> clone = new ArrayList<>(events);
events.clear();
return clone;
}
}

How to use org.hibernate.action.spi.AfterTransactionCompletionProcess?

I found this class that I really want to use:
org.hibernate.action.spi.AfterTransactionCompletionProcess -
http://docs.jboss.org/hibernate/orm/3.6/javadocs/org/hibernate/action/AfterTransactionCompletionProcess.html
Basically, I'd like some custom logic to happen after the transaction is committed. But I cannot for the life of me figure out how to use this thing.
Where do I specify this interface? Any examples would be awesome.
Found an example in the Hibernate 4.3's unit test code base:
org.hibernate.envers.test.integration.basic.RegisterUserEventListenersTest
Shows exactly what I was looking for:
package org.hibernate.envers.test.integration.basic;
import org.hibernate.Session;
import org.hibernate.action.spi.AfterTransactionCompletionProcess;
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.envers.internal.tools.MutableInteger;
import org.hibernate.envers.test.BaseEnversFunctionalTestCase;
import org.hibernate.envers.test.entities.StrTestEntity;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.persister.entity.EntityPersister;
import org.junit.Assert;
import org.junit.Test;
import org.hibernate.testing.TestForIssue;
/**
* #author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class RegisterUserEventListenersTest extends BaseEnversFunctionalTestCase {
#Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {StrTestEntity.class};
}
#Test
#TestForIssue(jiraKey = "HHH-7478")
public void testTransactionProcessSynchronization() {
final EventListenerRegistry registry = sessionFactory().getServiceRegistry()
.getService( EventListenerRegistry.class );
final CountingPostInsertTransactionBoundaryListener listener = new CountingPostInsertTransactionBoundaryListener();
registry.getEventListenerGroup( EventType.POST_INSERT ).appendListener( listener );
Session session = openSession();
session.getTransaction().begin();
StrTestEntity entity = new StrTestEntity( "str1" );
session.save( entity );
session.getTransaction().commit();
session.close();
// Post insert listener invoked three times - before/after insertion of original data,
// revision entity and audit row.
Assert.assertEquals( 3, listener.getBeforeCount() );
Assert.assertEquals( 3, listener.getAfterCount() );
}
private static class CountingPostInsertTransactionBoundaryListener implements PostInsertEventListener {
private final MutableInteger beforeCounter = new MutableInteger();
private final MutableInteger afterCounter = new MutableInteger();
#Override
public void onPostInsert(PostInsertEvent event) {
event.getSession().getActionQueue().registerProcess(
new BeforeTransactionCompletionProcess() {
#Override
public void doBeforeTransactionCompletion(SessionImplementor session) {
beforeCounter.increase();
}
}
);
event.getSession().getActionQueue().registerProcess(
new AfterTransactionCompletionProcess() {
#Override
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
afterCounter.increase();
}
}
);
}
#Override
public boolean requiresPostCommitHanding(EntityPersister persister) {
return true;
}
public int getBeforeCount() {
return beforeCounter.get();
}
public int getAfterCount() {
return afterCounter.get();
}
}
}

J2ME key event handling

I have created a textfield that takes all characters from the user.. but i want to disable the space so that user cant enter space ...help??
pin = new TextField("Pin#","",4,TextField.PASSWORD);
If it's a PIN number then maybe you should replace the constraints parameter with TextField.NUMERIC | TextField.PASSWORD.
Implement the ItemStateListener interface. Then call this.setItemStateListener(this) in the Form constructor.
Implement the itemStateChanged method so that if the Item is the one you are interested in then get its content and test it if it contains spaces.
In my case I create a MIDlet and a Form which contains a TextField. And it works. I do not know why did you say that the solution I gave you did not work to you ! Here is a very simple example I give ( I created it and tested it ! ) :
package hello;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class HelloMIDlet extends MIDlet {
public Display display;
public HelloMIDlet() {
display = Display.getDisplay(this);
}
public void startApp() {
Form f = new F(display);
display.setCurrent(f);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
package hello;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemStateListener;
import javax.microedition.lcdui.TextField;
public class F extends Form implements ItemStateListener {
private TextField pin = new TextField("PIN :","",4,TextField.PASSWORD);
private Alert alert;
private Display disp;
public F(Display d)
{
super("");
disp = d;
this.setItemStateListener(this);
this.append(pin);
}
public void itemStateChanged(Item item) {
if (item == pin)
{
for (int i=0; i<pin.getString().length(); i++)
{
if (String.valueOf(pin.getString().charAt(i)).equals(new String(" ")))
displayAlert();
}
}
}
private void displayAlert()
{
alert = new Alert("Info","No space please !",null, AlertType.ERROR);
disp.setCurrent(alert, this);
}
}

Categories

Resources