-AJlib is a simple java library with Swing widgets, utilities and other stuff.
-
-This library tries to simplify the development of Swing applications ... which is sometime a nightmare!
-It contains the classes I developed during the Yapbam project in
-order to deal with the problems I encountered.
-
-The source code is available here: https://github.com/fathzer/ajlib
-For maven users, AJLib is also available in Maven central:
+
+
+Overview
+
+
+
+AJlib is a simple java library with Swing widgets, utilities and other stuff.
+
+This library tries to simplify the development of Swing applications ... which is sometime a nightmare!
+It contains the classes I developed during the Yapbam project in
+order to deal with the problems I encountered.
+
+The source code is available here: https://github.com/fathzer/ajlib
+For maven users, AJLib is also available in Maven central:
<dependency>
<groupId>com.fathzer</groupId>
<artifactId>ajlib</artifactId>
- <version>0.3.16</version>
+ <version>0.3.16</version>
</dependency>
-It is released under Apache 2 License (information is available there).
-It requires Java 7+.
+It is released under Apache 2 License (information is available there).
+It requires Java 7+.
\ No newline at end of file
diff --git a/ajlib/pom.xml b/ajlib/pom.xml
new file mode 100644
index 0000000..59242aa
--- /dev/null
+++ b/ajlib/pom.xml
@@ -0,0 +1,30 @@
+
+ 4.0.0
+
+ com.fathzer
+ ajlib-parent-pom
+ 1.0.0
+
+ ajlib
+ 0.3.16
+
+ jar
+
+ A-JLib
+
+
+
+ com.fathzer
+ jlocal
+ 1.0.0
+
+
+ org.codehaus.mojo
+ animal-sniffer-annotations
+ ${animal-sniffer-version}
+ provided
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/Browser.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/Browser.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/Browser.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/Browser.java
index 3663341..b8a2e91 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/Browser.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/Browser.java
@@ -1,49 +1,49 @@
-package com.fathzer.soft.ajlib.swing;
-
-import java.awt.Component;
-import java.awt.Desktop;
-import java.awt.Toolkit;
-import java.awt.datatransfer.Clipboard;
-import java.awt.datatransfer.StringSelection;
-import java.io.IOException;
-import java.net.URI;
-
-import javax.swing.JOptionPane;
-
-import com.fathzer.jlocal.Formatter;
-import com.fathzer.soft.ajlib.swing.framework.Application;
-
-
-/** A class that is able to open a web browser to display an URI.
- *
The main advantage of this class is to display an alert dialog if java is not able to open the browser.
- */
-public abstract class Browser {
- private Browser() {
- //To prevent instance to be constructed
- }
-
- /** Displays an URI in a browser.
- * @param uri The uri to display
- * @param parent The parent component of the dialog displayed if browser is not available.
- * @param errorDialogTitle The title of the dialog displayed if browser is not available.
- */
- public static void show(URI uri, Component parent, String errorDialogTitle) {
- try {
- Desktop.getDesktop().browse(uri);
- } catch (IOException | UnsupportedOperationException e) {
- error(uri, parent, errorDialogTitle);
- }
- }
-
- private static void error(URI uri, Component parent, String errorDialogTitle) {
- String url = uri.toString();
- String message = Formatter.format(Application.getString("Browser.unsupported.message", parent.getLocale()), url); //$NON-NLS-1$
- StringSelection stringSelection = new StringSelection(url);
- Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
- clipboard.setContents(stringSelection, null);
- if (errorDialogTitle == null) {
- errorDialogTitle = "";
- }
- JOptionPane.showMessageDialog(Utils.getOwnerWindow(parent), message, errorDialogTitle, JOptionPane.WARNING_MESSAGE); //$NON-NLS-1$
- }
-}
+package com.fathzer.soft.ajlib.swing;
+
+import java.awt.Component;
+import java.awt.Desktop;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import java.io.IOException;
+import java.net.URI;
+
+import javax.swing.JOptionPane;
+
+import com.fathzer.jlocal.Formatter;
+import com.fathzer.soft.ajlib.swing.framework.Application;
+
+
+/** A class that is able to open a web browser to display an URI.
+ *
The main advantage of this class is to display an alert dialog if java is not able to open the browser.
+ */
+public abstract class Browser {
+ private Browser() {
+ //To prevent instance to be constructed
+ }
+
+ /** Displays an URI in a browser.
+ * @param uri The uri to display
+ * @param parent The parent component of the dialog displayed if browser is not available.
+ * @param errorDialogTitle The title of the dialog displayed if browser is not available.
+ */
+ public static void show(URI uri, Component parent, String errorDialogTitle) {
+ try {
+ Desktop.getDesktop().browse(uri);
+ } catch (IOException | UnsupportedOperationException e) {
+ error(uri, parent, errorDialogTitle);
+ }
+ }
+
+ private static void error(URI uri, Component parent, String errorDialogTitle) {
+ String url = uri.toString();
+ String message = Formatter.format(Application.getString("Browser.unsupported.message", parent.getLocale()), url); //$NON-NLS-1$
+ StringSelection stringSelection = new StringSelection(url);
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ clipboard.setContents(stringSelection, null);
+ if (errorDialogTitle == null) {
+ errorDialogTitle = "";
+ }
+ JOptionPane.showMessageDialog(Utils.getOwnerWindow(parent), message, errorDialogTitle, JOptionPane.WARNING_MESSAGE); //$NON-NLS-1$
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/ButtonGroup.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/ButtonGroup.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/ButtonGroup.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/ButtonGroup.java
index f4077c5..7e31502 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/ButtonGroup.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/ButtonGroup.java
@@ -1,141 +1,141 @@
-package com.fathzer.soft.ajlib.swing;
-
-import java.awt.event.*;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Observable;
-
-import javax.swing.AbstractButton;
-
-/**
- * This class is, like javax.swing.ButtonGroup, used to create a multiple-exclusion scope for
- * a set of buttons. Creating a set of buttons with the same ButtonGroup
object means that
- * turning "on" one of those buttons turns off all other buttons in the group.
- *
- * The main difference between this group and the swing one is that you can deselected buttons by clicking on them
- * and have a group without no selected button (see {@link #setAutoDeselect(boolean)}).
- * Another difference is that this class extends the java.util.Observable class and calls its observers update method
- * when the selected button changes.
- *
- */
-public class ButtonGroup extends Observable {
- /**
- * The buttons list
- */
- private List buttons;
- /**
- * The current selection.
- */
- private AbstractButton selected;
- private ItemListener listener;
- private boolean autoDeselect;
-
- /**
- * Constructor.
- */
- public ButtonGroup() {
- this.autoDeselect = false;
- this.buttons = new ArrayList<>();
- this.selected = null;
- this.listener = new ItemListener() {
- @Override
- public void itemStateChanged(ItemEvent e) {
- AbstractButton b = (AbstractButton) e.getItem();
- if (e.getStateChange()==ItemEvent.SELECTED) {
- setSelected(b);
- } else if (selected==b) {
- if (autoDeselect) {
- setSelected(null);
- } else {
- selected.setSelected(true);
- }
- }
- }
- };
- }
-
- /**
- * Adds a button to this group.
- * @param b the button to be added
- * @exception NullPointerException if the button is null
- */
- public void add(AbstractButton b) {
- if (b==null) {
- throw new NullPointerException();
- }
- buttons.add(b);
- b.addItemListener(listener);
- if (b.isSelected()) {
- setSelected(b);
- }
- }
-
- /**
- * Removes a button from this group.
- * @param b the button to be removed
- * @exception IllegalArgumentException if the button is unknown in this group
- * @exception NullPointerException if the button is null
- */
- public void remove(AbstractButton b) {
- if (b == null) {
- throw new NullPointerException();
- }
- if (this.buttons.remove(b)) {
- b.removeItemListener(this.listener);
- if (this.selected==b) {
- setSelected(null);
- }
- } else {
- throw new IllegalArgumentException();
- }
- }
-
- /**
- * Clears the selection such that none of the buttons in the
- * ButtonGroup
are selected.
- */
- public void clearSelection() {
- if (selected != null) {
- setSelected(null);
- }
- }
-
- /**
- * Returns the selected button.
- * @return the selected button
- */
- public AbstractButton getSelected() {
- return this.selected;
- }
-
- /** Changes the selected button.
- * @param b the button to be selected (null deselects all buttons)
- * @exception IllegalArgumentException if the button is not in this group
- */
- public void setSelected(AbstractButton b) {
- if (b==this.selected) {
- return;
- }
- if ((b!=null) && (!this.buttons.contains(b))) {
- throw new IllegalArgumentException();
- }
- AbstractButton old = this.selected;
- this.selected = b;
- if (b!=null) {
- b.setSelected(true);
- }
- if (old!=null) {
- old.setSelected(false);
- }
- this.setChanged();
- this.notifyObservers(this.selected);
- }
-
- /** Activates/deactivates the ability to deselect a selected button by cliking onto it.
- *
The default behavior is "a click on a selected button does nothing".
- * @param autoDeselect true to have selected button to be deactivated when clicked
- */
- public void setAutoDeselect(boolean autoDeselect) {
- this.autoDeselect = autoDeselect;
- }
-}
+package com.fathzer.soft.ajlib.swing;
+
+import java.awt.event.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Observable;
+
+import javax.swing.AbstractButton;
+
+/**
+ * This class is, like javax.swing.ButtonGroup, used to create a multiple-exclusion scope for
+ * a set of buttons. Creating a set of buttons with the same ButtonGroup
object means that
+ * turning "on" one of those buttons turns off all other buttons in the group.
+ *
+ * The main difference between this group and the swing one is that you can deselected buttons by clicking on them
+ * and have a group without no selected button (see {@link #setAutoDeselect(boolean)}).
+ * Another difference is that this class extends the java.util.Observable class and calls its observers update method
+ * when the selected button changes.
+ *
+ */
+public class ButtonGroup extends Observable {
+ /**
+ * The buttons list
+ */
+ private List buttons;
+ /**
+ * The current selection.
+ */
+ private AbstractButton selected;
+ private ItemListener listener;
+ private boolean autoDeselect;
+
+ /**
+ * Constructor.
+ */
+ public ButtonGroup() {
+ this.autoDeselect = false;
+ this.buttons = new ArrayList<>();
+ this.selected = null;
+ this.listener = new ItemListener() {
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ AbstractButton b = (AbstractButton) e.getItem();
+ if (e.getStateChange()==ItemEvent.SELECTED) {
+ setSelected(b);
+ } else if (selected==b) {
+ if (autoDeselect) {
+ setSelected(null);
+ } else {
+ selected.setSelected(true);
+ }
+ }
+ }
+ };
+ }
+
+ /**
+ * Adds a button to this group.
+ * @param b the button to be added
+ * @exception NullPointerException if the button is null
+ */
+ public void add(AbstractButton b) {
+ if (b==null) {
+ throw new NullPointerException();
+ }
+ buttons.add(b);
+ b.addItemListener(listener);
+ if (b.isSelected()) {
+ setSelected(b);
+ }
+ }
+
+ /**
+ * Removes a button from this group.
+ * @param b the button to be removed
+ * @exception IllegalArgumentException if the button is unknown in this group
+ * @exception NullPointerException if the button is null
+ */
+ public void remove(AbstractButton b) {
+ if (b == null) {
+ throw new NullPointerException();
+ }
+ if (this.buttons.remove(b)) {
+ b.removeItemListener(this.listener);
+ if (this.selected==b) {
+ setSelected(null);
+ }
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Clears the selection such that none of the buttons in the
+ * ButtonGroup
are selected.
+ */
+ public void clearSelection() {
+ if (selected != null) {
+ setSelected(null);
+ }
+ }
+
+ /**
+ * Returns the selected button.
+ * @return the selected button
+ */
+ public AbstractButton getSelected() {
+ return this.selected;
+ }
+
+ /** Changes the selected button.
+ * @param b the button to be selected (null deselects all buttons)
+ * @exception IllegalArgumentException if the button is not in this group
+ */
+ public void setSelected(AbstractButton b) {
+ if (b==this.selected) {
+ return;
+ }
+ if ((b!=null) && (!this.buttons.contains(b))) {
+ throw new IllegalArgumentException();
+ }
+ AbstractButton old = this.selected;
+ this.selected = b;
+ if (b!=null) {
+ b.setSelected(true);
+ }
+ if (old!=null) {
+ old.setSelected(false);
+ }
+ this.setChanged();
+ this.notifyObservers(this.selected);
+ }
+
+ /** Activates/deactivates the ability to deselect a selected button by cliking onto it.
+ *
The default behavior is "a click on a selected button does nothing".
+ * @param autoDeselect true to have selected button to be deactivated when clicked
+ */
+ public void setAutoDeselect(boolean autoDeselect) {
+ this.autoDeselect = autoDeselect;
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/FontUtils.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/FontUtils.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/FontUtils.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/FontUtils.java
index 5c1c77c..bf81a00 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/FontUtils.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/FontUtils.java
@@ -1,64 +1,64 @@
-package com.fathzer.soft.ajlib.swing;
-
-import java.awt.Font;
-import java.awt.GraphicsEnvironment;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-import javax.swing.UIManager;
-
-/** Some utilities related to font management.
- */
-public abstract class FontUtils {
- private static final String DEFAULT_FONT_PROPERTY_NAME = "defaultFont"; //$NON-NLS-1$
-
- private FontUtils() {
- super();
- }
-
- /** Gets the list of available text fonts.
- *
A text font is a font able to display text. if a font is available in the system but only displays symbols
- * it is not available as a text font.
- *
Please note that the returned list is approximated by the list of fonts able to display their own localized name. This could change in the future.
- * @param locale a locale used to display text.
- * @return The list of fonts that are available and able to display text in the specified locale.
- */
- public static List getAvailableTextFonts(Locale locale) {
- ArrayList result = new ArrayList<>();
- Font[] allfonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
- for (Font font : allfonts) {
- if (font.canDisplayUpTo(font.getFontName(locale)) == -1) {
- result.add(font);
- }
- }
- return result;
- }
-
- /** Tests whether a look and feel supports a default font
- * @param lookAndFeelName The look and feel name.
- * @return true if the look and feel supports default font.
- */
- public static boolean isDefaultFontSupportedByLookAndFeel(String lookAndFeelName) {
- return "Nimbus".equals(lookAndFeelName);
- }
-
- /** Gets the current default font.
- * @return a Font or null if the current look and feel do not supports default font.
- */
- public static Font getDefaultFont() {
- return isDefaultFontSupportedByLookAndFeel(UIManager.getLookAndFeel().getName()) ?
- (Font)UIManager.getDefaults().getFont(DEFAULT_FONT_PROPERTY_NAME) : null;
- }
-
- /** Sets the default font.
- *
Note that if the current UI does not support default font, the method does nothing.
- * @param font The new default font
- * @see FontUtils#isDefaultFontSupportedByLookAndFeel(String)
- */
- public static void setDefaultFont(Font font) {
- if (isDefaultFontSupportedByLookAndFeel(UIManager.getLookAndFeel().getName())) {
- UIManager.getLookAndFeelDefaults().put(DEFAULT_FONT_PROPERTY_NAME, font);
- }
- }
-}
+package com.fathzer.soft.ajlib.swing;
+
+import java.awt.Font;
+import java.awt.GraphicsEnvironment;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import javax.swing.UIManager;
+
+/** Some utilities related to font management.
+ */
+public abstract class FontUtils {
+ private static final String DEFAULT_FONT_PROPERTY_NAME = "defaultFont"; //$NON-NLS-1$
+
+ private FontUtils() {
+ super();
+ }
+
+ /** Gets the list of available text fonts.
+ *
A text font is a font able to display text. if a font is available in the system but only displays symbols
+ * it is not available as a text font.
+ *
Please note that the returned list is approximated by the list of fonts able to display their own localized name. This could change in the future.
+ * @param locale a locale used to display text.
+ * @return The list of fonts that are available and able to display text in the specified locale.
+ */
+ public static List getAvailableTextFonts(Locale locale) {
+ ArrayList result = new ArrayList<>();
+ Font[] allfonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
+ for (Font font : allfonts) {
+ if (font.canDisplayUpTo(font.getFontName(locale)) == -1) {
+ result.add(font);
+ }
+ }
+ return result;
+ }
+
+ /** Tests whether a look and feel supports a default font
+ * @param lookAndFeelName The look and feel name.
+ * @return true if the look and feel supports default font.
+ */
+ public static boolean isDefaultFontSupportedByLookAndFeel(String lookAndFeelName) {
+ return "Nimbus".equals(lookAndFeelName);
+ }
+
+ /** Gets the current default font.
+ * @return a Font or null if the current look and feel do not supports default font.
+ */
+ public static Font getDefaultFont() {
+ return isDefaultFontSupportedByLookAndFeel(UIManager.getLookAndFeel().getName()) ?
+ (Font)UIManager.getDefaults().getFont(DEFAULT_FONT_PROPERTY_NAME) : null;
+ }
+
+ /** Sets the default font.
+ *
Note that if the current UI does not support default font, the method does nothing.
+ * @param font The new default font
+ * @see FontUtils#isDefaultFontSupportedByLookAndFeel(String)
+ */
+ public static void setDefaultFont(Font font) {
+ if (isDefaultFontSupportedByLookAndFeel(UIManager.getLookAndFeel().getName())) {
+ UIManager.getLookAndFeelDefaults().put(DEFAULT_FONT_PROPERTY_NAME, font);
+ }
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/TextSearcher.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/TextSearcher.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/TextSearcher.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/TextSearcher.java
index a335ad2..d2f4a3a 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/TextSearcher.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/TextSearcher.java
@@ -1,220 +1,220 @@
-package com.fathzer.soft.ajlib.swing;
-
-import java.text.Normalizer;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.swing.text.BadLocationException;
-import javax.swing.text.DefaultHighlighter;
-import javax.swing.text.Document;
-import javax.swing.text.Highlighter;
-import javax.swing.text.JTextComponent;
-
-import com.fathzer.soft.ajlib.swing.widget.HTMLPane;
-
-
-/**
- * A class that searches for a text in a JTextComponent and highlights all
- * occurrences of that text.
- * It could be used, for instance, with an HTMLPane.
- * It supports case and diacritical sensitive/insensitive search.
- *
- * @author Jean-Marc Astesana
- * This code was inspired by an example from Kim Topley (ISBN: 0 13
- * 083292 8 - Publisher: Prentice Hall
- * @see HTMLPane
- */
-public class TextSearcher {
- protected JTextComponent comp;
- private boolean caseSensitive;
- private boolean diacriticalSensitive;
- private String text;
- private int[] offsets;
- private int searchedNormalizedLength;
-
- /**
- * Constructor.
- *
The searched text is set to null.
- * @param comp The text component in which to search
- * @see #TextSearcher(JTextComponent, String)
- */
- public TextSearcher(JTextComponent comp) {
- this(comp, null);
- }
-
- /**
- * Constructor.
- *
By default, the searcher is not case sensitive nor diacritical sensitive.
- * @param comp The text component in which to search
- * @param searchedText The text to search
- */
- public TextSearcher(JTextComponent comp, String searchedText) {
- this.comp = comp;
- this.caseSensitive = false;
- this.diacriticalSensitive = false;
- this.text = searchedText;
- search();
- }
-
- /**
- * Searches for this.text and updates the offset of all the occurrences.
- */
- private void search() {
- if (text == null || text.isEmpty()) {
- this.offsets = new int[0];
- return;
- }
-
- // Look for the text we are given
- // 1) Extract a normalized form of the text in which to search
- String content = null;
- try {
- Document d = comp.getDocument();
- content = normalize(d.getText(0, d.getLength()));
- } catch (BadLocationException e) {
- // Cannot happen
- throw new RuntimeException(e);
- }
-
- // 2) Get the normalized form of the searched text
- text = normalize(text);
-
- // 3) Search for the searched text
- List indexes = new LinkedList<>();
- int lastIndex = 0;
- int size = 0;
- searchedNormalizedLength = text.length();
- while ((lastIndex = content.indexOf(text, lastIndex)) != -1) {
- indexes.add(lastIndex);
- size++;
- lastIndex = lastIndex + searchedNormalizedLength;
- }
-
- offsets = new int[size];
- Iterator iter = indexes.iterator();
- for (int i = 0; i < offsets.length; i++) {
- offsets[i] = iter.next();
- }
- }
-
- /**
- * Gets the normalized version of a text.
- * The normalized version is lowercased if the TextSearcher is not case
- * sensitive and has no diacritical marks if it is diacritical insensitive.
- * @param content
- * @return a String
- */
- private String normalize(String content) {
- if (!isCaseSensitive()) {
- content = content.toLowerCase();
- }
- if (!isDiacriticalSensitive()) {
- content = Normalizer.normalize(content, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
- }
- return content;
- }
-
- /**
- * Tests whether the search is case sensitive or not.
- *
- * @return true if the search is case sensitive.
- */
- public boolean isCaseSensitive() {
- return this.caseSensitive;
- }
-
- /**
- * Sets if the search is case sensitive or not.
- * By default, the search is not case sensitive.
- * This method updates the offsets attribute.
- * @param caseSensitive true to have a case sensitive search
- * @see #getOffsets()
- */
- public void setCaseSentitive(boolean caseSensitive) {
- if (caseSensitive != this.caseSensitive) {
- this.caseSensitive = caseSensitive;
- search();
- }
- }
-
- /**
- * Tests whether the search is diacritical sensitive or not.
- * @return true if the search is diacritical sensitive.
- */
- public boolean isDiacriticalSensitive() {
- return diacriticalSensitive;
- }
-
- /**
- * Sets if the search is diacritical sensitive or not.
- * By default, the search is not diacritical sensitive.
- * This method updates the offsets attribute.
- * @param diacriticalSensitive true to have a diacritical sensitive search
- * @see #getOffsets()
- */
- public void setDiacriticalSensitive(boolean diacriticalSensitive) {
- if (diacriticalSensitive != this.diacriticalSensitive) {
- this.diacriticalSensitive = diacriticalSensitive;
- search();
- }
- }
-
- /** Gets the offsets of the searched text.
- *
These offsets can be passed to the highlight methods
- * @return a int array (its dimension is 0 if the text was not found)
- * @see #highlight(int, javax.swing.text.Highlighter.HighlightPainter)
- * @see #highlight(int[], javax.swing.text.Highlighter.HighlightPainter)
- */
- public int[] getOffsets() {
- return offsets;
- }
-
- /** Highlights some portions of the text.
- * @param offsets the start of the portions to highlight (these offsets are returned by getOffsets method).
- * null to remove all highlights.
- * @param painter The painter to be used (or null to use the default one).
- * @throws BadLocationException if offsets are out of text bounds
- * @see #getOffsets()
- */
- public void highlight(int[] offsets, Highlighter.HighlightPainter painter) throws BadLocationException {
- if (painter==null) {
- painter = DefaultHighlighter.DefaultPainter;
- }
- // Remove any existing highlights for last word
- Highlighter highlighter = comp.getHighlighter();
- highlighter.removeAllHighlights();
- if (offsets!=null) {
- for (int i = 0; i < offsets.length; i++) {
- highlighter.addHighlight(offsets[i], offsets[i] + this.searchedNormalizedLength, painter);
- }
- // Scroll the text pane in order to view the first occurrence.
- if (offsets.length>0) {
- comp.scrollRectToVisible(comp.modelToView(offsets[0]));
- }
- }
- }
-
- /** Highlights a portion of the text.
- * @param offset the start of the portion to highlight (one of the offsets returned by getOffsets method).
- * @param painter The painter to be used (or null to use the default one).
- * @throws BadLocationException if offset is out of text bounds
- * @see #getOffsets()
- */
- public void highlight(int offset, Highlighter.HighlightPainter painter) throws BadLocationException {
- if (painter==null) {
- painter = DefaultHighlighter.DefaultPainter;
- }
- // Remove any existing highlights for last word
- Highlighter highlighter = comp.getHighlighter();
- highlighter.removeAllHighlights();
- highlighter.addHighlight(offset, offset + this.searchedNormalizedLength, painter);
- // Scroll the text pane in order to view the first occurrence.
- comp.scrollRectToVisible(comp.modelToView(offset));
- }
-
- public void setSearchedText(String text) {
- this.text = text;
- search();
- }
+package com.fathzer.soft.ajlib.swing;
+
+import java.text.Normalizer;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultHighlighter;
+import javax.swing.text.Document;
+import javax.swing.text.Highlighter;
+import javax.swing.text.JTextComponent;
+
+import com.fathzer.soft.ajlib.swing.widget.HTMLPane;
+
+
+/**
+ * A class that searches for a text in a JTextComponent and highlights all
+ * occurrences of that text.
+ * It could be used, for instance, with an HTMLPane.
+ * It supports case and diacritical sensitive/insensitive search.
+ *
+ * @author Jean-Marc Astesana
+ * This code was inspired by an example from Kim Topley (ISBN: 0 13
+ * 083292 8 - Publisher: Prentice Hall
+ * @see HTMLPane
+ */
+public class TextSearcher {
+ protected JTextComponent comp;
+ private boolean caseSensitive;
+ private boolean diacriticalSensitive;
+ private String text;
+ private int[] offsets;
+ private int searchedNormalizedLength;
+
+ /**
+ * Constructor.
+ *
The searched text is set to null.
+ * @param comp The text component in which to search
+ * @see #TextSearcher(JTextComponent, String)
+ */
+ public TextSearcher(JTextComponent comp) {
+ this(comp, null);
+ }
+
+ /**
+ * Constructor.
+ *
By default, the searcher is not case sensitive nor diacritical sensitive.
+ * @param comp The text component in which to search
+ * @param searchedText The text to search
+ */
+ public TextSearcher(JTextComponent comp, String searchedText) {
+ this.comp = comp;
+ this.caseSensitive = false;
+ this.diacriticalSensitive = false;
+ this.text = searchedText;
+ search();
+ }
+
+ /**
+ * Searches for this.text and updates the offset of all the occurrences.
+ */
+ private void search() {
+ if (text == null || text.isEmpty()) {
+ this.offsets = new int[0];
+ return;
+ }
+
+ // Look for the text we are given
+ // 1) Extract a normalized form of the text in which to search
+ String content = null;
+ try {
+ Document d = comp.getDocument();
+ content = normalize(d.getText(0, d.getLength()));
+ } catch (BadLocationException e) {
+ // Cannot happen
+ throw new RuntimeException(e);
+ }
+
+ // 2) Get the normalized form of the searched text
+ text = normalize(text);
+
+ // 3) Search for the searched text
+ List indexes = new LinkedList<>();
+ int lastIndex = 0;
+ int size = 0;
+ searchedNormalizedLength = text.length();
+ while ((lastIndex = content.indexOf(text, lastIndex)) != -1) {
+ indexes.add(lastIndex);
+ size++;
+ lastIndex = lastIndex + searchedNormalizedLength;
+ }
+
+ offsets = new int[size];
+ Iterator iter = indexes.iterator();
+ for (int i = 0; i < offsets.length; i++) {
+ offsets[i] = iter.next();
+ }
+ }
+
+ /**
+ * Gets the normalized version of a text.
+ * The normalized version is lowercased if the TextSearcher is not case
+ * sensitive and has no diacritical marks if it is diacritical insensitive.
+ * @param content
+ * @return a String
+ */
+ private String normalize(String content) {
+ if (!isCaseSensitive()) {
+ content = content.toLowerCase();
+ }
+ if (!isDiacriticalSensitive()) {
+ content = Normalizer.normalize(content, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
+ }
+ return content;
+ }
+
+ /**
+ * Tests whether the search is case sensitive or not.
+ *
+ * @return true if the search is case sensitive.
+ */
+ public boolean isCaseSensitive() {
+ return this.caseSensitive;
+ }
+
+ /**
+ * Sets if the search is case sensitive or not.
+ * By default, the search is not case sensitive.
+ * This method updates the offsets attribute.
+ * @param caseSensitive true to have a case sensitive search
+ * @see #getOffsets()
+ */
+ public void setCaseSentitive(boolean caseSensitive) {
+ if (caseSensitive != this.caseSensitive) {
+ this.caseSensitive = caseSensitive;
+ search();
+ }
+ }
+
+ /**
+ * Tests whether the search is diacritical sensitive or not.
+ * @return true if the search is diacritical sensitive.
+ */
+ public boolean isDiacriticalSensitive() {
+ return diacriticalSensitive;
+ }
+
+ /**
+ * Sets if the search is diacritical sensitive or not.
+ * By default, the search is not diacritical sensitive.
+ * This method updates the offsets attribute.
+ * @param diacriticalSensitive true to have a diacritical sensitive search
+ * @see #getOffsets()
+ */
+ public void setDiacriticalSensitive(boolean diacriticalSensitive) {
+ if (diacriticalSensitive != this.diacriticalSensitive) {
+ this.diacriticalSensitive = diacriticalSensitive;
+ search();
+ }
+ }
+
+ /** Gets the offsets of the searched text.
+ *
These offsets can be passed to the highlight methods
+ * @return a int array (its dimension is 0 if the text was not found)
+ * @see #highlight(int, javax.swing.text.Highlighter.HighlightPainter)
+ * @see #highlight(int[], javax.swing.text.Highlighter.HighlightPainter)
+ */
+ public int[] getOffsets() {
+ return offsets;
+ }
+
+ /** Highlights some portions of the text.
+ * @param offsets the start of the portions to highlight (these offsets are returned by getOffsets method).
+ * null to remove all highlights.
+ * @param painter The painter to be used (or null to use the default one).
+ * @throws BadLocationException if offsets are out of text bounds
+ * @see #getOffsets()
+ */
+ public void highlight(int[] offsets, Highlighter.HighlightPainter painter) throws BadLocationException {
+ if (painter==null) {
+ painter = DefaultHighlighter.DefaultPainter;
+ }
+ // Remove any existing highlights for last word
+ Highlighter highlighter = comp.getHighlighter();
+ highlighter.removeAllHighlights();
+ if (offsets!=null) {
+ for (int i = 0; i < offsets.length; i++) {
+ highlighter.addHighlight(offsets[i], offsets[i] + this.searchedNormalizedLength, painter);
+ }
+ // Scroll the text pane in order to view the first occurrence.
+ if (offsets.length>0) {
+ comp.scrollRectToVisible(comp.modelToView(offsets[0]));
+ }
+ }
+ }
+
+ /** Highlights a portion of the text.
+ * @param offset the start of the portion to highlight (one of the offsets returned by getOffsets method).
+ * @param painter The painter to be used (or null to use the default one).
+ * @throws BadLocationException if offset is out of text bounds
+ * @see #getOffsets()
+ */
+ public void highlight(int offset, Highlighter.HighlightPainter painter) throws BadLocationException {
+ if (painter==null) {
+ painter = DefaultHighlighter.DefaultPainter;
+ }
+ // Remove any existing highlights for last word
+ Highlighter highlighter = comp.getHighlighter();
+ highlighter.removeAllHighlights();
+ highlighter.addHighlight(offset, offset + this.searchedNormalizedLength, painter);
+ // Scroll the text pane in order to view the first occurrence.
+ comp.scrollRectToVisible(comp.modelToView(offset));
+ }
+
+ public void setSearchedText(String text) {
+ this.text = text;
+ search();
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/ToolsFrame.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/ToolsFrame.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/swing/ToolsFrame.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/ToolsFrame.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/Utils.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/Utils.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/swing/Utils.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/Utils.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/dialog/AbstractDialog.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/dialog/AbstractDialog.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/dialog/AbstractDialog.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/dialog/AbstractDialog.java
index c766e55..17e7e36 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/dialog/AbstractDialog.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/dialog/AbstractDialog.java
@@ -1,251 +1,251 @@
-package com.fathzer.soft.ajlib.swing.dialog;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Container;
-import java.awt.Dimension;
-import java.awt.GraphicsEnvironment;
-import java.awt.Rectangle;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.WindowEvent;
-
-import javax.swing.*;
-
-import com.fathzer.soft.ajlib.swing.Utils;
-import com.fathzer.soft.ajlib.swing.framework.Application;
-
-
-/** An abstract dialog with a customizable center pane, an Ok and/or a Cancel button.
- *
By default, the dialog:
- * - is not resizable, call this.setResizable(true) to change this behavior (don't forget to call pack
- * and set the minimum size after calling setResizable).
- * - has default close operation sets to DISPOSE_ON_CLOSE.
- *
- * The dialog automatically wrap its center component in a JScollPane to guarantee that the dialog will
- * never be bigger than the screen (in such a case ok/cancel buttons would be hidden).
- * @param The class of the parameter of the dialog (information that is useful to build the center pane).
- * @param The class of the result of the dialog
- */
-public abstract class AbstractDialog extends JDialog {
- //FIXME The horizontal scroll bar is always shown when the vertical one is shown.
- private static final long serialVersionUID = 1L;
-
- private V result;
-
- private JButton cancelButton;
- private JButton okButton;
- /** The data passed to the dialog's constructor.
- */
- protected T data;
-
- /**
- * Constructor
- * @param owner Dialog's parent frame
- * @param title Dialog's title
- * @param data optional data (will be transfered to createContentPane)
- */
- protected AbstractDialog(Window owner, String title, T data) {
- super(owner, title, ModalityType.APPLICATION_MODAL);
- setDefaultCloseOperation(DISPOSE_ON_CLOSE);
- this.data = data;
- this.result = null;
- final AbstractAction escapeAction = new AbstractAction() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void actionPerformed(ActionEvent ae) {
- cancel();
- }
- };
- String actionMapKey = "ESCAPE_KEY"; //$NON-NLS-1$
- getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), actionMapKey);
- getRootPane().getActionMap().put(actionMapKey, escapeAction);
- this.setContentPane(this.createContentPane());
- this.setResizable(false);
- this.pack();
- this.setLocationRelativeTo(owner);
- }
-
- private Container createContentPane() {
- //Create the content pane.
- JPanel contentPane = new JPanel(new BorderLayout(5,5));
- contentPane.setOpaque(true);
- contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-
- JPanel southPane = new JPanel(new BorderLayout());
- southPane.setOpaque(false);
- JPanel buttonsPane = createButtonsPane();
-
- southPane.add(buttonsPane, BorderLayout.EAST);
- JComponent extra = createExtraComponent();
- if (extra!=null) {
- southPane.add(extra, BorderLayout.WEST);
- }
- contentPane.add(southPane, BorderLayout.SOUTH);
-
- JPanel centerPane = this.createCenterPane();
- if (centerPane != null) {
- // As component can be bigger than screen ... and we always want the "ok", "cancel" button to be present,
- // we will wrap the center pane into a scrollPane
- Component component = (centerPane instanceof Scrollable) ? centerPane : new DefaultScrollablePanel(centerPane);
- JScrollPane scrollPane = new JScrollPane(component);
- scrollPane.setBorder(null);
- contentPane.add(scrollPane, BorderLayout.CENTER);
- }
-
- this.updateOkButtonEnabled();
-
- ActionListener listener = new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- if (e.getSource().equals(okButton)) {
- confirm();
- } else {
- cancel();
- }
- }
- };
- getOkButton().addActionListener(listener);
- getCancelButton().addActionListener(listener);
- return contentPane;
- }
-
- /** Gets the panel that contains the ok and cancel buttons.
- *
This method creates a new JPanel with flow layout and ok and cancel buttons. Then, it defines ok has the default button.
- *
It can be override to add more buttons.
- * @return a JPanel
- */
- protected JPanel createButtonsPane() {
- JPanel buttonsPane = new JPanel();
- buttonsPane.setOpaque(false);
- buttonsPane.add(getOkButton());
- buttonsPane.add(getCancelButton());
- getRootPane().setDefaultButton(okButton);
- return buttonsPane;
- }
-
- /** Gets an extra component displayed on the same line as the buttons panel (see {@link #createButtonsPane()}) on the left side.
- *
By default, this method returns null.
- * @return A JComponent or null if no component is provided.
- */
- protected JComponent createExtraComponent() {
- return null;
- }
-
- /** Gets the ok button.
- *
If you want the dialog not to have an ok button, you may set the visibility of this button to false with
- * (getOkButton.setVisible(false)).
- * @return The ok button.
- */
- protected JButton getOkButton() {
- if (okButton==null) {
- okButton = new JButton(Application.getString("GenericButton.ok", getLocale())); //$NON-NLS-1$
- okButton.setOpaque(false);
- }
- return okButton;
- }
-
- /** Gets the cancel button.
- * If you want the dialog not to have a cancel button, you may set the visibility of this button to false
- * (getCancelButton.setVisible(false)).
- * @return the cancel button.
- */
- protected JButton getCancelButton() {
- if (cancelButton==null) {
- cancelButton = new JButton(Application.getString("GenericButton.cancel", getLocale())); //$NON-NLS-1$
- cancelButton.setToolTipText(Application.getString("GenericButton.cancel.toolTip", getLocale())); //$NON-NLS-1$
- cancelButton.setOpaque(false);
- }
- return cancelButton;
- }
-
- /** Gets the center pane of this dialog.
- * This method is called once by the constructor of the dialog.
- * The data attribute is already set to the data parameter passed to the constructor.
- * @return a panel
- */
- protected abstract JPanel createCenterPane();
-
- /** This method is called when the user clicks the ok button.
- *
This method should return the object, result of the dialog, that will be returned
- * by getResult.
- *
Note that it is not a good practice to override this method and set its visibility to public.
- * You should prefer calling the getResult method as buildResult may instantiate a new object each
- * time it is called.
- * @return an object
- * @see #getResult()
- */
- protected abstract V buildResult();
-
- /** This method is called when the user clicks the ok button.
- *
It calls the buildResult method, stores the result, then closes the dialog.
- * @see #getResult()
- */
- protected void confirm() {
- result = buildResult();
- close();
- }
-
- /** This method is called when the user clicks the cancel button.
- *
This default implementation closes the dialog.
- */
- protected void cancel() {
- result = null;
- close();
- }
-
- private void close() {
- dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
- }
-
- /** Checks if the user input is consistent and return a short explanation of why it is not.
- *
In this implementation, this method returns null. You should override this method if the input can be inconsistent.
- * @return a short message explaining why the ok button is disabled or null if the ok button has to be enabled.
- * This message will be displayed in the ok button toolTip.
- */
- protected String getOkDisabledCause() {
- return null;
- }
-
- /** Gets the result of this dialog.
- * @return an object, or null if the dialog was cancelled.
- */
- public V getResult() {
- return result;
- }
-
- /** Forces the state of the users input to be evaluated and updates the state of the ok button.
- * @see #getOkDisabledCause()
- */
- public void updateOkButtonEnabled() {
- String cause = getOkDisabledCause();
- this.getOkButton().setEnabled(cause==null);
- this.getOkButton().setToolTipText(cause==null?Application.getString("GenericButton.ok.toolTip", getLocale()):cause); //$NON-NLS-1$
- }
-
- @Override
- public Dimension getPreferredSize() {
- //We never want the dialog to be bigger than the available screen space
- //So, we will return the smaller of the preferred size and the available one.
- Dimension preferred = super.getPreferredSize();
- Rectangle availableSpace = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
- preferred.height = Math.min(preferred.height, availableSpace.height);
- preferred.width = Math.min(preferred.width, availableSpace.width);
- return preferred;
- }
-
-
- /** Gets the window which contains a component.
- * @deprecated
- * @param component the component
- * @return The window containing the component or null if no window contains the component.
- * @see Utils#getOwnerWindow(Component)
- */
- @Deprecated
- public static Window getOwnerWindow(Component component) {
- return Utils.getOwnerWindow(component);
- }
-}
+package com.fathzer.soft.ajlib.swing.dialog;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.GraphicsEnvironment;
+import java.awt.Rectangle;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowEvent;
+
+import javax.swing.*;
+
+import com.fathzer.soft.ajlib.swing.Utils;
+import com.fathzer.soft.ajlib.swing.framework.Application;
+
+
+/** An abstract dialog with a customizable center pane, an Ok and/or a Cancel button.
+ *
By default, the dialog:
+ * - is not resizable, call this.setResizable(true) to change this behavior (don't forget to call pack
+ * and set the minimum size after calling setResizable).
+ * - has default close operation sets to DISPOSE_ON_CLOSE.
+ *
+ * The dialog automatically wrap its center component in a JScollPane to guarantee that the dialog will
+ * never be bigger than the screen (in such a case ok/cancel buttons would be hidden).
+ * @param The class of the parameter of the dialog (information that is useful to build the center pane).
+ * @param The class of the result of the dialog
+ */
+public abstract class AbstractDialog extends JDialog {
+ //FIXME The horizontal scroll bar is always shown when the vertical one is shown.
+ private static final long serialVersionUID = 1L;
+
+ private V result;
+
+ private JButton cancelButton;
+ private JButton okButton;
+ /** The data passed to the dialog's constructor.
+ */
+ protected T data;
+
+ /**
+ * Constructor
+ * @param owner Dialog's parent frame
+ * @param title Dialog's title
+ * @param data optional data (will be transfered to createContentPane)
+ */
+ protected AbstractDialog(Window owner, String title, T data) {
+ super(owner, title, ModalityType.APPLICATION_MODAL);
+ setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+ this.data = data;
+ this.result = null;
+ final AbstractAction escapeAction = new AbstractAction() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void actionPerformed(ActionEvent ae) {
+ cancel();
+ }
+ };
+ String actionMapKey = "ESCAPE_KEY"; //$NON-NLS-1$
+ getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), actionMapKey);
+ getRootPane().getActionMap().put(actionMapKey, escapeAction);
+ this.setContentPane(this.createContentPane());
+ this.setResizable(false);
+ this.pack();
+ this.setLocationRelativeTo(owner);
+ }
+
+ private Container createContentPane() {
+ //Create the content pane.
+ JPanel contentPane = new JPanel(new BorderLayout(5,5));
+ contentPane.setOpaque(true);
+ contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+ JPanel southPane = new JPanel(new BorderLayout());
+ southPane.setOpaque(false);
+ JPanel buttonsPane = createButtonsPane();
+
+ southPane.add(buttonsPane, BorderLayout.EAST);
+ JComponent extra = createExtraComponent();
+ if (extra!=null) {
+ southPane.add(extra, BorderLayout.WEST);
+ }
+ contentPane.add(southPane, BorderLayout.SOUTH);
+
+ JPanel centerPane = this.createCenterPane();
+ if (centerPane != null) {
+ // As component can be bigger than screen ... and we always want the "ok", "cancel" button to be present,
+ // we will wrap the center pane into a scrollPane
+ Component component = (centerPane instanceof Scrollable) ? centerPane : new DefaultScrollablePanel(centerPane);
+ JScrollPane scrollPane = new JScrollPane(component);
+ scrollPane.setBorder(null);
+ contentPane.add(scrollPane, BorderLayout.CENTER);
+ }
+
+ this.updateOkButtonEnabled();
+
+ ActionListener listener = new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource().equals(okButton)) {
+ confirm();
+ } else {
+ cancel();
+ }
+ }
+ };
+ getOkButton().addActionListener(listener);
+ getCancelButton().addActionListener(listener);
+ return contentPane;
+ }
+
+ /** Gets the panel that contains the ok and cancel buttons.
+ *
This method creates a new JPanel with flow layout and ok and cancel buttons. Then, it defines ok has the default button.
+ *
It can be override to add more buttons.
+ * @return a JPanel
+ */
+ protected JPanel createButtonsPane() {
+ JPanel buttonsPane = new JPanel();
+ buttonsPane.setOpaque(false);
+ buttonsPane.add(getOkButton());
+ buttonsPane.add(getCancelButton());
+ getRootPane().setDefaultButton(okButton);
+ return buttonsPane;
+ }
+
+ /** Gets an extra component displayed on the same line as the buttons panel (see {@link #createButtonsPane()}) on the left side.
+ *
By default, this method returns null.
+ * @return A JComponent or null if no component is provided.
+ */
+ protected JComponent createExtraComponent() {
+ return null;
+ }
+
+ /** Gets the ok button.
+ *
If you want the dialog not to have an ok button, you may set the visibility of this button to false with
+ * (getOkButton.setVisible(false)).
+ * @return The ok button.
+ */
+ protected JButton getOkButton() {
+ if (okButton==null) {
+ okButton = new JButton(Application.getString("GenericButton.ok", getLocale())); //$NON-NLS-1$
+ okButton.setOpaque(false);
+ }
+ return okButton;
+ }
+
+ /** Gets the cancel button.
+ * If you want the dialog not to have a cancel button, you may set the visibility of this button to false
+ * (getCancelButton.setVisible(false)).
+ * @return the cancel button.
+ */
+ protected JButton getCancelButton() {
+ if (cancelButton==null) {
+ cancelButton = new JButton(Application.getString("GenericButton.cancel", getLocale())); //$NON-NLS-1$
+ cancelButton.setToolTipText(Application.getString("GenericButton.cancel.toolTip", getLocale())); //$NON-NLS-1$
+ cancelButton.setOpaque(false);
+ }
+ return cancelButton;
+ }
+
+ /** Gets the center pane of this dialog.
+ * This method is called once by the constructor of the dialog.
+ * The data attribute is already set to the data parameter passed to the constructor.
+ * @return a panel
+ */
+ protected abstract JPanel createCenterPane();
+
+ /** This method is called when the user clicks the ok button.
+ *
This method should return the object, result of the dialog, that will be returned
+ * by getResult.
+ *
Note that it is not a good practice to override this method and set its visibility to public.
+ * You should prefer calling the getResult method as buildResult may instantiate a new object each
+ * time it is called.
+ * @return an object
+ * @see #getResult()
+ */
+ protected abstract V buildResult();
+
+ /** This method is called when the user clicks the ok button.
+ *
It calls the buildResult method, stores the result, then closes the dialog.
+ * @see #getResult()
+ */
+ protected void confirm() {
+ result = buildResult();
+ close();
+ }
+
+ /** This method is called when the user clicks the cancel button.
+ *
This default implementation closes the dialog.
+ */
+ protected void cancel() {
+ result = null;
+ close();
+ }
+
+ private void close() {
+ dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
+ }
+
+ /** Checks if the user input is consistent and return a short explanation of why it is not.
+ *
In this implementation, this method returns null. You should override this method if the input can be inconsistent.
+ * @return a short message explaining why the ok button is disabled or null if the ok button has to be enabled.
+ * This message will be displayed in the ok button toolTip.
+ */
+ protected String getOkDisabledCause() {
+ return null;
+ }
+
+ /** Gets the result of this dialog.
+ * @return an object, or null if the dialog was cancelled.
+ */
+ public V getResult() {
+ return result;
+ }
+
+ /** Forces the state of the users input to be evaluated and updates the state of the ok button.
+ * @see #getOkDisabledCause()
+ */
+ public void updateOkButtonEnabled() {
+ String cause = getOkDisabledCause();
+ this.getOkButton().setEnabled(cause==null);
+ this.getOkButton().setToolTipText(cause==null?Application.getString("GenericButton.ok.toolTip", getLocale()):cause); //$NON-NLS-1$
+ }
+
+ @Override
+ public Dimension getPreferredSize() {
+ //We never want the dialog to be bigger than the available screen space
+ //So, we will return the smaller of the preferred size and the available one.
+ Dimension preferred = super.getPreferredSize();
+ Rectangle availableSpace = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
+ preferred.height = Math.min(preferred.height, availableSpace.height);
+ preferred.width = Math.min(preferred.width, availableSpace.width);
+ return preferred;
+ }
+
+
+ /** Gets the window which contains a component.
+ * @deprecated
+ * @param component the component
+ * @return The window containing the component or null if no window contains the component.
+ * @see Utils#getOwnerWindow(Component)
+ */
+ @Deprecated
+ public static Window getOwnerWindow(Component component) {
+ return Utils.getOwnerWindow(component);
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/dialog/DefaultScrollablePanel.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/dialog/DefaultScrollablePanel.java
similarity index 95%
rename from src/main/java/com/fathzer/soft/ajlib/swing/dialog/DefaultScrollablePanel.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/dialog/DefaultScrollablePanel.java
index 11e9f92..b6f9475 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/dialog/DefaultScrollablePanel.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/dialog/DefaultScrollablePanel.java
@@ -1,42 +1,42 @@
-package com.fathzer.soft.ajlib.swing.dialog;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.Rectangle;
-
-import javax.swing.JPanel;
-import javax.swing.Scrollable;
-
-@SuppressWarnings("serial")
-class DefaultScrollablePanel extends JPanel implements Scrollable {
- DefaultScrollablePanel(Component component) {
- super(new BorderLayout());
- this.add(component);
- }
-
- @Override
- public Dimension getPreferredScrollableViewportSize() {
- return this.getComponent(0).getPreferredSize();
- }
-
- @Override
- public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
- return 10;
- }
-
- @Override
- public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
- return 40;
- }
-
- @Override
- public boolean getScrollableTracksViewportWidth() {
- return true;
- }
-
- @Override
- public boolean getScrollableTracksViewportHeight() {
- return true;
- }
-}
+package com.fathzer.soft.ajlib.swing.dialog;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Rectangle;
+
+import javax.swing.JPanel;
+import javax.swing.Scrollable;
+
+@SuppressWarnings("serial")
+class DefaultScrollablePanel extends JPanel implements Scrollable {
+ DefaultScrollablePanel(Component component) {
+ super(new BorderLayout());
+ this.add(component);
+ }
+
+ @Override
+ public Dimension getPreferredScrollableViewportSize() {
+ return this.getComponent(0).getPreferredSize();
+ }
+
+ @Override
+ public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
+ return 10;
+ }
+
+ @Override
+ public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
+ return 40;
+ }
+
+ @Override
+ public boolean getScrollableTracksViewportWidth() {
+ return true;
+ }
+
+ @Override
+ public boolean getScrollableTracksViewportHeight() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/dialog/FileChooser.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/dialog/FileChooser.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/swing/dialog/FileChooser.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/dialog/FileChooser.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/dialog/package-info.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/dialog/package-info.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/dialog/package-info.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/dialog/package-info.java
index e063f66..c074f3c 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/dialog/package-info.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/dialog/package-info.java
@@ -1,3 +1,3 @@
-/** Swing dialog utilities*/
-package com.fathzer.soft.ajlib.swing.dialog;
-
+/** Swing dialog utilities*/
+package com.fathzer.soft.ajlib.swing.dialog;
+
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/framework/Application.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/framework/Application.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/swing/framework/Application.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/framework/Application.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/framework/MainMenu.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/framework/MainMenu.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/framework/MainMenu.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/framework/MainMenu.java
index 0a470aa..6fad250 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/framework/MainMenu.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/framework/MainMenu.java
@@ -1,38 +1,38 @@
-package com.fathzer.soft.ajlib.swing.framework;
-
-import java.awt.Toolkit;
-import java.awt.event.ActionEvent;
-
-import javax.swing.AbstractAction;
-import javax.swing.JMenu;
-import javax.swing.JMenuBar;
-import javax.swing.JMenuItem;
-import javax.swing.KeyStroke;
-
-@SuppressWarnings("serial")
-class MainMenu extends JMenuBar {
- public MainMenu (Application application) {
- JMenu menu = new JMenu(Application.getString("MainMenu.file")); //$NON-NLS-1$
- menu.setMnemonic(Application.getString("MainMenu.file.mnemonic").charAt(0)); //$NON-NLS-1$
- this.add(menu);
- JMenuItem menuItem = new JMenuItem(new QuitAction(application));
- menuItem.setAccelerator(KeyStroke.getKeyStroke(Application.getString("MainMenu.quit.shortcut").charAt(0), Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); //$NON-NLS-1$
- menuItem.setMnemonic(Application.getString("MainMenu.quit.mnemonic").charAt(0)); //$NON-NLS-1$
- menu.add(menuItem);
- }
-
- private static class QuitAction extends AbstractAction {
- private Application app;
-
- QuitAction(Application app) {
- super(Application.getString("MainMenu.quit"), null); //$NON-NLS-1$
- putValue(SHORT_DESCRIPTION, Application.getString("MainMenu.quit.tooltip")); //$NON-NLS-1$
- this.app = app;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- app.quit();
- }
- }
-}
+package com.fathzer.soft.ajlib.swing.framework;
+
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.KeyStroke;
+
+@SuppressWarnings("serial")
+class MainMenu extends JMenuBar {
+ public MainMenu (Application application) {
+ JMenu menu = new JMenu(Application.getString("MainMenu.file")); //$NON-NLS-1$
+ menu.setMnemonic(Application.getString("MainMenu.file.mnemonic").charAt(0)); //$NON-NLS-1$
+ this.add(menu);
+ JMenuItem menuItem = new JMenuItem(new QuitAction(application));
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(Application.getString("MainMenu.quit.shortcut").charAt(0), Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); //$NON-NLS-1$
+ menuItem.setMnemonic(Application.getString("MainMenu.quit.mnemonic").charAt(0)); //$NON-NLS-1$
+ menu.add(menuItem);
+ }
+
+ private static class QuitAction extends AbstractAction {
+ private Application app;
+
+ QuitAction(Application app) {
+ super(Application.getString("MainMenu.quit"), null); //$NON-NLS-1$
+ putValue(SHORT_DESCRIPTION, Application.getString("MainMenu.quit.tooltip")); //$NON-NLS-1$
+ this.app = app;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ app.quit();
+ }
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/framework/package-info.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/framework/package-info.java
similarity index 99%
rename from src/main/java/com/fathzer/soft/ajlib/swing/framework/package-info.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/framework/package-info.java
index 8da4771..5b20aea 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/framework/package-info.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/framework/package-info.java
@@ -1,2 +1,2 @@
-/** A simple framework to implement Java application*/
+/** A simple framework to implement Java application*/
package com.fathzer.soft.ajlib.swing.framework;
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/package-info.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/package-info.java
similarity index 98%
rename from src/main/java/com/fathzer/soft/ajlib/swing/package-info.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/package-info.java
index 33c9f1a..9138ac2 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/package-info.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/package-info.java
@@ -1,2 +1,2 @@
-/** General purpose swing utilities*/
+/** General purpose swing utilities*/
package com.fathzer.soft.ajlib.swing;
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/table/AbstractTableRowMover.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/AbstractTableRowMover.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/table/AbstractTableRowMover.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/AbstractTableRowMover.java
index 837a60d..bca137e 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/table/AbstractTableRowMover.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/AbstractTableRowMover.java
@@ -1,119 +1,119 @@
-package com.fathzer.soft.ajlib.swing.table;
-
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.ImageIcon;
-import javax.swing.JButton;
-import javax.swing.JPanel;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-
-import com.fathzer.soft.ajlib.utilities.ListUtils;
-
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-
-/** An abstract widget composed of two buttons to move up or down selected rows of a JTable.
- * @see JTable
- */
-public abstract class AbstractTableRowMover extends JPanel {
- private static final long serialVersionUID = 1L;
-
- private JButton downButton;
- private JButton upButton;
-
- private JTable table;
-
- /**
- * Creates the panel.
- * @param table The table that contains the moveable rows.
- */
- protected AbstractTableRowMover(JTable table) {
- this.table = table;
- initialize();
-
- getJTable().getSelectionModel().addListSelectionListener(new ListSelectionListener() {
- public void valueChanged(ListSelectionEvent e) {
- if (e.getValueIsAdjusting()) {
- return;
- }
- updateupDownEnabled();
- }
- });
- }
- private void initialize() {
- GridBagLayout gridBagLayout = new GridBagLayout();
- setLayout(gridBagLayout);
- GridBagConstraints gbcUpButton = new GridBagConstraints();
- gbcUpButton.insets = new Insets(0, 0, 5, 0);
- gbcUpButton.weighty = 1.0;
- gbcUpButton.anchor = GridBagConstraints.SOUTH;
- gbcUpButton.gridx = 0;
- gbcUpButton.gridy = 0;
- add(getUpButton(), gbcUpButton);
- GridBagConstraints gbcDownButton = new GridBagConstraints();
- gbcDownButton.anchor = GridBagConstraints.NORTH;
- gbcDownButton.weighty = 1.0;
- gbcDownButton.gridx = 0;
- gbcDownButton.gridy = 1;
- add(getDownButton(), gbcDownButton);
- }
-
- private JButton getUpButton() {
- if (upButton == null) {
- upButton = new JButton("");
- upButton.setIcon(new ImageIcon(AbstractTableRowMover.class.getResource("/com/fathzer/soft/ajlib/swing/widget/up.png"))); //$NON-NLS-1$
- upButton.setEnabled(false);
- upButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- int[] selectedRows = getJTable().getSelectedRows();
- moveModelRows(selectedRows, true);
- offsetSelection(selectedRows,-1);
- }
- });
- }
- return upButton;
- }
- private JButton getDownButton() {
- if (downButton == null) {
- downButton = new JButton("");
- downButton.setIcon(new ImageIcon(AbstractTableRowMover.class.getResource("/com/fathzer/soft/ajlib/swing/widget/down.png"))); //$NON-NLS-1$
- downButton.setEnabled(false);
- downButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- int[] selectedRows = getJTable().getSelectedRows();
- moveModelRows(selectedRows, false);
- offsetSelection(selectedRows,1);
- }
- });
- }
- return downButton;
- }
-
- private void updateupDownEnabled() {
- getUpButton().setEnabled(getJTable().getSelectedRow()>0);
- int [] rowsSelected=getJTable().getSelectedRows();
- getDownButton().setEnabled((rowsSelected.length!=0) && (rowsSelected[rowsSelected.length-1]!=getJTable().getRowCount()-1));
- }
- private void offsetSelection(int[] selectedRows, int offset) {
- for (int i = 0; i < selectedRows.length; i++) {
- selectedRows[i] = selectedRows[i]+offset;
- }
- getJTable().setSelectedIndexes(selectedRows);
- }
-
- protected JTable getJTable() {
- return this.table;
- }
-
- /** Moves the rows in the table model.
- *
This method is called when the user clicks the up or down buttons.
- *
It is mandatory that this method fire the proper model change event after updating the model.
- * @param selectedRows The moved rows
- * @param up true if the rows are moved up, false if they are moved down.
- * @see ListUtils#move(java.util.List, int[], int)
- */
- protected abstract void moveModelRows(int[] selectedRows, boolean up);
-}
+package com.fathzer.soft.ajlib.swing.table;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import com.fathzer.soft.ajlib.utilities.ListUtils;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+
+/** An abstract widget composed of two buttons to move up or down selected rows of a JTable.
+ * @see JTable
+ */
+public abstract class AbstractTableRowMover extends JPanel {
+ private static final long serialVersionUID = 1L;
+
+ private JButton downButton;
+ private JButton upButton;
+
+ private JTable table;
+
+ /**
+ * Creates the panel.
+ * @param table The table that contains the moveable rows.
+ */
+ protected AbstractTableRowMover(JTable table) {
+ this.table = table;
+ initialize();
+
+ getJTable().getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+ public void valueChanged(ListSelectionEvent e) {
+ if (e.getValueIsAdjusting()) {
+ return;
+ }
+ updateupDownEnabled();
+ }
+ });
+ }
+ private void initialize() {
+ GridBagLayout gridBagLayout = new GridBagLayout();
+ setLayout(gridBagLayout);
+ GridBagConstraints gbcUpButton = new GridBagConstraints();
+ gbcUpButton.insets = new Insets(0, 0, 5, 0);
+ gbcUpButton.weighty = 1.0;
+ gbcUpButton.anchor = GridBagConstraints.SOUTH;
+ gbcUpButton.gridx = 0;
+ gbcUpButton.gridy = 0;
+ add(getUpButton(), gbcUpButton);
+ GridBagConstraints gbcDownButton = new GridBagConstraints();
+ gbcDownButton.anchor = GridBagConstraints.NORTH;
+ gbcDownButton.weighty = 1.0;
+ gbcDownButton.gridx = 0;
+ gbcDownButton.gridy = 1;
+ add(getDownButton(), gbcDownButton);
+ }
+
+ private JButton getUpButton() {
+ if (upButton == null) {
+ upButton = new JButton("");
+ upButton.setIcon(new ImageIcon(AbstractTableRowMover.class.getResource("/com/fathzer/soft/ajlib/swing/widget/up.png"))); //$NON-NLS-1$
+ upButton.setEnabled(false);
+ upButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ int[] selectedRows = getJTable().getSelectedRows();
+ moveModelRows(selectedRows, true);
+ offsetSelection(selectedRows,-1);
+ }
+ });
+ }
+ return upButton;
+ }
+ private JButton getDownButton() {
+ if (downButton == null) {
+ downButton = new JButton("");
+ downButton.setIcon(new ImageIcon(AbstractTableRowMover.class.getResource("/com/fathzer/soft/ajlib/swing/widget/down.png"))); //$NON-NLS-1$
+ downButton.setEnabled(false);
+ downButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ int[] selectedRows = getJTable().getSelectedRows();
+ moveModelRows(selectedRows, false);
+ offsetSelection(selectedRows,1);
+ }
+ });
+ }
+ return downButton;
+ }
+
+ private void updateupDownEnabled() {
+ getUpButton().setEnabled(getJTable().getSelectedRow()>0);
+ int [] rowsSelected=getJTable().getSelectedRows();
+ getDownButton().setEnabled((rowsSelected.length!=0) && (rowsSelected[rowsSelected.length-1]!=getJTable().getRowCount()-1));
+ }
+ private void offsetSelection(int[] selectedRows, int offset) {
+ for (int i = 0; i < selectedRows.length; i++) {
+ selectedRows[i] = selectedRows[i]+offset;
+ }
+ getJTable().setSelectedIndexes(selectedRows);
+ }
+
+ protected JTable getJTable() {
+ return this.table;
+ }
+
+ /** Moves the rows in the table model.
+ *
This method is called when the user clicks the up or down buttons.
+ *
It is mandatory that this method fire the proper model change event after updating the model.
+ * @param selectedRows The moved rows
+ * @param up true if the rows are moved up, false if they are moved down.
+ * @see ListUtils#move(java.util.List, int[], int)
+ */
+ protected abstract void moveModelRows(int[] selectedRows, boolean up);
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/table/CSVExporter.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/CSVExporter.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/swing/table/CSVExporter.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/CSVExporter.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/table/CustomCellRenderer.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/CustomCellRenderer.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/table/CustomCellRenderer.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/CustomCellRenderer.java
index 3bdccb4..e9f39e5 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/table/CustomCellRenderer.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/CustomCellRenderer.java
@@ -1,92 +1,92 @@
-package com.fathzer.soft.ajlib.swing.table;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Calendar;
-import java.util.Date;
-
-import javax.swing.JTable;
-import javax.swing.SwingConstants;
-import javax.swing.table.DefaultTableCellRenderer;
-
-/** A JTable CellRenderer easy to customize.
- */
-public class CustomCellRenderer extends DefaultTableCellRenderer {
- private static final long serialVersionUID = 1L;
-
- @Override
- public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
- row = table.convertRowIndexToModel(row);
- column = table.convertColumnIndexToModel(column);
- this.setHorizontalAlignment(getAlignment(table, value, isSelected, hasFocus, row, column));
- this.setBackground(getBackground(table, value, isSelected, hasFocus, row, column));
- this.setForeground(getForeground(table, value, isSelected, hasFocus, row, column));
- setValue(getValue(table, value, isSelected, hasFocus, row, column));
- return this;
- }
-
- /** Gets the alignment.
- * @param table The JTable.
- * @param value The original value in the cell (not the replacement value returned by getReplacementValue).
- * @param isSelected true if cell is selected.
- * @param hasFocus true if cell has the focus.
- * @param rowModel The row index in the model.
- * @param columnModel The column index in the model.
- * @return The alignment, an int in the set SwingConstants: LEFT, CENTER, RIGHT, LEADING or TRAILING.
- * By default it returns CENTER if value is an instance of Date or Calendar, RIGHT if value is an instance of Float, Double
- * BigDecimal, Integer, Long or BigInteger, LEFT in other cases.
You may override this method to change this behavior.
- */
- protected int getAlignment(JTable table, Object value, boolean isSelected, boolean hasFocus, int rowModel, int columnModel) {
- int alignment = SwingConstants.LEFT;
- if ((value instanceof Date) || (value instanceof Calendar)) {
- alignment = SwingConstants.CENTER;
- } else if ((value instanceof Double) || (value instanceof Integer) || (value instanceof Long) || (value instanceof Float) ||
- (value instanceof BigDecimal) || (value instanceof BigInteger)) {
- alignment = SwingConstants.RIGHT;
- }
- return alignment;
- }
-
- /** Gets the replacement value of a cell.
- * This method allows you to change the value on the fly. By default, it returns the original value but you can override
- * this method to change this behavior.
- * @param table The JTable.
- * @param value The value in the cell.
- * @param isSelected true if cell is selected.
- * @param hasFocus true if cell has the focus.
- * @param rowModel The row index in the model.
- * @param columnModel The column index in the model.
- * @return The value that should be displayed in the cell.
- */
- protected Object getValue(JTable table, Object value, boolean isSelected, boolean hasFocus, int rowModel, int columnModel) {
- return value;
- }
-
- /** Gets the background color of a cell.
- * @param table The JTable.
- * @param value The value in the cell.
- * @param isSelected true if cell is selected.
- * @param hasFocus true if cell has the focus.
- * @param rowModel The row index in the model.
- * @param columnModel The column index in the model.
- * @return The background color of the cell. The default implementation returns the JTable default color.
- */
- protected Color getBackground(JTable table, Object value, boolean isSelected, boolean hasFocus, int rowModel, int columnModel) {
- return isSelected ? table.getSelectionBackground() : table.getBackground();
- }
-
- /** Gets the foreground color of a cell.
- * @param table The JTable.
- * @param value The value in the cell.
- * @param isSelected true if cell is selected.
- * @param hasFocus true if cell has the focus.
- * @param rowModel The row index in the model.
- * @param columnModel The column index in the model.
- * @return The foreground color of the cell. The default implementation returns the JTable default color.
- */
- protected Color getForeground(JTable table, Object value, boolean isSelected, boolean hasFocus, int rowModel, int columnModel) {
- return isSelected ? table.getSelectionForeground() : table.getForeground();
- }
-}
+package com.fathzer.soft.ajlib.swing.table;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Calendar;
+import java.util.Date;
+
+import javax.swing.JTable;
+import javax.swing.SwingConstants;
+import javax.swing.table.DefaultTableCellRenderer;
+
+/** A JTable CellRenderer easy to customize.
+ */
+public class CustomCellRenderer extends DefaultTableCellRenderer {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+ row = table.convertRowIndexToModel(row);
+ column = table.convertColumnIndexToModel(column);
+ this.setHorizontalAlignment(getAlignment(table, value, isSelected, hasFocus, row, column));
+ this.setBackground(getBackground(table, value, isSelected, hasFocus, row, column));
+ this.setForeground(getForeground(table, value, isSelected, hasFocus, row, column));
+ setValue(getValue(table, value, isSelected, hasFocus, row, column));
+ return this;
+ }
+
+ /** Gets the alignment.
+ * @param table The JTable.
+ * @param value The original value in the cell (not the replacement value returned by getReplacementValue).
+ * @param isSelected true if cell is selected.
+ * @param hasFocus true if cell has the focus.
+ * @param rowModel The row index in the model.
+ * @param columnModel The column index in the model.
+ * @return The alignment, an int in the set SwingConstants: LEFT, CENTER, RIGHT, LEADING or TRAILING.
+ * By default it returns CENTER if value is an instance of Date or Calendar, RIGHT if value is an instance of Float, Double
+ * BigDecimal, Integer, Long or BigInteger, LEFT in other cases.
You may override this method to change this behavior.
+ */
+ protected int getAlignment(JTable table, Object value, boolean isSelected, boolean hasFocus, int rowModel, int columnModel) {
+ int alignment = SwingConstants.LEFT;
+ if ((value instanceof Date) || (value instanceof Calendar)) {
+ alignment = SwingConstants.CENTER;
+ } else if ((value instanceof Double) || (value instanceof Integer) || (value instanceof Long) || (value instanceof Float) ||
+ (value instanceof BigDecimal) || (value instanceof BigInteger)) {
+ alignment = SwingConstants.RIGHT;
+ }
+ return alignment;
+ }
+
+ /** Gets the replacement value of a cell.
+ * This method allows you to change the value on the fly. By default, it returns the original value but you can override
+ * this method to change this behavior.
+ * @param table The JTable.
+ * @param value The value in the cell.
+ * @param isSelected true if cell is selected.
+ * @param hasFocus true if cell has the focus.
+ * @param rowModel The row index in the model.
+ * @param columnModel The column index in the model.
+ * @return The value that should be displayed in the cell.
+ */
+ protected Object getValue(JTable table, Object value, boolean isSelected, boolean hasFocus, int rowModel, int columnModel) {
+ return value;
+ }
+
+ /** Gets the background color of a cell.
+ * @param table The JTable.
+ * @param value The value in the cell.
+ * @param isSelected true if cell is selected.
+ * @param hasFocus true if cell has the focus.
+ * @param rowModel The row index in the model.
+ * @param columnModel The column index in the model.
+ * @return The background color of the cell. The default implementation returns the JTable default color.
+ */
+ protected Color getBackground(JTable table, Object value, boolean isSelected, boolean hasFocus, int rowModel, int columnModel) {
+ return isSelected ? table.getSelectionBackground() : table.getBackground();
+ }
+
+ /** Gets the foreground color of a cell.
+ * @param table The JTable.
+ * @param value The value in the cell.
+ * @param isSelected true if cell is selected.
+ * @param hasFocus true if cell has the focus.
+ * @param rowModel The row index in the model.
+ * @param columnModel The column index in the model.
+ * @return The foreground color of the cell. The default implementation returns the JTable default color.
+ */
+ protected Color getForeground(JTable table, Object value, boolean isSelected, boolean hasFocus, int rowModel, int columnModel) {
+ return isSelected ? table.getSelectionForeground() : table.getForeground();
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/table/JTable.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/JTable.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/table/JTable.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/JTable.java
index 6c4a1ed..0d3bd02 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/table/JTable.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/JTable.java
@@ -1,50 +1,50 @@
-package com.fathzer.soft.ajlib.swing.table;
-
-import javax.swing.ListSelectionModel;
-import javax.swing.table.TableModel;
-
-/** A JTable that fixes the following bugs in the JTable and adds some functionalities.
- *
Bugs fixed:
- * - Unlike the original swing JTable class, the row height is set accordingly to the font (see setRowHeigth() method).
- *
The method setRowHeight is called in the constructor. You should call it again when changing the font.
- *
- */
-@SuppressWarnings("serial")
-public class JTable extends javax.swing.JTable {
- public JTable() {
- super();
- setRowHeight();
- }
-
- public JTable(TableModel tableModel) {
- super(tableModel);
- setRowHeight();
- }
-
- /** Sets the row height according to the font size.
- *
The row height is set to getFont().getSize()*4/3.
- */
- public void setRowHeight() {
- setRowHeight(getFont().getSize()*4/3);
- }
-
- /** Sets the selection.
- * @param selectedIndexes The indexes to select.
Please note that specifying non contiguous selection on a table that
- * uses SINGLE_SELECTION mode may have unpredictable result.
- * @throws IllegalArgumentException if an index is out of bounds.
- */
- public void setSelectedIndexes(int[] selectedIndexes) {
- for (int i = 0; i < selectedIndexes.length; i++) {
- if ((selectedIndexes[i]<0) || (selectedIndexes[i]>=getRowCount())) {
- throw new IllegalArgumentException();
- }
- }
- ListSelectionModel selectionModel = getSelectionModel();
- selectionModel.setValueIsAdjusting(true);
- selectionModel.clearSelection();
- for (int i = 0; i < selectedIndexes.length; i++) {
- selectionModel.addSelectionInterval(selectedIndexes[i], selectedIndexes[i]);
- }
- selectionModel.setValueIsAdjusting(false);
- }
-}
+package com.fathzer.soft.ajlib.swing.table;
+
+import javax.swing.ListSelectionModel;
+import javax.swing.table.TableModel;
+
+/** A JTable that fixes the following bugs in the JTable and adds some functionalities.
+ *
Bugs fixed:
+ * - Unlike the original swing JTable class, the row height is set accordingly to the font (see setRowHeigth() method).
+ *
The method setRowHeight is called in the constructor. You should call it again when changing the font.
+ *
+ */
+@SuppressWarnings("serial")
+public class JTable extends javax.swing.JTable {
+ public JTable() {
+ super();
+ setRowHeight();
+ }
+
+ public JTable(TableModel tableModel) {
+ super(tableModel);
+ setRowHeight();
+ }
+
+ /** Sets the row height according to the font size.
+ *
The row height is set to getFont().getSize()*4/3.
+ */
+ public void setRowHeight() {
+ setRowHeight(getFont().getSize()*4/3);
+ }
+
+ /** Sets the selection.
+ * @param selectedIndexes The indexes to select.
Please note that specifying non contiguous selection on a table that
+ * uses SINGLE_SELECTION mode may have unpredictable result.
+ * @throws IllegalArgumentException if an index is out of bounds.
+ */
+ public void setSelectedIndexes(int[] selectedIndexes) {
+ for (int i = 0; i < selectedIndexes.length; i++) {
+ if ((selectedIndexes[i]<0) || (selectedIndexes[i]>=getRowCount())) {
+ throw new IllegalArgumentException();
+ }
+ }
+ ListSelectionModel selectionModel = getSelectionModel();
+ selectionModel.setValueIsAdjusting(true);
+ selectionModel.clearSelection();
+ for (int i = 0; i < selectedIndexes.length; i++) {
+ selectionModel.addSelectionInterval(selectedIndexes[i], selectedIndexes[i]);
+ }
+ selectionModel.setValueIsAdjusting(false);
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/table/JTableListener.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/JTableListener.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/table/JTableListener.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/JTableListener.java
index 4f3cd94..edd8c47 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/table/JTableListener.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/JTableListener.java
@@ -1,98 +1,98 @@
-package com.fathzer.soft.ajlib.swing.table;
-
-import java.awt.Point;
-import java.awt.event.ActionEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-
-import javax.swing.Action;
-import javax.swing.JMenuItem;
-import javax.swing.JPopupMenu;
-import javax.swing.JTable;
-
-/** This is a standard JTable mouse listener.
- *
It has action attributes (typically new/edit/delete/duplicate row)
- *
When a double click occurs on the JTable, a default action is invoked (typically an edit action).
- *
A pop-up menu is shown when needed (when a right click occurs under windows).
- *
You should register this with a JTable in order to receive interesting events (using JTable.addMouseListener).
- *
Please note that this class doesn't guarantee that actions will be enabled/disabled when rows are selected/deselected.
- */
-public class JTableListener extends MouseAdapter {
- private Action[] actions;
- private Action defaultAction;
-
- /** Constructor.
- * @param actions The actions that will appear in the popupMenu. Insert a null in this array to have a separator in the pop-up menu.
- * If actions is null or contains no item, no pop-up menu is shown.
- * @param defaultAction The default action which will be invoked when a double click occurs. This action is not necessarily one of the actions array.
- * If defaultAction is null, nothing occurs on a double click.
- */
- public JTableListener(Action[] actions, Action defaultAction) {
- super();
- this.actions = actions==null ? null : actions.clone();
- this.defaultAction = defaultAction;
- }
-
- @Override
- public void mouseReleased(MouseEvent e) {
- maybeShowPopup(e);
- }
-
- @Override
- public void mousePressed(MouseEvent e) {
- JTable jTable = (JTable) e.getComponent();
- if ((e.getClickCount() == 2) && (e.getButton() == MouseEvent.BUTTON1)) {
- Point p = e.getPoint();
- int row = jTable.rowAtPoint(p);
- if (row >= 0) {
- Action action = getDoubleClickAction();
- if (action != null) {
- action.actionPerformed(new ActionEvent(e.getSource(), e.getID(), ""));
- }
- }
- } else {
- maybeShowPopup(e);
- }
- }
-
- /** When a double click occurs, the action returned by this method is invoked.
- * This implementation returns the defaultButton.
- * You can override this method in order to change this action, for instance if the JTable has a mode switch that
- * trigger another action when it is set.
- * @return The action to invoke.
- */
- protected Action getDoubleClickAction() {
- return defaultAction;
- }
-
- private void maybeShowPopup(MouseEvent e) {
- JTable jTable = (JTable) e.getComponent();
- if (e.isPopupTrigger()) {
- Point p = e.getPoint();
- int row = jTable.rowAtPoint(p);
- if (!jTable.isRowSelected(row)) {
- jTable.getSelectionModel().setSelectionInterval(row, row);
- }
- if ((actions!=null) && (actions.length>0)) {
- JPopupMenu popup = new JPopupMenu();
- fillPopUp(popup);
- popup.show(e.getComponent(), e.getX(), e.getY());
- }
- }
- }
-
- /** Fill the popup menu.
- * This implementation put all the actions in the popup. You may override it in order to add
- * more actions ... or less.
- * @param popup the pop up to be filled.
- */
- protected void fillPopUp(JPopupMenu popup) {
- for (int i = 0; i < actions.length; i++) {
- if (actions[i]==null) {
- popup.addSeparator();
- } else {
- popup.add(new JMenuItem(actions[i]));
- }
- }
- }
-}
+package com.fathzer.soft.ajlib.swing.table;
+
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import javax.swing.Action;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.JTable;
+
+/** This is a standard JTable mouse listener.
+ *
It has action attributes (typically new/edit/delete/duplicate row)
+ *
When a double click occurs on the JTable, a default action is invoked (typically an edit action).
+ *
A pop-up menu is shown when needed (when a right click occurs under windows).
+ *
You should register this with a JTable in order to receive interesting events (using JTable.addMouseListener).
+ *
Please note that this class doesn't guarantee that actions will be enabled/disabled when rows are selected/deselected.
+ */
+public class JTableListener extends MouseAdapter {
+ private Action[] actions;
+ private Action defaultAction;
+
+ /** Constructor.
+ * @param actions The actions that will appear in the popupMenu. Insert a null in this array to have a separator in the pop-up menu.
+ * If actions is null or contains no item, no pop-up menu is shown.
+ * @param defaultAction The default action which will be invoked when a double click occurs. This action is not necessarily one of the actions array.
+ * If defaultAction is null, nothing occurs on a double click.
+ */
+ public JTableListener(Action[] actions, Action defaultAction) {
+ super();
+ this.actions = actions==null ? null : actions.clone();
+ this.defaultAction = defaultAction;
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ maybeShowPopup(e);
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ JTable jTable = (JTable) e.getComponent();
+ if ((e.getClickCount() == 2) && (e.getButton() == MouseEvent.BUTTON1)) {
+ Point p = e.getPoint();
+ int row = jTable.rowAtPoint(p);
+ if (row >= 0) {
+ Action action = getDoubleClickAction();
+ if (action != null) {
+ action.actionPerformed(new ActionEvent(e.getSource(), e.getID(), ""));
+ }
+ }
+ } else {
+ maybeShowPopup(e);
+ }
+ }
+
+ /** When a double click occurs, the action returned by this method is invoked.
+ * This implementation returns the defaultButton.
+ * You can override this method in order to change this action, for instance if the JTable has a mode switch that
+ * trigger another action when it is set.
+ * @return The action to invoke.
+ */
+ protected Action getDoubleClickAction() {
+ return defaultAction;
+ }
+
+ private void maybeShowPopup(MouseEvent e) {
+ JTable jTable = (JTable) e.getComponent();
+ if (e.isPopupTrigger()) {
+ Point p = e.getPoint();
+ int row = jTable.rowAtPoint(p);
+ if (!jTable.isRowSelected(row)) {
+ jTable.getSelectionModel().setSelectionInterval(row, row);
+ }
+ if ((actions!=null) && (actions.length>0)) {
+ JPopupMenu popup = new JPopupMenu();
+ fillPopUp(popup);
+ popup.show(e.getComponent(), e.getX(), e.getY());
+ }
+ }
+ }
+
+ /** Fill the popup menu.
+ * This implementation put all the actions in the popup. You may override it in order to add
+ * more actions ... or less.
+ * @param popup the pop up to be filled.
+ */
+ protected void fillPopUp(JPopupMenu popup) {
+ for (int i = 0; i < actions.length; i++) {
+ if (actions[i]==null) {
+ popup.addSeparator();
+ } else {
+ popup.add(new JMenuItem(actions[i]));
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/table/JTableSelector.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/JTableSelector.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/table/JTableSelector.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/JTableSelector.java
index ad8c3ea..4c83812 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/table/JTableSelector.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/JTableSelector.java
@@ -1,49 +1,49 @@
-package com.fathzer.soft.ajlib.swing.table;
-
-import javax.swing.JTable;
-
-/** A class that is able to set the selection of elements in a JTable.
- *
This could be seen very easy, but, unfortunately, there's some pitfalls:
- * You have to set "value is adjusting" to false before start selecting elements,
- * be aware of view/model index and don't forget to scroll the table to make the selection visible.
- *
This class takes care of this for you.
- * @param The class of the elements in the table.
- */
-public abstract class JTableSelector {
- /** The JTable that contains the selected elements.*/
- protected JTable table;
-
- /** Constructor
- * @param table The JTable that contains the selected transactions.
- */
- protected JTableSelector(JTable table) {
- this.table = table;
- }
-
- /** Selects some elements.
- * @param elements The elements to select. If some elements do not exist in the table, they are ignored.
- */
- public void setSelected(T[] elements) {
- table.getSelectionModel().setValueIsAdjusting(true);
- table.getSelectionModel().clearSelection();
- int firstViewRow = -1;
- for (int i = 0; i < elements.length; i++) {
- int row = getModelIndex(elements[i]);
- if (row>=0) {
- row = table.convertRowIndexToView(row);
- if ((firstViewRow<0) || (firstViewRow>row)) {
- firstViewRow = row;
- }
- table.getSelectionModel().addSelectionInterval(row, row);
- }
- }
- table.getSelectionModel().setValueIsAdjusting(false);
- table.scrollRectToVisible(table.getCellRect(firstViewRow, 0, true));
- }
-
- /** Gets the model index of an element.
- * @param element an element
- * @return the index of the element in the table model (a negative number is the element is not in the table).
- */
- protected abstract int getModelIndex(T element);
+package com.fathzer.soft.ajlib.swing.table;
+
+import javax.swing.JTable;
+
+/** A class that is able to set the selection of elements in a JTable.
+ *
This could be seen very easy, but, unfortunately, there's some pitfalls:
+ * You have to set "value is adjusting" to false before start selecting elements,
+ * be aware of view/model index and don't forget to scroll the table to make the selection visible.
+ *
This class takes care of this for you.
+ * @param The class of the elements in the table.
+ */
+public abstract class JTableSelector {
+ /** The JTable that contains the selected elements.*/
+ protected JTable table;
+
+ /** Constructor
+ * @param table The JTable that contains the selected transactions.
+ */
+ protected JTableSelector(JTable table) {
+ this.table = table;
+ }
+
+ /** Selects some elements.
+ * @param elements The elements to select. If some elements do not exist in the table, they are ignored.
+ */
+ public void setSelected(T[] elements) {
+ table.getSelectionModel().setValueIsAdjusting(true);
+ table.getSelectionModel().clearSelection();
+ int firstViewRow = -1;
+ for (int i = 0; i < elements.length; i++) {
+ int row = getModelIndex(elements[i]);
+ if (row>=0) {
+ row = table.convertRowIndexToView(row);
+ if ((firstViewRow<0) || (firstViewRow>row)) {
+ firstViewRow = row;
+ }
+ table.getSelectionModel().addSelectionInterval(row, row);
+ }
+ }
+ table.getSelectionModel().setValueIsAdjusting(false);
+ table.scrollRectToVisible(table.getCellRect(firstViewRow, 0, true));
+ }
+
+ /** Gets the model index of an element.
+ * @param element an element
+ * @return the index of the element in the table model (a negative number is the element is not in the table).
+ */
+ protected abstract int getModelIndex(T element);
}
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/table/NimbusPatchBooleanTableCellRenderer.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/NimbusPatchBooleanTableCellRenderer.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/table/NimbusPatchBooleanTableCellRenderer.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/NimbusPatchBooleanTableCellRenderer.java
index 23819c4..87a49a6 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/table/NimbusPatchBooleanTableCellRenderer.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/NimbusPatchBooleanTableCellRenderer.java
@@ -1,48 +1,48 @@
-package com.fathzer.soft.ajlib.swing.table;
-
-import java.awt.Color;
-import java.awt.Component;
-
-import javax.swing.JCheckBox;
-import javax.swing.JTable;
-import javax.swing.SwingConstants;
-import javax.swing.table.DefaultTableCellRenderer;
-
-/** This class is a workaround for a very weird bug in Swing and Nimbus L&F :
- *
Default boolean renderer is broken. Its background desperately remains blank instead of using the alternate Nimbus background.
- * @see bug id 6723524
- */
-public class NimbusPatchBooleanTableCellRenderer extends DefaultTableCellRenderer {
- private static final long serialVersionUID = 1L;
-
- private JCheckBox renderer;
-
- /** Constructor.
- */
- public NimbusPatchBooleanTableCellRenderer() {
- renderer = new JCheckBox();
- renderer.setHorizontalAlignment(SwingConstants.CENTER);
- }
-
- @Override
- public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
- Boolean b = (Boolean) value;
- if (b != null) {
- renderer.setSelected(b);
- }
- if (isSelected) {
- renderer.setForeground(table.getSelectionForeground());
- renderer.setBackground(table.getSelectionBackground());
- } else {
- // Call super in order to have background color initialized
- super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
- Color bg = getBackground();
- renderer.setForeground(getForeground());
- // We have to create a new color object because Nimbus returns
- // a color of type DerivedColor, which behaves strange, not sure why.
- renderer.setBackground(new Color(bg.getRed(), bg.getGreen(), bg.getBlue()));
- renderer.setOpaque(true);
- }
- return renderer;
- }
-}
+package com.fathzer.soft.ajlib.swing.table;
+
+import java.awt.Color;
+import java.awt.Component;
+
+import javax.swing.JCheckBox;
+import javax.swing.JTable;
+import javax.swing.SwingConstants;
+import javax.swing.table.DefaultTableCellRenderer;
+
+/** This class is a workaround for a very weird bug in Swing and Nimbus L&F :
+ *
Default boolean renderer is broken. Its background desperately remains blank instead of using the alternate Nimbus background.
+ * @see bug id 6723524
+ */
+public class NimbusPatchBooleanTableCellRenderer extends DefaultTableCellRenderer {
+ private static final long serialVersionUID = 1L;
+
+ private JCheckBox renderer;
+
+ /** Constructor.
+ */
+ public NimbusPatchBooleanTableCellRenderer() {
+ renderer = new JCheckBox();
+ renderer.setHorizontalAlignment(SwingConstants.CENTER);
+ }
+
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+ Boolean b = (Boolean) value;
+ if (b != null) {
+ renderer.setSelected(b);
+ }
+ if (isSelected) {
+ renderer.setForeground(table.getSelectionForeground());
+ renderer.setBackground(table.getSelectionBackground());
+ } else {
+ // Call super in order to have background color initialized
+ super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+ Color bg = getBackground();
+ renderer.setForeground(getForeground());
+ // We have to create a new color object because Nimbus returns
+ // a color of type DerivedColor, which behaves strange, not sure why.
+ renderer.setBackground(new Color(bg.getRed(), bg.getGreen(), bg.getBlue()));
+ renderer.setOpaque(true);
+ }
+ return renderer;
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/table/RowHeaderRenderer.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/RowHeaderRenderer.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/table/RowHeaderRenderer.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/RowHeaderRenderer.java
index d7bc8d3..1581e65 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/table/RowHeaderRenderer.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/RowHeaderRenderer.java
@@ -1,29 +1,29 @@
-package com.fathzer.soft.ajlib.swing.table;
-
-import java.awt.Component;
-
-import javax.swing.table.DefaultTableCellRenderer;
-import javax.swing.table.TableCellRenderer;
-import javax.swing.JTable;
-
-/**
- * A table CellRenderer that renders row headers.
- */
-public class RowHeaderRenderer implements TableCellRenderer {
- private TableCellRenderer renderer;
-
- public RowHeaderRenderer() {
- renderer = new JTable().getTableHeader().getDefaultRenderer();
- }
-
- @Override
- public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
- try {
- return renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
- } catch (NullPointerException e) {
- // Bug workaround: Under some unclear circumstances (Launch Application, Menu File/New, then choose Windows look and feel, then Windows Classic,
- // then Nimbus, then, open a non empty file ... a NullPointerException occurred :-(
- return new DefaultTableCellRenderer().getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
- }
- }
-}
+package com.fathzer.soft.ajlib.swing.table;
+
+import java.awt.Component;
+
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.JTable;
+
+/**
+ * A table CellRenderer that renders row headers.
+ */
+public class RowHeaderRenderer implements TableCellRenderer {
+ private TableCellRenderer renderer;
+
+ public RowHeaderRenderer() {
+ renderer = new JTable().getTableHeader().getDefaultRenderer();
+ }
+
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
+ try {
+ return renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
+ } catch (NullPointerException e) {
+ // Bug workaround: Under some unclear circumstances (Launch Application, Menu File/New, then choose Windows look and feel, then Windows Classic,
+ // then Nimbus, then, open a non empty file ... a NullPointerException occurred :-(
+ return new DefaultTableCellRenderer().getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
+ }
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/table/RowModel.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/RowModel.java
similarity index 95%
rename from src/main/java/com/fathzer/soft/ajlib/swing/table/RowModel.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/RowModel.java
index 69fbeb2..25015dd 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/table/RowModel.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/RowModel.java
@@ -1,37 +1,37 @@
-package com.fathzer.soft.ajlib.swing.table;
-
-import javax.swing.event.TableModelEvent;
-import javax.swing.event.TableModelListener;
-import javax.swing.table.AbstractTableModel;
-
-class RowModel extends AbstractTableModel {
- private static final long serialVersionUID = 1L;
-
- private TitledRowsTableModel model;
-
- RowModel(TitledRowsTableModel model) {
- this.model = model;
- model.addTableModelListener(new TableModelListener() {
- @Override
- public void tableChanged(TableModelEvent e) {
- //FIXME Be more precise ?
- fireTableChanged(e);
- }
- });
- }
-
- @Override
- public Object getValueAt(int rowIndex, int columnIndex) {
- return model.getRowTitle(rowIndex, columnIndex);
- }
-
- @Override
- public int getRowCount() {
- return model.getRowCount();
- }
-
- @Override
- public int getColumnCount() {
- return model.getTitlesColumnCount();
- }
+package com.fathzer.soft.ajlib.swing.table;
+
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.AbstractTableModel;
+
+class RowModel extends AbstractTableModel {
+ private static final long serialVersionUID = 1L;
+
+ private TitledRowsTableModel model;
+
+ RowModel(TitledRowsTableModel model) {
+ this.model = model;
+ model.addTableModelListener(new TableModelListener() {
+ @Override
+ public void tableChanged(TableModelEvent e) {
+ //FIXME Be more precise ?
+ fireTableChanged(e);
+ }
+ });
+ }
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex) {
+ return model.getRowTitle(rowIndex, columnIndex);
+ }
+
+ @Override
+ public int getRowCount() {
+ return model.getRowCount();
+ }
+
+ @Override
+ public int getColumnCount() {
+ return model.getTitlesColumnCount();
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/table/RowSorter.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/RowSorter.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/table/RowSorter.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/RowSorter.java
index 1c37e5b..02dbdd0 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/table/RowSorter.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/RowSorter.java
@@ -1,100 +1,100 @@
-package com.fathzer.soft.ajlib.swing.table;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.swing.SortOrder;
-import javax.swing.table.TableModel;
-import javax.swing.table.TableRowSorter;
-
-/** A subclass of javax.swing.TableRowSorter that allows the user to deselect sort keys.
- *
The TableRowSorter receives user's clicks on the table header and manage the sort keys and order.
- * Unfortunately, when the user click a column, the row sorter toggle the sort order (ascending/descending),
- * but provides no way to deselect the sort key.
- *
This class makes a cycle between ASCENDING, DESCENDING and UNSORTED when the user clicks a column header.
- *
Using this class is simple as:
- *
- * JTable table;
- * ...
- * table.setRowSorter<TableModel>(new RowSorter(table.getModel()))
- *
- * @param The type of the table model
- */
-public class RowSorter extends TableRowSorter {
- private List toggleSequence;
-
- /** Constructor.
- */
- public RowSorter() {
- super();
- this.toggleSequence = Arrays.asList(SortOrder.values());
- }
-
- /** Constructor.
- * @param model The table's model.
- */
- public RowSorter(M model) {
- super(model);
- this.toggleSequence = Arrays.asList(SortOrder.values());
- }
-
- /* (non-Javadoc)
- * @see javax.swing.DefaultRowSorter#toggleSortOrder(int)
- */
- @Override
- public void toggleSortOrder(int column) {
- if (!isSortable(column)) {
- return;
- }
- List extends SortKey> sortKeys = getSortKeys();
- ArrayList futureKeys = new ArrayList<>();
- SortKey theKey = null;
- for (SortKey sortKey : sortKeys) {
- if (sortKey.getColumn()==column) {
- int index = toggleSequence.indexOf(sortKey.getSortOrder());
- if ((index<0) || (index==toggleSequence.size()-1)) {
- index = 0;
- } else {
- index++;
- }
- theKey = new SortKey(column, toggleSequence.get(index));
- } else {
- futureKeys.add(sortKey);
- }
- }
- if (theKey == null) {
- theKey = new SortKey(column, toggleSequence.get(0));
- }
- if (!theKey.getSortOrder().equals(SortOrder.UNSORTED)) {
- futureKeys.add(0, theKey);
- } else {
- // One might be tempted to remove the key from the sort key list, it
- // would not be a good idea
- // If the UNSORTED is not at the end of the toggleSequence, it would
- // broke the sequence
- // Example: ASCENDING, UNSORTED, DESCENDING would leave DESCENDING
- // unreachable
- // Instead of removing the key, we will put it to the lowest
- // priority.
- futureKeys.add(theKey);
- }
- super.setSortKeys(futureKeys);
- }
-
- /** Sets the toggle sequence.
- *
By default, the sequence is ASCENDING, DESCENDING and UNSORTED
- * @param sequence the toggle sequence, a non empty list of SortOrder. Null to restore the default order.
- * Please note that if a SorterOrder occurs twice in the list, the behavior of this class is unpredictable.
- * @throws IllegalArgumentException if the sequence is empty
- */
- public void setToggleSequence(List sequence) {
- if (sequence==null) {
- this.toggleSequence = Arrays.asList(SortOrder.values());
- } else if (sequence.isEmpty()) {
- throw new IllegalArgumentException("toggle sequence can't be empty");
- } else {
- this.toggleSequence = sequence;
- }
- }
-}
+package com.fathzer.soft.ajlib.swing.table;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.swing.SortOrder;
+import javax.swing.table.TableModel;
+import javax.swing.table.TableRowSorter;
+
+/** A subclass of javax.swing.TableRowSorter that allows the user to deselect sort keys.
+ *
The TableRowSorter receives user's clicks on the table header and manage the sort keys and order.
+ * Unfortunately, when the user click a column, the row sorter toggle the sort order (ascending/descending),
+ * but provides no way to deselect the sort key.
+ *
This class makes a cycle between ASCENDING, DESCENDING and UNSORTED when the user clicks a column header.
+ *
Using this class is simple as:
+ *
+ * JTable table;
+ * ...
+ * table.setRowSorter<TableModel>(new RowSorter(table.getModel()))
+ *
+ * @param The type of the table model
+ */
+public class RowSorter extends TableRowSorter {
+ private List toggleSequence;
+
+ /** Constructor.
+ */
+ public RowSorter() {
+ super();
+ this.toggleSequence = Arrays.asList(SortOrder.values());
+ }
+
+ /** Constructor.
+ * @param model The table's model.
+ */
+ public RowSorter(M model) {
+ super(model);
+ this.toggleSequence = Arrays.asList(SortOrder.values());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.DefaultRowSorter#toggleSortOrder(int)
+ */
+ @Override
+ public void toggleSortOrder(int column) {
+ if (!isSortable(column)) {
+ return;
+ }
+ List extends SortKey> sortKeys = getSortKeys();
+ ArrayList futureKeys = new ArrayList<>();
+ SortKey theKey = null;
+ for (SortKey sortKey : sortKeys) {
+ if (sortKey.getColumn()==column) {
+ int index = toggleSequence.indexOf(sortKey.getSortOrder());
+ if ((index<0) || (index==toggleSequence.size()-1)) {
+ index = 0;
+ } else {
+ index++;
+ }
+ theKey = new SortKey(column, toggleSequence.get(index));
+ } else {
+ futureKeys.add(sortKey);
+ }
+ }
+ if (theKey == null) {
+ theKey = new SortKey(column, toggleSequence.get(0));
+ }
+ if (!theKey.getSortOrder().equals(SortOrder.UNSORTED)) {
+ futureKeys.add(0, theKey);
+ } else {
+ // One might be tempted to remove the key from the sort key list, it
+ // would not be a good idea
+ // If the UNSORTED is not at the end of the toggleSequence, it would
+ // broke the sequence
+ // Example: ASCENDING, UNSORTED, DESCENDING would leave DESCENDING
+ // unreachable
+ // Instead of removing the key, we will put it to the lowest
+ // priority.
+ futureKeys.add(theKey);
+ }
+ super.setSortKeys(futureKeys);
+ }
+
+ /** Sets the toggle sequence.
+ *
By default, the sequence is ASCENDING, DESCENDING and UNSORTED
+ * @param sequence the toggle sequence, a non empty list of SortOrder. Null to restore the default order.
+ * Please note that if a SorterOrder occurs twice in the list, the behavior of this class is unpredictable.
+ * @throws IllegalArgumentException if the sequence is empty
+ */
+ public void setToggleSequence(List sequence) {
+ if (sequence==null) {
+ this.toggleSequence = Arrays.asList(SortOrder.values());
+ } else if (sequence.isEmpty()) {
+ throw new IllegalArgumentException("toggle sequence can't be empty");
+ } else {
+ this.toggleSequence = sequence;
+ }
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/table/Table.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/Table.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/table/Table.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/Table.java
index ac2a9d2..d379992 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/table/Table.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/Table.java
@@ -1,187 +1,187 @@
-package com.fathzer.soft.ajlib.swing.table;
-
-import javax.swing.JPanel;
-
-import java.awt.Dimension;
-import javax.swing.JScrollPane;
-
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.TableColumnModelEvent;
-import javax.swing.event.TableColumnModelListener;
-import javax.swing.table.TableModel;
-
-import com.fathzer.soft.ajlib.swing.Utils;
-
-import java.awt.BorderLayout;
-
-/**
- * JTable has a lot of lacks, this class adds the ability for a table to have
- * row titles.
- */
-public class Table extends JPanel {
- private static final long serialVersionUID = 1L;
-
- private JScrollPane scrollPane;
- private JTable table;
- private JTable rowView;
-
- /**
- * Constructor.
- */
- public Table() {
- initialize();
- }
-
- private void initialize() {
- setLayout(new BorderLayout(0, 0));
- add(getScrollPane());
- }
-
- private JScrollPane getScrollPane() {
- if (scrollPane == null) {
- scrollPane = new JScrollPane();
- scrollPane.setRowHeaderView(getRowJTable());
- scrollPane.setViewportView(getJTable());
- }
- return scrollPane;
- }
-
- /**
- * Gets the internal table that is used to display table rows.
- * You can override this method in order to create a customized row table.
- *
- * @return a JTable
- */
- public final JTable getRowJTable() {
- if (rowView == null) {
- rowView = new JTable();
- rowView.setDefaultRenderer(Object.class, new RowHeaderRenderer());
- rowView.setFocusable(false);
- rowView.setCellSelectionEnabled(false);
- setRowViewSize(rowView);
- }
- return rowView;
- }
-
- private void setRowViewSize(final JTable rowView) {
- int width = 0;
- for (int i = 0; i < rowView.getColumnCount(); i++) {
- width += Utils.packColumn(rowView, i, 2);
- }
- Dimension d = rowView.getPreferredScrollableViewportSize();
- d.width = width;
- rowView.setPreferredScrollableViewportSize(d);
- }
-
- /**
- * Gets the internal JTable.
- *
- * @return a JTable
- * @see #buildJTable()
- */
- public final JTable getJTable() {
- if (table == null) {
- table = buildJTable();
- if (table.getModel() instanceof TitledRowsTableModel) {
- installModelInRowJTable((TitledRowsTableModel) table.getModel());
- }
- }
- return table;
- }
-
- /**
- * Builds the internal JTable.
- * This table doesn't not contains the row titles.
- * This method is called once and creates the internal JTable.
- * It is useful to customize the table (for example to change its
- * CellRenderer).
- * So, you can override this method in order to create a customized table.
- *
- * @return a JTable
- */
- protected JTable buildJTable() {
- return new JTable();
- }
-
- /**
- * Sets the table model.
- * Please note that you should not modify directly the model of the internal
- * JTable. It would results in having the row titles not updated.
- *
- * @param model
- * The model. If this model implements TitledRowsTableModel, the
- * table will have row titles.
- * @see TitledRowsTableModel
- */
- public void setModel(TableModel model) {
- table.setModel(model);
- if (model instanceof TitledRowsTableModel) {
- installModelInRowJTable((TitledRowsTableModel) model);
- }
- }
-
- private void installModelInRowJTable(TitledRowsTableModel model) {
- final TableModel rowHeaderModel = new RowModel(model);
- getRowJTable().setModel(rowHeaderModel);
- getRowJTable().getColumnModel().addColumnModelListener(
- new TableColumnModelListener() {
-
- @Override
- public void columnSelectionChanged(ListSelectionEvent e) {
- // Nothing to do
- }
-
- @Override
- public void columnRemoved(TableColumnModelEvent e) {
- setRowViewSize(getRowJTable());
- }
-
- @Override
- public void columnMoved(TableColumnModelEvent e) {
- // Nothing to do
- }
-
- @Override
- public void columnMarginChanged(ChangeEvent e) {
- // Nothing to do
- }
-
- @Override
- public void columnAdded(TableColumnModelEvent e) {
- setRowViewSize(getRowJTable());
- }
- });
- setRowViewSize(getRowJTable());
- }
-
- /**
- * Gets the table model.
- *
- * @return a TableModel
- */
- public TableModel getModel() {
- return this.getJTable().getModel();
- }
-
- /**
- * Gets the default row height of this table.
- *
- * @return an integer.
- */
- public int getRowHeight() {
- return this.getJTable().getRowHeight();
- }
-
- /**
- * Sets the default row height of this table.
- * This method sets the row height of the main table and its title table.
- *
- * @param rowHeight
- * The new row height
- */
- public void setRowHeight(int rowHeight) {
- this.getJTable().setRowHeight(rowHeight);
- this.getRowJTable().setRowHeight(rowHeight);
- }
+package com.fathzer.soft.ajlib.swing.table;
+
+import javax.swing.JPanel;
+
+import java.awt.Dimension;
+import javax.swing.JScrollPane;
+
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.TableColumnModelEvent;
+import javax.swing.event.TableColumnModelListener;
+import javax.swing.table.TableModel;
+
+import com.fathzer.soft.ajlib.swing.Utils;
+
+import java.awt.BorderLayout;
+
+/**
+ * JTable has a lot of lacks, this class adds the ability for a table to have
+ * row titles.
+ */
+public class Table extends JPanel {
+ private static final long serialVersionUID = 1L;
+
+ private JScrollPane scrollPane;
+ private JTable table;
+ private JTable rowView;
+
+ /**
+ * Constructor.
+ */
+ public Table() {
+ initialize();
+ }
+
+ private void initialize() {
+ setLayout(new BorderLayout(0, 0));
+ add(getScrollPane());
+ }
+
+ private JScrollPane getScrollPane() {
+ if (scrollPane == null) {
+ scrollPane = new JScrollPane();
+ scrollPane.setRowHeaderView(getRowJTable());
+ scrollPane.setViewportView(getJTable());
+ }
+ return scrollPane;
+ }
+
+ /**
+ * Gets the internal table that is used to display table rows.
+ * You can override this method in order to create a customized row table.
+ *
+ * @return a JTable
+ */
+ public final JTable getRowJTable() {
+ if (rowView == null) {
+ rowView = new JTable();
+ rowView.setDefaultRenderer(Object.class, new RowHeaderRenderer());
+ rowView.setFocusable(false);
+ rowView.setCellSelectionEnabled(false);
+ setRowViewSize(rowView);
+ }
+ return rowView;
+ }
+
+ private void setRowViewSize(final JTable rowView) {
+ int width = 0;
+ for (int i = 0; i < rowView.getColumnCount(); i++) {
+ width += Utils.packColumn(rowView, i, 2);
+ }
+ Dimension d = rowView.getPreferredScrollableViewportSize();
+ d.width = width;
+ rowView.setPreferredScrollableViewportSize(d);
+ }
+
+ /**
+ * Gets the internal JTable.
+ *
+ * @return a JTable
+ * @see #buildJTable()
+ */
+ public final JTable getJTable() {
+ if (table == null) {
+ table = buildJTable();
+ if (table.getModel() instanceof TitledRowsTableModel) {
+ installModelInRowJTable((TitledRowsTableModel) table.getModel());
+ }
+ }
+ return table;
+ }
+
+ /**
+ * Builds the internal JTable.
+ * This table doesn't not contains the row titles.
+ * This method is called once and creates the internal JTable.
+ * It is useful to customize the table (for example to change its
+ * CellRenderer).
+ * So, you can override this method in order to create a customized table.
+ *
+ * @return a JTable
+ */
+ protected JTable buildJTable() {
+ return new JTable();
+ }
+
+ /**
+ * Sets the table model.
+ * Please note that you should not modify directly the model of the internal
+ * JTable. It would results in having the row titles not updated.
+ *
+ * @param model
+ * The model. If this model implements TitledRowsTableModel, the
+ * table will have row titles.
+ * @see TitledRowsTableModel
+ */
+ public void setModel(TableModel model) {
+ table.setModel(model);
+ if (model instanceof TitledRowsTableModel) {
+ installModelInRowJTable((TitledRowsTableModel) model);
+ }
+ }
+
+ private void installModelInRowJTable(TitledRowsTableModel model) {
+ final TableModel rowHeaderModel = new RowModel(model);
+ getRowJTable().setModel(rowHeaderModel);
+ getRowJTable().getColumnModel().addColumnModelListener(
+ new TableColumnModelListener() {
+
+ @Override
+ public void columnSelectionChanged(ListSelectionEvent e) {
+ // Nothing to do
+ }
+
+ @Override
+ public void columnRemoved(TableColumnModelEvent e) {
+ setRowViewSize(getRowJTable());
+ }
+
+ @Override
+ public void columnMoved(TableColumnModelEvent e) {
+ // Nothing to do
+ }
+
+ @Override
+ public void columnMarginChanged(ChangeEvent e) {
+ // Nothing to do
+ }
+
+ @Override
+ public void columnAdded(TableColumnModelEvent e) {
+ setRowViewSize(getRowJTable());
+ }
+ });
+ setRowViewSize(getRowJTable());
+ }
+
+ /**
+ * Gets the table model.
+ *
+ * @return a TableModel
+ */
+ public TableModel getModel() {
+ return this.getJTable().getModel();
+ }
+
+ /**
+ * Gets the default row height of this table.
+ *
+ * @return an integer.
+ */
+ public int getRowHeight() {
+ return this.getJTable().getRowHeight();
+ }
+
+ /**
+ * Sets the default row height of this table.
+ * This method sets the row height of the main table and its title table.
+ *
+ * @param rowHeight
+ * The new row height
+ */
+ public void setRowHeight(int rowHeight) {
+ this.getJTable().setRowHeight(rowHeight);
+ this.getRowJTable().setRowHeight(rowHeight);
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/table/TitledRowsTableModel.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/TitledRowsTableModel.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/table/TitledRowsTableModel.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/TitledRowsTableModel.java
index a6d831e..702b360 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/table/TitledRowsTableModel.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/TitledRowsTableModel.java
@@ -1,20 +1,20 @@
-package com.fathzer.soft.ajlib.swing.table;
-
-import javax.swing.table.TableModel;
-
-/** A TableModel that defines titles for its rows.
- *
This kind of model can be used with Table that automatically display titles when its model implements this interface.
- */
-public interface TitledRowsTableModel extends TableModel {
- /** Gets the number of columns dedicated to the row titles.
- * @return an positive integer
- */
- public int getTitlesColumnCount();
-
- /** Gets a row title.
- * @param rowIndex The index of the row
- * @param columnIndex The index of the title column
- * @return the title of the row
- */
- public String getRowTitle(int rowIndex, int columnIndex);
+package com.fathzer.soft.ajlib.swing.table;
+
+import javax.swing.table.TableModel;
+
+/** A TableModel that defines titles for its rows.
+ *
This kind of model can be used with Table that automatically display titles when its model implements this interface.
+ */
+public interface TitledRowsTableModel extends TableModel {
+ /** Gets the number of columns dedicated to the row titles.
+ * @return an positive integer
+ */
+ public int getTitlesColumnCount();
+
+ /** Gets a row title.
+ * @param rowIndex The index of the row
+ * @param columnIndex The index of the title column
+ * @return the title of the row
+ */
+ public String getRowTitle(int rowIndex, int columnIndex);
}
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/table/package-info.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/package-info.java
similarity index 98%
rename from src/main/java/com/fathzer/soft/ajlib/swing/table/package-info.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/package-info.java
index 636303f..5df2689 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/table/package-info.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/table/package-info.java
@@ -1,2 +1,2 @@
-/** Table utilities*/
+/** Table utilities*/
package com.fathzer.soft.ajlib.swing.table;
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractFileSelector.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractFileSelector.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractFileSelector.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractFileSelector.java
index a94de96..4e31163 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractFileSelector.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractFileSelector.java
@@ -1,297 +1,297 @@
-package com.fathzer.soft.ajlib.swing.widget;
-
-import javax.swing.JFileChooser;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-
-import java.awt.GridBagLayout;
-
-import javax.swing.JButton;
-
-import java.awt.GridBagConstraints;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.File;
-
-import javax.swing.ImageIcon;
-
-import com.fathzer.soft.ajlib.swing.Utils;
-import com.fathzer.soft.ajlib.swing.dialog.FileChooser;
-import com.fathzer.soft.ajlib.swing.framework.Application;
-import com.fathzer.soft.ajlib.utilities.NullUtils;
-
-/** An abstract widget composed of four buttons to open, save, save as and create new file.
- */
-public abstract class AbstractFileSelector extends JPanel {
- private static final long serialVersionUID = 1L;
- /** A property bind with the file selected in this panel.*/
- public static final String SELECTED_FILE_PROPERTY = "SELECTED_FILE";
- /** A property bind with the changes of the data managed by this panel.*/
- public static final String CHANGED_PROPERTY = "CHANGED";
- /** A property bind with the emptiness the data managed by this panel.*/
- public static final String EMPTY_PROPERTY = "EMPTY";
-
- private JButton btnOpen;
- private JButton btnNew;
- private JButton btnSave;
- private JButton btnSaveAs;
-
- private File file;
- private boolean isChanged;
-
- /**
- * Creates the panel.
- */
- protected AbstractFileSelector() {
- initialize();
- this.isChanged = false;
- }
- private void initialize() {
- GridBagLayout gridBagLayout = new GridBagLayout();
- setLayout(gridBagLayout);
- GridBagConstraints gbcBtnOpen = new GridBagConstraints();
- gbcBtnOpen.gridx = 0;
- gbcBtnOpen.gridy = 0;
- add(getBtnOpen(), gbcBtnOpen);
- GridBagConstraints gbcBtnNew = new GridBagConstraints();
- gbcBtnNew.gridx = 1;
- gbcBtnNew.gridy = 0;
- add(getBtnNew(), gbcBtnNew);
- GridBagConstraints gbcBtnSave = new GridBagConstraints();
- gbcBtnSave.gridx = 2;
- gbcBtnSave.gridy = 0;
- add(getBtnSave(), gbcBtnSave);
- GridBagConstraints gbcBtnSaveAs = new GridBagConstraints();
- gbcBtnSaveAs.weightx = 1.0;
- gbcBtnSaveAs.anchor = GridBagConstraints.WEST;
- gbcBtnSaveAs.gridx = 3;
- gbcBtnSaveAs.gridy = 0;
- add(getBtnSaveAs(), gbcBtnSaveAs);
- }
-
- protected JButton getBtnOpen() {
- if (btnOpen == null) {
- btnOpen = new JButton(Application.getString("FileSelector.open", getLocale())); //$NON-NLS-1$
- btnOpen.setToolTipText(Application.getString("FileSelector.open.tooltip", getLocale())); //$NON-NLS-1$
- btnOpen.setIcon(new ImageIcon(AbstractFileSelector.class.getResource("Open.png"))); //$NON-NLS-1$
- btnOpen.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- if (!lastChanceToSave()) {
- return;
- }
- JFileChooser chooser = new FileChooser();
- if (getSelectedFile()!=null) {
- chooser.setCurrentDirectory(getSelectedFile().getParentFile());
- }
- File selectedFile = chooser.showOpenDialog(Utils.getOwnerWindow(btnOpen)) == JFileChooser.APPROVE_OPTION ? chooser.getSelectedFile() : null;
- if (selectedFile != null && read(selectedFile)) {
- setFile(selectedFile);
- setEmpty(false);
- }
- }
- });
- }
- return btnOpen;
- }
- protected JButton getBtnNew() {
- if (btnNew == null) {
- btnNew = new JButton(Application.getString("FileSelector.new", getLocale())); //$NON-NLS-1$
- btnNew.setIcon(new ImageIcon(AbstractFileSelector.class.getResource("New.png"))); //$NON-NLS-1$
- btnNew.setToolTipText(Application.getString("FileSelector.new.tooltip", getLocale())); //$NON-NLS-1$
- btnNew.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- if (!lastChanceToSave()) {
- return;
- }
- newFile();
- setEmpty(true);
- setFile(null);
- }
- });
- }
- return btnNew;
- }
- protected JButton getBtnSave() {
- if (btnSave == null) {
- btnSave = new JButton(Application.getString("FileSelector.save", getLocale())); //$NON-NLS-1$
- btnSave.setIcon(new ImageIcon(AbstractFileSelector.class.getResource("Save.png"))); //$NON-NLS-1$
- btnSave.setToolTipText(Application.getString("FileSelector.save.tooltip", getLocale())); //$NON-NLS-1$
- btnSave.setEnabled(false);
- btnSave.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- File selectedFile = getSelectedFile();
- if (selectedFile==null) {
- JFileChooser chooser = new FileChooser();
- selectedFile = chooser.showSaveDialog(Utils.getOwnerWindow(btnSave)) == JFileChooser.APPROVE_OPTION ? chooser.getSelectedFile() : null;
- }
- if (selectedFile != null && save(selectedFile)) {
- setFile(selectedFile);
- }
- }
- });
- }
- return btnSave;
- }
- protected JButton getBtnSaveAs() {
- if (btnSaveAs == null) {
- btnSaveAs = new JButton(Application.getString("FileSelector.saveAs", getLocale())); //$NON-NLS-1$
- btnSaveAs.setIcon(new ImageIcon(AbstractFileSelector.class.getResource("SaveAs.png"))); //$NON-NLS-1$
- btnSaveAs.setToolTipText(Application.getString("FileSelector.saveAs.tooltip", getLocale())); //$NON-NLS-1$
- btnSaveAs.setEnabled(false);
- btnSaveAs.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- JFileChooser chooser = new FileChooser();
- if (getSelectedFile()!=null) {
- chooser.setCurrentDirectory(getSelectedFile().getParentFile());
- }
- File selectedFile = chooser.showSaveDialog(Utils.getOwnerWindow(btnSave)) == JFileChooser.APPROVE_OPTION ? chooser.getSelectedFile() : null;
- if (selectedFile != null && save(selectedFile)) {
- setFile(selectedFile);
- }
- }
- });
- }
- return btnSaveAs;
- }
-
- private void updateButtons(boolean isEmpty) {
- getBtnSaveAs().setEnabled(!isEmpty);
- getBtnSave().setEnabled(!isEmpty && isChanged());
- }
-
- /** Informs this panel that the data was changed since last save.
- *
This method should be called when the data state changes.
- *
Please note that when data is successfully read, saved, or created using this panel buttons, changed state is automatically set to false.
- * @param isChanged true if dated as been modified since last call to save method.
- * @see #save(File)
- */
- public void setChanged(boolean isChanged) {
- if (isChanged!=this.isChanged) {
- boolean oldIsChanged = this.isChanged;
- this.isChanged = isChanged;
- updateButtons(isEmpty());
- firePropertyChange(CHANGED_PROPERTY, oldIsChanged, isChanged);
- }
- }
-
- /** Informs this panel that the data was changed since last save.
- *
This method should be called when the data state changes.
- *
Please note that when data is successfully read, empty state is automatically set to false.
- *
Please note that when data is successfully create, empty state is automatically set to true.
- * @param isEmpty true if data is empty.
- */
- public void setEmpty(boolean isEmpty) {
- if (isEmpty!=this.isEmpty()) {
- boolean oldIsEmpty = isEmpty();
- updateButtons(isEmpty);
- firePropertyChange(EMPTY_PROPERTY, oldIsEmpty, isEmpty);
- }
- }
-
- /** This method is called before changing the selected file.
- *
If current data is not saved yet, this method asks the user what to do (ignore, save, cancel).
- *
You can call this method if needed, for example, when the window containing this widget is closing.
- * @return true if the process can continue, false to keep everything unchanged
- */
- public boolean lastChanceToSave() {
- if (!getBtnSave().isEnabled()) {
- // If save button is enabled, there's nothing to save
- return true;
- }
- String[] options = new String[]{getBtnSave().getText(),Application.getString("GenericButton.ignore", getLocale()),
- Application.getString("GenericButton.cancel", getLocale())}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- int n = JOptionPane.showOptionDialog(Utils.getOwnerWindow(this),
- getUnsavedQuestion(),
- Application.getString("FileSelector.unsavedChanges", getLocale()), //$NON-NLS-1$
- JOptionPane.YES_NO_CANCEL_OPTION,
- JOptionPane.WARNING_MESSAGE,
- null, //do not use a custom Icon
- options, //the titles of buttons
- options[2]); //default button title
- if (n==-1 || n==2) {
- return false;
- } else if (n==0) {
- if (getSelectedFile()==null) {
- JFileChooser chooser = new FileChooser();
- File selectedFile = chooser.showSaveDialog(Utils.getOwnerWindow(this)) == JFileChooser.APPROVE_OPTION ? chooser.getSelectedFile() : null;
- if (selectedFile != null) {
- boolean ok = save(selectedFile);
- if (ok) {
- setFile(selectedFile);
- }
- return ok;
- } else {
- return false;
- }
- }
- }
- return true;
- }
-
- /** Gets the question to ask to the user when lastChanceToSave is called and data has unsaved changes.
- *
Subclasses may override this method to customize the question.
- * @return The question to ask.
- */
- protected String getUnsavedQuestion() {
- return Application.getString("FileSelector.unsavedChanges.question", getLocale()); //$NON-NLS-1$
- }
-
- /** Reads a file.
- *
This method is called when the user clicks the "open" button.
- * @param file The file to read.
- * @return true if the file was successfully read, false if the file reading failed.
- */
- protected abstract boolean read(File file);
-
- /** Creates a new empty data set.
- *
This method is called when the user clicks the "new" button.
- */
- protected abstract void newFile();
-
- /** Saves the data to a file.
- *
This method is called when the user clicks the "Save" or "Save as" buttons.
- * @param file The file where to save the data.
- * @return true if the save succeeds.
- */
- protected abstract boolean save(File file);
-
- /** Gets the current edited file.
- * @return The selected file or null if no file is selected.
- */
- public File getSelectedFile() {
- return this.file;
- }
-
- /** Sets the selected file.
- *
If current file has unmodified changes, a dialog asks the user if he wants to save the changes.
- * @param file The file to read or null to clear the data and select no file
- */
- public void setSelectedFile(File file) {
- if (!NullUtils.areEquals(this.file, file)) {
- if (!lastChanceToSave()) {
- return;
- }
- if (file == null && lastChanceToSave()) {
- newFile();
- setFile(null);
- } else if (read(file)) {
- setFile(file);
- }
- }
- }
-
- private void setFile(File file) {
- File old = this.file;
- this.file = file;
- firePropertyChange(SELECTED_FILE_PROPERTY, old, file);
- setChanged(false);
- }
-
- public boolean isEmpty() {
- return !getBtnSaveAs().isEnabled();
- }
-
- public boolean isChanged() {
- return isChanged;
- }
+package com.fathzer.soft.ajlib.swing.widget;
+
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+import java.awt.GridBagLayout;
+
+import javax.swing.JButton;
+
+import java.awt.GridBagConstraints;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+
+import javax.swing.ImageIcon;
+
+import com.fathzer.soft.ajlib.swing.Utils;
+import com.fathzer.soft.ajlib.swing.dialog.FileChooser;
+import com.fathzer.soft.ajlib.swing.framework.Application;
+import com.fathzer.soft.ajlib.utilities.NullUtils;
+
+/** An abstract widget composed of four buttons to open, save, save as and create new file.
+ */
+public abstract class AbstractFileSelector extends JPanel {
+ private static final long serialVersionUID = 1L;
+ /** A property bind with the file selected in this panel.*/
+ public static final String SELECTED_FILE_PROPERTY = "SELECTED_FILE";
+ /** A property bind with the changes of the data managed by this panel.*/
+ public static final String CHANGED_PROPERTY = "CHANGED";
+ /** A property bind with the emptiness the data managed by this panel.*/
+ public static final String EMPTY_PROPERTY = "EMPTY";
+
+ private JButton btnOpen;
+ private JButton btnNew;
+ private JButton btnSave;
+ private JButton btnSaveAs;
+
+ private File file;
+ private boolean isChanged;
+
+ /**
+ * Creates the panel.
+ */
+ protected AbstractFileSelector() {
+ initialize();
+ this.isChanged = false;
+ }
+ private void initialize() {
+ GridBagLayout gridBagLayout = new GridBagLayout();
+ setLayout(gridBagLayout);
+ GridBagConstraints gbcBtnOpen = new GridBagConstraints();
+ gbcBtnOpen.gridx = 0;
+ gbcBtnOpen.gridy = 0;
+ add(getBtnOpen(), gbcBtnOpen);
+ GridBagConstraints gbcBtnNew = new GridBagConstraints();
+ gbcBtnNew.gridx = 1;
+ gbcBtnNew.gridy = 0;
+ add(getBtnNew(), gbcBtnNew);
+ GridBagConstraints gbcBtnSave = new GridBagConstraints();
+ gbcBtnSave.gridx = 2;
+ gbcBtnSave.gridy = 0;
+ add(getBtnSave(), gbcBtnSave);
+ GridBagConstraints gbcBtnSaveAs = new GridBagConstraints();
+ gbcBtnSaveAs.weightx = 1.0;
+ gbcBtnSaveAs.anchor = GridBagConstraints.WEST;
+ gbcBtnSaveAs.gridx = 3;
+ gbcBtnSaveAs.gridy = 0;
+ add(getBtnSaveAs(), gbcBtnSaveAs);
+ }
+
+ protected JButton getBtnOpen() {
+ if (btnOpen == null) {
+ btnOpen = new JButton(Application.getString("FileSelector.open", getLocale())); //$NON-NLS-1$
+ btnOpen.setToolTipText(Application.getString("FileSelector.open.tooltip", getLocale())); //$NON-NLS-1$
+ btnOpen.setIcon(new ImageIcon(AbstractFileSelector.class.getResource("Open.png"))); //$NON-NLS-1$
+ btnOpen.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ if (!lastChanceToSave()) {
+ return;
+ }
+ JFileChooser chooser = new FileChooser();
+ if (getSelectedFile()!=null) {
+ chooser.setCurrentDirectory(getSelectedFile().getParentFile());
+ }
+ File selectedFile = chooser.showOpenDialog(Utils.getOwnerWindow(btnOpen)) == JFileChooser.APPROVE_OPTION ? chooser.getSelectedFile() : null;
+ if (selectedFile != null && read(selectedFile)) {
+ setFile(selectedFile);
+ setEmpty(false);
+ }
+ }
+ });
+ }
+ return btnOpen;
+ }
+ protected JButton getBtnNew() {
+ if (btnNew == null) {
+ btnNew = new JButton(Application.getString("FileSelector.new", getLocale())); //$NON-NLS-1$
+ btnNew.setIcon(new ImageIcon(AbstractFileSelector.class.getResource("New.png"))); //$NON-NLS-1$
+ btnNew.setToolTipText(Application.getString("FileSelector.new.tooltip", getLocale())); //$NON-NLS-1$
+ btnNew.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ if (!lastChanceToSave()) {
+ return;
+ }
+ newFile();
+ setEmpty(true);
+ setFile(null);
+ }
+ });
+ }
+ return btnNew;
+ }
+ protected JButton getBtnSave() {
+ if (btnSave == null) {
+ btnSave = new JButton(Application.getString("FileSelector.save", getLocale())); //$NON-NLS-1$
+ btnSave.setIcon(new ImageIcon(AbstractFileSelector.class.getResource("Save.png"))); //$NON-NLS-1$
+ btnSave.setToolTipText(Application.getString("FileSelector.save.tooltip", getLocale())); //$NON-NLS-1$
+ btnSave.setEnabled(false);
+ btnSave.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ File selectedFile = getSelectedFile();
+ if (selectedFile==null) {
+ JFileChooser chooser = new FileChooser();
+ selectedFile = chooser.showSaveDialog(Utils.getOwnerWindow(btnSave)) == JFileChooser.APPROVE_OPTION ? chooser.getSelectedFile() : null;
+ }
+ if (selectedFile != null && save(selectedFile)) {
+ setFile(selectedFile);
+ }
+ }
+ });
+ }
+ return btnSave;
+ }
+ protected JButton getBtnSaveAs() {
+ if (btnSaveAs == null) {
+ btnSaveAs = new JButton(Application.getString("FileSelector.saveAs", getLocale())); //$NON-NLS-1$
+ btnSaveAs.setIcon(new ImageIcon(AbstractFileSelector.class.getResource("SaveAs.png"))); //$NON-NLS-1$
+ btnSaveAs.setToolTipText(Application.getString("FileSelector.saveAs.tooltip", getLocale())); //$NON-NLS-1$
+ btnSaveAs.setEnabled(false);
+ btnSaveAs.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ JFileChooser chooser = new FileChooser();
+ if (getSelectedFile()!=null) {
+ chooser.setCurrentDirectory(getSelectedFile().getParentFile());
+ }
+ File selectedFile = chooser.showSaveDialog(Utils.getOwnerWindow(btnSave)) == JFileChooser.APPROVE_OPTION ? chooser.getSelectedFile() : null;
+ if (selectedFile != null && save(selectedFile)) {
+ setFile(selectedFile);
+ }
+ }
+ });
+ }
+ return btnSaveAs;
+ }
+
+ private void updateButtons(boolean isEmpty) {
+ getBtnSaveAs().setEnabled(!isEmpty);
+ getBtnSave().setEnabled(!isEmpty && isChanged());
+ }
+
+ /** Informs this panel that the data was changed since last save.
+ *
This method should be called when the data state changes.
+ *
Please note that when data is successfully read, saved, or created using this panel buttons, changed state is automatically set to false.
+ * @param isChanged true if dated as been modified since last call to save method.
+ * @see #save(File)
+ */
+ public void setChanged(boolean isChanged) {
+ if (isChanged!=this.isChanged) {
+ boolean oldIsChanged = this.isChanged;
+ this.isChanged = isChanged;
+ updateButtons(isEmpty());
+ firePropertyChange(CHANGED_PROPERTY, oldIsChanged, isChanged);
+ }
+ }
+
+ /** Informs this panel that the data was changed since last save.
+ *
This method should be called when the data state changes.
+ *
Please note that when data is successfully read, empty state is automatically set to false.
+ *
Please note that when data is successfully create, empty state is automatically set to true.
+ * @param isEmpty true if data is empty.
+ */
+ public void setEmpty(boolean isEmpty) {
+ if (isEmpty!=this.isEmpty()) {
+ boolean oldIsEmpty = isEmpty();
+ updateButtons(isEmpty);
+ firePropertyChange(EMPTY_PROPERTY, oldIsEmpty, isEmpty);
+ }
+ }
+
+ /** This method is called before changing the selected file.
+ *
If current data is not saved yet, this method asks the user what to do (ignore, save, cancel).
+ *
You can call this method if needed, for example, when the window containing this widget is closing.
+ * @return true if the process can continue, false to keep everything unchanged
+ */
+ public boolean lastChanceToSave() {
+ if (!getBtnSave().isEnabled()) {
+ // If save button is enabled, there's nothing to save
+ return true;
+ }
+ String[] options = new String[]{getBtnSave().getText(),Application.getString("GenericButton.ignore", getLocale()),
+ Application.getString("GenericButton.cancel", getLocale())}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ int n = JOptionPane.showOptionDialog(Utils.getOwnerWindow(this),
+ getUnsavedQuestion(),
+ Application.getString("FileSelector.unsavedChanges", getLocale()), //$NON-NLS-1$
+ JOptionPane.YES_NO_CANCEL_OPTION,
+ JOptionPane.WARNING_MESSAGE,
+ null, //do not use a custom Icon
+ options, //the titles of buttons
+ options[2]); //default button title
+ if (n==-1 || n==2) {
+ return false;
+ } else if (n==0) {
+ if (getSelectedFile()==null) {
+ JFileChooser chooser = new FileChooser();
+ File selectedFile = chooser.showSaveDialog(Utils.getOwnerWindow(this)) == JFileChooser.APPROVE_OPTION ? chooser.getSelectedFile() : null;
+ if (selectedFile != null) {
+ boolean ok = save(selectedFile);
+ if (ok) {
+ setFile(selectedFile);
+ }
+ return ok;
+ } else {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /** Gets the question to ask to the user when lastChanceToSave is called and data has unsaved changes.
+ *
Subclasses may override this method to customize the question.
+ * @return The question to ask.
+ */
+ protected String getUnsavedQuestion() {
+ return Application.getString("FileSelector.unsavedChanges.question", getLocale()); //$NON-NLS-1$
+ }
+
+ /** Reads a file.
+ *
This method is called when the user clicks the "open" button.
+ * @param file The file to read.
+ * @return true if the file was successfully read, false if the file reading failed.
+ */
+ protected abstract boolean read(File file);
+
+ /** Creates a new empty data set.
+ *
This method is called when the user clicks the "new" button.
+ */
+ protected abstract void newFile();
+
+ /** Saves the data to a file.
+ *
This method is called when the user clicks the "Save" or "Save as" buttons.
+ * @param file The file where to save the data.
+ * @return true if the save succeeds.
+ */
+ protected abstract boolean save(File file);
+
+ /** Gets the current edited file.
+ * @return The selected file or null if no file is selected.
+ */
+ public File getSelectedFile() {
+ return this.file;
+ }
+
+ /** Sets the selected file.
+ *
If current file has unmodified changes, a dialog asks the user if he wants to save the changes.
+ * @param file The file to read or null to clear the data and select no file
+ */
+ public void setSelectedFile(File file) {
+ if (!NullUtils.areEquals(this.file, file)) {
+ if (!lastChanceToSave()) {
+ return;
+ }
+ if (file == null && lastChanceToSave()) {
+ newFile();
+ setFile(null);
+ } else if (read(file)) {
+ setFile(file);
+ }
+ }
+ }
+
+ private void setFile(File file) {
+ File old = this.file;
+ this.file = file;
+ firePropertyChange(SELECTED_FILE_PROPERTY, old, file);
+ setChanged(false);
+ }
+
+ public boolean isEmpty() {
+ return !getBtnSaveAs().isEnabled();
+ }
+
+ public boolean isChanged() {
+ return isChanged;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractSelector.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractSelector.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractSelector.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractSelector.java
index 0a35fd8..a3dbed4 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractSelector.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractSelector.java
@@ -1,300 +1,300 @@
-package com.fathzer.soft.ajlib.swing.widget;
-
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.Icon;
-import javax.swing.JList;
-import javax.swing.JPanel;
-
-import java.awt.Component;
-import java.awt.Dimension;
-import javax.swing.JLabel;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.JButton;
-
-import com.fathzer.soft.ajlib.swing.Utils;
-import com.fathzer.soft.ajlib.utilities.NullUtils;
-import javax.swing.SwingConstants;
-import java.awt.BorderLayout;
-
-
-/** An abstract widget composed of an optional label, a combo box and a new button.
- *
It is typically used to select a value in a list of possible values.
- *
This widget defines a property that reflects the selection changes. Its name is defined by the method getPropertyName.
- *
It also allows the combo box display to be customized using method getDefaultRenderedValue.
- * @param The class of the items selected by the selector.
- * @param The class of the constructor argument.
- * @see #getPropertyName()
- * @see #getDefaultRenderedValue(Object)
- */
-public abstract class AbstractSelector extends JPanel {
- private static final long serialVersionUID = 1L;
- private JLabel jLabel;
- private ComboBox combo;
- private JButton newButton;
-
- private T lastSelected;
- private V parameters;
-
- /**
- * Constructor.
- * @param parameters The init parameters of the selector (that object will be used to populate the combo).
- */
- protected AbstractSelector(V parameters) {
- this.parameters = parameters;
- initialize();
- internalPopulate();
- this.lastSelected = get();
- }
-
- private void internalPopulate() {
- getCombo().setActionEnabled(false);
- getCombo().removeAllItems();
- populateCombo();
- getCombo().setActionEnabled(true);
- }
-
- protected Icon getNewButtonIcon() {
- return null;
- }
-
- /** Gets the parameters of the widget.
- * @return The argument passed to the constructor.
- * @see #AbstractSelector(Object)
- */
- public V getParameters() {
- return this.parameters;
- }
-
- /** Sets the parameters of the widget.
- *
The refresh method is called.
- * @param parameters The new parameters
- */
- public void setParameters(V parameters) {
- this.parameters = parameters;
- refresh();
- }
-
- /** Populates the combo.
- *
You should override this method to define how the combo is populated.
- *
Usually, you will use the getParameters method in order to retrieve the argument of the constructor.
- *
Note that this method is always called with a empty combo.
- * @see #getParameters()
- */
- protected abstract void populateCombo();
-
- /** Refreshes the widget when the parameters has changed.
- *
This method is called when the widget parameters are changed by setParameters.
- *
It removes all old combo items, then calls populateCombo and setSelectionAfterRefresh.
- *
A property change is thrown if the selection changes (and the combo action is not disabled).
- *
The actionEnabled attribute of the combo is unchanged.
- * @see ComboBox#setActionEnabled(boolean)
- * @see #populateCombo()
- * @see #setSelectionAfterRefresh(Object)
- */
- public void refresh() {
- T old = get();
- boolean oldEnabled = getCombo().isActionEnabled();
- getCombo().setActionEnabled(false);
- getCombo().removeAllItems();
- populateCombo();
- getCombo().setActionEnabled(oldEnabled);
- setSelectionAfterRefresh(old);
- }
-
- /** Sets the combo selection during a refresh.
- *
By default, this method selects the last item selected, if it is still available.
- * @param old the last selected item before refresh was performed.
- */
- protected void setSelectionAfterRefresh(T old) {
- if (getCombo().contains(old)) {
- getCombo().setSelectedItem(old);
- }
- }
-
- private void initialize() {
- String label = getLabel();
- setLayout(new BorderLayout(0, 0));
- add(getJLabel(), BorderLayout.WEST);
- add(getCombo());
-
- add(getNewButton(), BorderLayout.EAST);
-
- Dimension dimension = getCombo().getPreferredSize();
- getNewButton().setPreferredSize(new Dimension(dimension.height, dimension.height));
-
- if (label!=null) {
- getJLabel().setText(getLabel());
- }
- if (getComboTip()!=null) {
- getCombo().setToolTipText(getComboTip());
- }
- if (getNewButtonTip()!=null) {
- getNewButton().setToolTipText(getNewButtonTip());
- }
- }
-
- /** Gets the label.
- * @return a JLabel
- */
- public JLabel getJLabel() {
- if (jLabel == null) {
- jLabel = new JLabel();
- }
- return jLabel;
- }
-
- /** Gets the new button.
- * @return a JButton
- */
- public JButton getNewButton() {
- if (newButton == null) {
- newButton = new JButton();
- newButton.setHorizontalAlignment(SwingConstants.LEFT);
- Icon icon = getNewButtonIcon();
- newButton = new JButton(icon);
- newButton.setFocusable(false);
- newButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- T c = createNew();
- if (c != null) {
- internalPopulate();
- getCombo().setSelectedItem(c);
- Utils.getOwnerWindow(AbstractSelector.this).pack();
- }
- }
- });
- newButton.setVisible(isNewButtonVisible());
- }
- return newButton;
- }
-
- protected boolean isNewButtonVisible() {
- return true;
- }
-
- /** Gets the ComboBox.
- * @return a CoolJComboBox.
- */
- public ComboBox getCombo() {
- if (combo == null) {
- combo = new ComboBox<>();
- combo.setRenderer(new Renderer());
- combo.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- T old = lastSelected;
- lastSelected = get();
- if (!NullUtils.areEquals(old, lastSelected)) {
- firePropertyChange(getPropertyName(), old, lastSelected);
- }
- }
- });
- }
- return combo;
- }
-
- @SuppressWarnings("serial")
- private class Renderer extends DefaultListCellRenderer {
- @SuppressWarnings("unchecked")
- @Override
- public Component getListCellRendererComponent(JList> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
- T v = (T)value;
- Component renderer = super.getListCellRendererComponent(list, getDefaultRenderedValue(v), index, isSelected, cellHasFocus);
- return getCustomizedRenderer (renderer, v, index, isSelected, cellHasFocus);
- }
- }
-
- /** Returns a customized renderer used to display a specific value.
- *
Please note that this method is never called when combo's renderer is set by getCombo().setRenderer(...) method.
- * @param renderer The default renderer
- * @param value The value to be rendered
- * @param index The index of the value in the combo
- * @param isSelected True if the value is selected
- * @param cellHasFocus True if the value has the focus
- * @return a customized renderer, by default this method returns the renderer argument.
- */
- protected Component getCustomizedRenderer (Component renderer, T value, int index, boolean isSelected, boolean cellHasFocus) {
- return renderer;
- }
-
- /** Returns the default value displayed in the combo box.
- *
Default means that this value is used by the default renderer. If you define your own ListCellRenderer, this method will never been called.
- * The default implementation returns the value itself (the default renderer will display the toString of that object).
- * You may override this method in order to customized the combo box displayed
- * @param value The value to be displayed (it can be null)
- * @return The value that will be displayed.
- */
- protected Object getDefaultRenderedValue (T value) {
- return value;
- }
-
- /** Creates a new element.
- * This method is called when the new button is clicked. It should ask for the new instance to be created, then, adds it to the object used
- * by method populateCombo, then, returns the created object.
- * @return The created object, null if the object creation was cancelled.
- */
- protected abstract T createNew();
-
- /** Gets the widget's label.
- * @return a String, null to have no label.
- */
- protected String getLabel() {
- return null;
- }
-
- /** Gets the combo's initial tooltip.
- * @return a String, null to have no tooltip.
- */
- protected String getComboTip() {
- return null;
- }
-
- /** Gets the new button's initial tooltip.
- * @return a String, null to have no tooltip.
- */
- protected String getNewButtonTip() {
- return null;
- }
-
- /** Gets the name of the property that changes when the selection changes.
- * @return a String
- */
- protected abstract String getPropertyName();
-
- /** Gets the selected value.
- * @return the selected value.
- */
- public T get() {
- return (T)getCombo().getSelectedItem();
- }
-
- /** Sets the selected value.
- * @param value The value to select
- */
- public void set(T value) {
- T oldValue = this.get();
- if (!NullUtils.areEquals(value,oldValue)) {
- getCombo().setSelectedItem(value);
- }
- }
-
- /** Sets the combo tooltip.
- *
This method is a shortcut to this.getCombo().setToolTipText(text)
- * @param tip The tooltip text.
- */
- @Override
- public void setToolTipText(String tip) {
- getCombo().setToolTipText(tip);
- }
-
- @Override
- public void setEnabled(boolean enabled) {
- super.setEnabled(enabled);
- getJLabel().setEnabled(enabled);
- getNewButton().setEnabled(enabled);
- getCombo().setEnabled(enabled);
- }
-}
+package com.fathzer.soft.ajlib.swing.widget;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.Icon;
+import javax.swing.JList;
+import javax.swing.JPanel;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import javax.swing.JLabel;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+
+import com.fathzer.soft.ajlib.swing.Utils;
+import com.fathzer.soft.ajlib.utilities.NullUtils;
+import javax.swing.SwingConstants;
+import java.awt.BorderLayout;
+
+
+/** An abstract widget composed of an optional label, a combo box and a new button.
+ *
It is typically used to select a value in a list of possible values.
+ *
This widget defines a property that reflects the selection changes. Its name is defined by the method getPropertyName.
+ *
It also allows the combo box display to be customized using method getDefaultRenderedValue.
+ * @param The class of the items selected by the selector.
+ * @param The class of the constructor argument.
+ * @see #getPropertyName()
+ * @see #getDefaultRenderedValue(Object)
+ */
+public abstract class AbstractSelector extends JPanel {
+ private static final long serialVersionUID = 1L;
+ private JLabel jLabel;
+ private ComboBox combo;
+ private JButton newButton;
+
+ private T lastSelected;
+ private V parameters;
+
+ /**
+ * Constructor.
+ * @param parameters The init parameters of the selector (that object will be used to populate the combo).
+ */
+ protected AbstractSelector(V parameters) {
+ this.parameters = parameters;
+ initialize();
+ internalPopulate();
+ this.lastSelected = get();
+ }
+
+ private void internalPopulate() {
+ getCombo().setActionEnabled(false);
+ getCombo().removeAllItems();
+ populateCombo();
+ getCombo().setActionEnabled(true);
+ }
+
+ protected Icon getNewButtonIcon() {
+ return null;
+ }
+
+ /** Gets the parameters of the widget.
+ * @return The argument passed to the constructor.
+ * @see #AbstractSelector(Object)
+ */
+ public V getParameters() {
+ return this.parameters;
+ }
+
+ /** Sets the parameters of the widget.
+ *
The refresh method is called.
+ * @param parameters The new parameters
+ */
+ public void setParameters(V parameters) {
+ this.parameters = parameters;
+ refresh();
+ }
+
+ /** Populates the combo.
+ *
You should override this method to define how the combo is populated.
+ *
Usually, you will use the getParameters method in order to retrieve the argument of the constructor.
+ *
Note that this method is always called with a empty combo.
+ * @see #getParameters()
+ */
+ protected abstract void populateCombo();
+
+ /** Refreshes the widget when the parameters has changed.
+ *
This method is called when the widget parameters are changed by setParameters.
+ *
It removes all old combo items, then calls populateCombo and setSelectionAfterRefresh.
+ *
A property change is thrown if the selection changes (and the combo action is not disabled).
+ *
The actionEnabled attribute of the combo is unchanged.
+ * @see ComboBox#setActionEnabled(boolean)
+ * @see #populateCombo()
+ * @see #setSelectionAfterRefresh(Object)
+ */
+ public void refresh() {
+ T old = get();
+ boolean oldEnabled = getCombo().isActionEnabled();
+ getCombo().setActionEnabled(false);
+ getCombo().removeAllItems();
+ populateCombo();
+ getCombo().setActionEnabled(oldEnabled);
+ setSelectionAfterRefresh(old);
+ }
+
+ /** Sets the combo selection during a refresh.
+ *
By default, this method selects the last item selected, if it is still available.
+ * @param old the last selected item before refresh was performed.
+ */
+ protected void setSelectionAfterRefresh(T old) {
+ if (getCombo().contains(old)) {
+ getCombo().setSelectedItem(old);
+ }
+ }
+
+ private void initialize() {
+ String label = getLabel();
+ setLayout(new BorderLayout(0, 0));
+ add(getJLabel(), BorderLayout.WEST);
+ add(getCombo());
+
+ add(getNewButton(), BorderLayout.EAST);
+
+ Dimension dimension = getCombo().getPreferredSize();
+ getNewButton().setPreferredSize(new Dimension(dimension.height, dimension.height));
+
+ if (label!=null) {
+ getJLabel().setText(getLabel());
+ }
+ if (getComboTip()!=null) {
+ getCombo().setToolTipText(getComboTip());
+ }
+ if (getNewButtonTip()!=null) {
+ getNewButton().setToolTipText(getNewButtonTip());
+ }
+ }
+
+ /** Gets the label.
+ * @return a JLabel
+ */
+ public JLabel getJLabel() {
+ if (jLabel == null) {
+ jLabel = new JLabel();
+ }
+ return jLabel;
+ }
+
+ /** Gets the new button.
+ * @return a JButton
+ */
+ public JButton getNewButton() {
+ if (newButton == null) {
+ newButton = new JButton();
+ newButton.setHorizontalAlignment(SwingConstants.LEFT);
+ Icon icon = getNewButtonIcon();
+ newButton = new JButton(icon);
+ newButton.setFocusable(false);
+ newButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ T c = createNew();
+ if (c != null) {
+ internalPopulate();
+ getCombo().setSelectedItem(c);
+ Utils.getOwnerWindow(AbstractSelector.this).pack();
+ }
+ }
+ });
+ newButton.setVisible(isNewButtonVisible());
+ }
+ return newButton;
+ }
+
+ protected boolean isNewButtonVisible() {
+ return true;
+ }
+
+ /** Gets the ComboBox.
+ * @return a CoolJComboBox.
+ */
+ public ComboBox getCombo() {
+ if (combo == null) {
+ combo = new ComboBox<>();
+ combo.setRenderer(new Renderer());
+ combo.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ T old = lastSelected;
+ lastSelected = get();
+ if (!NullUtils.areEquals(old, lastSelected)) {
+ firePropertyChange(getPropertyName(), old, lastSelected);
+ }
+ }
+ });
+ }
+ return combo;
+ }
+
+ @SuppressWarnings("serial")
+ private class Renderer extends DefaultListCellRenderer {
+ @SuppressWarnings("unchecked")
+ @Override
+ public Component getListCellRendererComponent(JList> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ T v = (T)value;
+ Component renderer = super.getListCellRendererComponent(list, getDefaultRenderedValue(v), index, isSelected, cellHasFocus);
+ return getCustomizedRenderer (renderer, v, index, isSelected, cellHasFocus);
+ }
+ }
+
+ /** Returns a customized renderer used to display a specific value.
+ *
Please note that this method is never called when combo's renderer is set by getCombo().setRenderer(...) method.
+ * @param renderer The default renderer
+ * @param value The value to be rendered
+ * @param index The index of the value in the combo
+ * @param isSelected True if the value is selected
+ * @param cellHasFocus True if the value has the focus
+ * @return a customized renderer, by default this method returns the renderer argument.
+ */
+ protected Component getCustomizedRenderer (Component renderer, T value, int index, boolean isSelected, boolean cellHasFocus) {
+ return renderer;
+ }
+
+ /** Returns the default value displayed in the combo box.
+ *
Default means that this value is used by the default renderer. If you define your own ListCellRenderer, this method will never been called.
+ * The default implementation returns the value itself (the default renderer will display the toString of that object).
+ * You may override this method in order to customized the combo box displayed
+ * @param value The value to be displayed (it can be null)
+ * @return The value that will be displayed.
+ */
+ protected Object getDefaultRenderedValue (T value) {
+ return value;
+ }
+
+ /** Creates a new element.
+ * This method is called when the new button is clicked. It should ask for the new instance to be created, then, adds it to the object used
+ * by method populateCombo, then, returns the created object.
+ * @return The created object, null if the object creation was cancelled.
+ */
+ protected abstract T createNew();
+
+ /** Gets the widget's label.
+ * @return a String, null to have no label.
+ */
+ protected String getLabel() {
+ return null;
+ }
+
+ /** Gets the combo's initial tooltip.
+ * @return a String, null to have no tooltip.
+ */
+ protected String getComboTip() {
+ return null;
+ }
+
+ /** Gets the new button's initial tooltip.
+ * @return a String, null to have no tooltip.
+ */
+ protected String getNewButtonTip() {
+ return null;
+ }
+
+ /** Gets the name of the property that changes when the selection changes.
+ * @return a String
+ */
+ protected abstract String getPropertyName();
+
+ /** Gets the selected value.
+ * @return the selected value.
+ */
+ public T get() {
+ return (T)getCombo().getSelectedItem();
+ }
+
+ /** Sets the selected value.
+ * @param value The value to select
+ */
+ public void set(T value) {
+ T oldValue = this.get();
+ if (!NullUtils.areEquals(value,oldValue)) {
+ getCombo().setSelectedItem(value);
+ }
+ }
+
+ /** Sets the combo tooltip.
+ *
This method is a shortcut to this.getCombo().setToolTipText(text)
+ * @param tip The tooltip text.
+ */
+ @Override
+ public void setToolTipText(String tip) {
+ getCombo().setToolTipText(tip);
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ getJLabel().setEnabled(enabled);
+ getNewButton().setEnabled(enabled);
+ getCombo().setEnabled(enabled);
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractTitledPanel.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractTitledPanel.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractTitledPanel.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractTitledPanel.java
index 4bab874..53df241 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractTitledPanel.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/AbstractTitledPanel.java
@@ -1,123 +1,123 @@
-package com.fathzer.soft.ajlib.swing.widget;
-
-import java.awt.GridBagLayout;
-
-import javax.swing.Icon;
-import javax.swing.JComponent;
-import javax.swing.JPanel;
-
-import java.awt.BorderLayout;
-import javax.swing.JLabel;
-
-import java.awt.GridBagConstraints;
-import java.awt.Insets;
-
-/** A very basic panel, composed of a header with an icon at its north and a component in the center.
- * @param The class of the data used to fill the center panel.
- */
-public abstract class AbstractTitledPanel extends JPanel {
- private static final long serialVersionUID = 1L;
- private JPanel northPanel = null;
- private JLabel iconLabel = null;
- private JLabel textLabel = null;
-
- protected T data;
-
- /**
- * Constructor.
- * @param headerMessage The header message
- * @param headerIcon The header icon (null for no icon)
- * @param data The center component's data
- */
- protected AbstractTitledPanel(String headerMessage, Icon headerIcon, T data) {
- super();
- this.data = data;
- initialize();
- this.setHeaderMessage(headerMessage);
- this.setHeaderIcon(headerIcon);
- }
-
- /**
- * This method initializes this
- */
- private void initialize() {
- this.setLayout(new BorderLayout());
- this.add(getNorthPanel(), BorderLayout.NORTH);
- this.add(getCenterComponent(), BorderLayout.CENTER);
- }
-
- /**
- * This method initializes northPanel
- *
- * @return javax.swing.JPanel
- */
- private JPanel getNorthPanel() {
- if (northPanel == null) {
- GridBagConstraints gridBagConstraints1 = new GridBagConstraints();
- gridBagConstraints1.gridx = 1;
- gridBagConstraints1.weightx = 1.0D;
- gridBagConstraints1.fill = GridBagConstraints.HORIZONTAL;
- gridBagConstraints1.insets = new Insets(5, 5, 5, 5);
- gridBagConstraints1.gridy = 0;
- textLabel = new JLabel();
- GridBagConstraints gridBagConstraints = new GridBagConstraints();
- gridBagConstraints.gridx = 0;
- gridBagConstraints.anchor = GridBagConstraints.WEST;
- gridBagConstraints.insets = new Insets(5, 5, 5, 5);
- gridBagConstraints.gridy = 0;
- northPanel = new JPanel();
- northPanel.setLayout(new GridBagLayout());
- northPanel.add(getIconLabel(), gridBagConstraints);
- northPanel.add(textLabel, gridBagConstraints1);
- }
- return northPanel;
- }
-
- /** Sets the header message.
- * @param message The message
- */
- public void setHeaderMessage(String message) {
- this.textLabel.setText(message);
- }
-
- /** Gets the header message.
- * @return a String
- */
- public String getHeaderMessage() {
- return this.textLabel.getText();
- }
-
- /**
- * This method initializes iconLabel
- *
- * @return javax.swing.JLabel
- */
- private JLabel getIconLabel() {
- if (iconLabel == null) {
- iconLabel = new JLabel();
- }
- return iconLabel;
- }
-
- /** Gets the icon.
- * @return a Icon
- */
- public Icon getHeaderIcon() {
- return this.getIconLabel().getIcon();
- }
-
- /** Sets the icon.
- *
By default, the icon is null (no icon). You may want to set it to some of the standard dialog icons (example UIManager.getIcon("OptionPane.informationIcon"))
- * @param icon null to remove the icon
- */
- public void setHeaderIcon(Icon icon) {
- this.getIconLabel().setIcon(icon);
- }
-
- /**
- * Gets the center Component.
- *
Please note that this method should always return the same JComponent instance.
- * @return a JComponent
- */
- public abstract JComponent getCenterComponent();
-} // @jve:decl-index=0:visual-constraint="10,10"
+package com.fathzer.soft.ajlib.swing.widget;
+
+import java.awt.GridBagLayout;
+
+import javax.swing.Icon;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+import java.awt.BorderLayout;
+import javax.swing.JLabel;
+
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+
+/** A very basic panel, composed of a header with an icon at its north and a component in the center.
+ * @param The class of the data used to fill the center panel.
+ */
+public abstract class AbstractTitledPanel extends JPanel {
+ private static final long serialVersionUID = 1L;
+ private JPanel northPanel = null;
+ private JLabel iconLabel = null;
+ private JLabel textLabel = null;
+
+ protected T data;
+
+ /**
+ * Constructor.
+ * @param headerMessage The header message
+ * @param headerIcon The header icon (null for no icon)
+ * @param data The center component's data
+ */
+ protected AbstractTitledPanel(String headerMessage, Icon headerIcon, T data) {
+ super();
+ this.data = data;
+ initialize();
+ this.setHeaderMessage(headerMessage);
+ this.setHeaderIcon(headerIcon);
+ }
+
+ /**
+ * This method initializes this
+ */
+ private void initialize() {
+ this.setLayout(new BorderLayout());
+ this.add(getNorthPanel(), BorderLayout.NORTH);
+ this.add(getCenterComponent(), BorderLayout.CENTER);
+ }
+
+ /**
+ * This method initializes northPanel
+ *
+ * @return javax.swing.JPanel
+ */
+ private JPanel getNorthPanel() {
+ if (northPanel == null) {
+ GridBagConstraints gridBagConstraints1 = new GridBagConstraints();
+ gridBagConstraints1.gridx = 1;
+ gridBagConstraints1.weightx = 1.0D;
+ gridBagConstraints1.fill = GridBagConstraints.HORIZONTAL;
+ gridBagConstraints1.insets = new Insets(5, 5, 5, 5);
+ gridBagConstraints1.gridy = 0;
+ textLabel = new JLabel();
+ GridBagConstraints gridBagConstraints = new GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.anchor = GridBagConstraints.WEST;
+ gridBagConstraints.insets = new Insets(5, 5, 5, 5);
+ gridBagConstraints.gridy = 0;
+ northPanel = new JPanel();
+ northPanel.setLayout(new GridBagLayout());
+ northPanel.add(getIconLabel(), gridBagConstraints);
+ northPanel.add(textLabel, gridBagConstraints1);
+ }
+ return northPanel;
+ }
+
+ /** Sets the header message.
+ * @param message The message
+ */
+ public void setHeaderMessage(String message) {
+ this.textLabel.setText(message);
+ }
+
+ /** Gets the header message.
+ * @return a String
+ */
+ public String getHeaderMessage() {
+ return this.textLabel.getText();
+ }
+
+ /**
+ * This method initializes iconLabel
+ *
+ * @return javax.swing.JLabel
+ */
+ private JLabel getIconLabel() {
+ if (iconLabel == null) {
+ iconLabel = new JLabel();
+ }
+ return iconLabel;
+ }
+
+ /** Gets the icon.
+ * @return a Icon
+ */
+ public Icon getHeaderIcon() {
+ return this.getIconLabel().getIcon();
+ }
+
+ /** Sets the icon.
+ *
By default, the icon is null (no icon). You may want to set it to some of the standard dialog icons (example UIManager.getIcon("OptionPane.informationIcon"))
+ * @param icon null to remove the icon
+ */
+ public void setHeaderIcon(Icon icon) {
+ this.getIconLabel().setIcon(icon);
+ }
+
+ /**
+ * Gets the center Component.
+ *
Please note that this method should always return the same JComponent instance.
+ * @return a JComponent
+ */
+ public abstract JComponent getCenterComponent();
+} // @jve:decl-index=0:visual-constraint="10,10"
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/CharWidget.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/CharWidget.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/CharWidget.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/CharWidget.java
index 587b3ba..1610138 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/CharWidget.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/CharWidget.java
@@ -1,84 +1,84 @@
-package com.fathzer.soft.ajlib.swing.widget;
-
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-
-import com.fathzer.soft.ajlib.utilities.NullUtils;
-
-
-/** A widget that allows the user to enter only one character.
- */
-@SuppressWarnings("serial")
-public class CharWidget extends TextWidget {
- /** The character property name.
- *
This property is the character contained in the widget.
- */
- public static final String CHAR_PROPERTY = "char";
- private Character content;
- private Character defaultChar;
-
- /** Constructor.
- *
The field is empty and the default character is null.
- * @see CharWidget#setDefaultChar(char)
- */
- public CharWidget() {
- super(1);
- // We will not use a document listener to listen the field modifications because we want to change the field (truncate it to its first character)
- // and document listener can't modify the source event (it throws an IllegalStateException).
- addPropertyChangeListener(TextWidget.TEXT_PROPERTY, new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- String text = getText();
- if (text.length()==0) {
- setChar(defaultChar);
- } else if (text.length()>1){
- setText(new String(new char[]{text.charAt(text.length()-1)}));
- } else {
- setChar(text.charAt(0));
- }
- selectAll();
- }
- });
- addFocusListener(new FocusListener() {
- @Override
- public void focusLost(FocusEvent e) {
- // Nothing to do
- }
-
- @Override
- public void focusGained(FocusEvent e) {
- selectAll();
- }
- });
- }
-
- /** Sets the widget's character.
- * @param character The character to put in the widget or null to make the field empty (or set it to its default value).
- * @see CharWidget#setDefaultChar(char)
- */
- public void setChar(Character character) {
- if (!NullUtils.areEquals(character,content)) {
- Character old = this.content;
- this.content = character;
- setText(content==null?"":new String(new char[]{this.content}));
- this.firePropertyChange(CHAR_PROPERTY, old, content);
- }
- }
-
- /** Gets the widget's character.
- * @return a character (null if the field is empty)
- */
- public Character getChar() {
- return this.content;
- }
-
- /** Sets the default character.
- *
When the user delete the character in the field. The field content is automatically set to the default character.
- * @param defaultChar The new default character (null to leave the field empty).
- */
- public void setDefaultChar(char defaultChar) {
- this.defaultChar = defaultChar;
- }
-}
+package com.fathzer.soft.ajlib.swing.widget;
+
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import com.fathzer.soft.ajlib.utilities.NullUtils;
+
+
+/** A widget that allows the user to enter only one character.
+ */
+@SuppressWarnings("serial")
+public class CharWidget extends TextWidget {
+ /** The character property name.
+ *
This property is the character contained in the widget.
+ */
+ public static final String CHAR_PROPERTY = "char";
+ private Character content;
+ private Character defaultChar;
+
+ /** Constructor.
+ *
The field is empty and the default character is null.
+ * @see CharWidget#setDefaultChar(char)
+ */
+ public CharWidget() {
+ super(1);
+ // We will not use a document listener to listen the field modifications because we want to change the field (truncate it to its first character)
+ // and document listener can't modify the source event (it throws an IllegalStateException).
+ addPropertyChangeListener(TextWidget.TEXT_PROPERTY, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ String text = getText();
+ if (text.length()==0) {
+ setChar(defaultChar);
+ } else if (text.length()>1){
+ setText(new String(new char[]{text.charAt(text.length()-1)}));
+ } else {
+ setChar(text.charAt(0));
+ }
+ selectAll();
+ }
+ });
+ addFocusListener(new FocusListener() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ // Nothing to do
+ }
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ selectAll();
+ }
+ });
+ }
+
+ /** Sets the widget's character.
+ * @param character The character to put in the widget or null to make the field empty (or set it to its default value).
+ * @see CharWidget#setDefaultChar(char)
+ */
+ public void setChar(Character character) {
+ if (!NullUtils.areEquals(character,content)) {
+ Character old = this.content;
+ this.content = character;
+ setText(content==null?"":new String(new char[]{this.content}));
+ this.firePropertyChange(CHAR_PROPERTY, old, content);
+ }
+ }
+
+ /** Gets the widget's character.
+ * @return a character (null if the field is empty)
+ */
+ public Character getChar() {
+ return this.content;
+ }
+
+ /** Sets the default character.
+ *
When the user delete the character in the field. The field content is automatically set to the default character.
+ * @param defaultChar The new default character (null to leave the field empty).
+ */
+ public void setDefaultChar(char defaultChar) {
+ this.defaultChar = defaultChar;
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/ComboBox.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/ComboBox.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/ComboBox.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/ComboBox.java
index a415490..b6303da 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/ComboBox.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/ComboBox.java
@@ -1,50 +1,50 @@
-package com.fathzer.soft.ajlib.swing.widget;
-
-import javax.swing.JComboBox;
-
-/** This subclass of JCombo is cool because it adds some useful functionalities, often asked in the forums.
- * - you can prevent instance from sending action event.
- * It could be very useful when you have to refresh the menu but don't want any event being sent.
- * - The method contains tests whether the menu contains an item or not
- *
- */
-public class ComboBox extends JComboBox {
- private static final long serialVersionUID = 1L;
-
- private boolean isActionEnabled = true;
-
- /** Enables/Disables the events.
- *
Note: This method doesn't throw any event.
- * @param isActionEnabled true to enable the events.
- */
- public void setActionEnabled(boolean isActionEnabled) {
- this.isActionEnabled = isActionEnabled;
- }
-
- /** Tests whether the events are enabled or not.
- * @return true if events are enabled.
- */
- public boolean isActionEnabled() {
- return isActionEnabled;
- }
-
- /** Tests whether the menu contains an item or not
- * @param item the item to test
- * @return true if the item is in the menu.
- */
- public boolean contains (T item) {
- for (int i = 0; i < this.getItemCount(); i++) {
- if (this.getItemAt(i).equals(item)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- protected void fireActionEvent() {
- if (isActionEnabled) {
- super.fireActionEvent();
- }
- }
-}
+package com.fathzer.soft.ajlib.swing.widget;
+
+import javax.swing.JComboBox;
+
+/** This subclass of JCombo is cool because it adds some useful functionalities, often asked in the forums.
+ * - you can prevent instance from sending action event.
+ * It could be very useful when you have to refresh the menu but don't want any event being sent.
+ * - The method contains tests whether the menu contains an item or not
+ *
+ */
+public class ComboBox extends JComboBox {
+ private static final long serialVersionUID = 1L;
+
+ private boolean isActionEnabled = true;
+
+ /** Enables/Disables the events.
+ *
Note: This method doesn't throw any event.
+ * @param isActionEnabled true to enable the events.
+ */
+ public void setActionEnabled(boolean isActionEnabled) {
+ this.isActionEnabled = isActionEnabled;
+ }
+
+ /** Tests whether the events are enabled or not.
+ * @return true if events are enabled.
+ */
+ public boolean isActionEnabled() {
+ return isActionEnabled;
+ }
+
+ /** Tests whether the menu contains an item or not
+ * @param item the item to test
+ * @return true if the item is in the menu.
+ */
+ public boolean contains (T item) {
+ for (int i = 0; i < this.getItemCount(); i++) {
+ if (this.getItemAt(i).equals(item)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void fireActionEvent() {
+ if (isActionEnabled) {
+ super.fireActionEvent();
+ }
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/CurrencyWidget.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/CurrencyWidget.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/CurrencyWidget.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/CurrencyWidget.java
index 7bf4041..2fb16c4 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/CurrencyWidget.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/CurrencyWidget.java
@@ -1,76 +1,76 @@
-package com.fathzer.soft.ajlib.swing.widget;
-
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.util.Currency;
-import java.util.Locale;
-
-/** A widget to enter a monetary value.
- *
This widget automatically format the value it contains according to its local's currency.
- *
You can restrict the valid values by setting minimum and maximum values.
- *
This bean defines two properties:
- * - VALUE_PROPERTY: a double, the value currently entered in the field.
- * - CONTENT_VALID_PROPERTY: a boolean, true if the text currently entered in the field is a valid value, false if it is not.
- *
The CONTENT_VALID_PROPERTY is a read only property.
- *
- */
-public class CurrencyWidget extends NumberWidget {
- private static final long serialVersionUID = 1L;
-
- private DecimalFormat numberFormat;
-
- /** Constructor.
- * The local is set to default locale.
- * @see #CurrencyWidget(Locale)
- */
- public CurrencyWidget() {
- this(Locale.getDefault());
- }
-
- /** Constructor.
- * Empty field is not allowed.
- * minValue is equals to Double.NEGATIVE_INFINITY, maxValue to Double.POSITIVE_INFINITY.
- * The value is set to null.
- * @param locale The locale to apply to the widget (use to format the amount typed).
- */
- public CurrencyWidget(Locale locale) {
- super(locale);
- }
-
- @Override
- protected DecimalFormat buildFormat(Locale locale) {
- this.numberFormat = super.buildFormat(locale);
- return patchJavaBug4510618((DecimalFormat) NumberFormat.getCurrencyInstance(locale));
- }
-
- /** Gets the widget's currency.
- * @return the windget's currency
- */
- public Currency getCurrency() {
- return getFormat().getCurrency();
- }
-
- /** Sets the currency.
- *
By default, the currency is the one of the widget's locale.
- * @param currency The new currency.
- */
- public void setCurrency (Currency currency) {
- getFormat().setCurrency(currency);
- int digits = currency.getDefaultFractionDigits();
- getFormat().setMaximumFractionDigits(digits);
- getFormat().setMinimumFractionDigits(digits);
- refreshText();
- }
-
- /* (non-Javadoc)
- * @see NumberWidget#parseValue(java.lang.String)
- */
- @Override
- protected Number parseValue(String text) {
- Number result = super.parseValue(text);
- if (result==null) {
- result = safeParse(numberFormat, text);
- }
- return result;
- }
-}
+package com.fathzer.soft.ajlib.swing.widget;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Currency;
+import java.util.Locale;
+
+/** A widget to enter a monetary value.
+ *
This widget automatically format the value it contains according to its local's currency.
+ *
You can restrict the valid values by setting minimum and maximum values.
+ *
This bean defines two properties:
+ * - VALUE_PROPERTY: a double, the value currently entered in the field.
+ * - CONTENT_VALID_PROPERTY: a boolean, true if the text currently entered in the field is a valid value, false if it is not.
+ *
The CONTENT_VALID_PROPERTY is a read only property.
+ *
+ */
+public class CurrencyWidget extends NumberWidget {
+ private static final long serialVersionUID = 1L;
+
+ private DecimalFormat numberFormat;
+
+ /** Constructor.
+ * The local is set to default locale.
+ * @see #CurrencyWidget(Locale)
+ */
+ public CurrencyWidget() {
+ this(Locale.getDefault());
+ }
+
+ /** Constructor.
+ * Empty field is not allowed.
+ * minValue is equals to Double.NEGATIVE_INFINITY, maxValue to Double.POSITIVE_INFINITY.
+ * The value is set to null.
+ * @param locale The locale to apply to the widget (use to format the amount typed).
+ */
+ public CurrencyWidget(Locale locale) {
+ super(locale);
+ }
+
+ @Override
+ protected DecimalFormat buildFormat(Locale locale) {
+ this.numberFormat = super.buildFormat(locale);
+ return patchJavaBug4510618((DecimalFormat) NumberFormat.getCurrencyInstance(locale));
+ }
+
+ /** Gets the widget's currency.
+ * @return the windget's currency
+ */
+ public Currency getCurrency() {
+ return getFormat().getCurrency();
+ }
+
+ /** Sets the currency.
+ *
By default, the currency is the one of the widget's locale.
+ * @param currency The new currency.
+ */
+ public void setCurrency (Currency currency) {
+ getFormat().setCurrency(currency);
+ int digits = currency.getDefaultFractionDigits();
+ getFormat().setMaximumFractionDigits(digits);
+ getFormat().setMinimumFractionDigits(digits);
+ refreshText();
+ }
+
+ /* (non-Javadoc)
+ * @see NumberWidget#parseValue(java.lang.String)
+ */
+ @Override
+ protected Number parseValue(String text) {
+ Number result = super.parseValue(text);
+ if (result==null) {
+ result = safeParse(numberFormat, text);
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/ExcelPane.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/ExcelPane.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/ExcelPane.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/ExcelPane.java
index 4186504..ce83a8e 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/ExcelPane.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/ExcelPane.java
@@ -1,187 +1,187 @@
-package com.fathzer.soft.ajlib.swing.widget;
-
-import javax.swing.JComponent;
-import javax.swing.JFileChooser;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-
-import java.awt.GridBagLayout;
-import java.awt.GridBagConstraints;
-
-import javax.swing.JButton;
-import javax.swing.filechooser.FileNameExtensionFilter;
-
-import com.fathzer.jlocal.Formatter;
-import com.fathzer.soft.ajlib.swing.dialog.FileChooser;
-import com.fathzer.soft.ajlib.swing.framework.Application;
-import com.fathzer.soft.ajlib.swing.table.CSVExporter;
-import com.fathzer.soft.ajlib.swing.table.Table;
-
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-
-/** A widget with a JTable and a button that is able to save it in csv format.
- */
-public class ExcelPane extends JPanel {
- private static final long serialVersionUID = 1L;
- private static final String CSV_EXTENSION = ".csv";
-
- private Table table;
- private JButton saveButton;
-
- private CSVExporter exporter;
-
- /**
- * Creates the panel.
- */
- public ExcelPane() {
- initialize();
- }
-
- /** Initializes the panel.
- *
This method is called once by the constructor.
- *
This implementation sets the layout to a new GridBagLayout and adds the table and the button to it.
- *
You can override this method in order to create a custom panel (for example, if you want to change the button position).
- */
- protected void initialize() {
- GridBagLayout gridBagLayout = new GridBagLayout();
- setLayout(gridBagLayout);
- GridBagConstraints gbcScrollPane = new GridBagConstraints();
- gbcScrollPane.gridwidth = 0;
- gbcScrollPane.weighty = 1.0;
- gbcScrollPane.weightx = 1.0;
- gbcScrollPane.fill = GridBagConstraints.BOTH;
- gbcScrollPane.gridx = 0;
- gbcScrollPane.gridy = 0;
- add(getTable(), gbcScrollPane);
- GridBagConstraints gbcSaveButton = new GridBagConstraints();
- gbcSaveButton.insets = new Insets(5, 0, 0, 0);
- gbcSaveButton.anchor = GridBagConstraints.EAST;
- gbcSaveButton.gridx = 1;
- gbcSaveButton.gridy = 1;
- add(getSaveButton(), gbcSaveButton);
- JComponent extra = getExtraComponent();
- if (extra!=null) {
- GridBagConstraints gbcExtra = new GridBagConstraints();
- gbcExtra.insets = new Insets(5, 0, 0, 0);
- gbcExtra.anchor = GridBagConstraints.EAST;
- gbcExtra.gridx = 0;
- gbcExtra.gridy = 1;
- gbcExtra.weightx = 1.0;
- gbcExtra.fill = GridBagConstraints.HORIZONTAL;
- add(extra, gbcExtra);
- }
- }
-
- /** Gets an extra component displayed at left below the table.
- *
By default, this method returns null.
- * @return A JComponent or null if no component is provided.
- */
- protected JComponent getExtraComponent() {
- return null;
- }
-
- /** Gets the table.
- * @return a Table
- */
- public final Table getTable() {
- if (table == null) {
- table = buildTable();
- }
- return table;
- }
-
- /** Gets the save button.
- * @return a button
- */
- public final JButton getSaveButton() {
- if (saveButton == null) {
- saveButton = new JButton(Application.getString("ExcelPane.save", getLocale())); //$NON-NLS-1$
- saveButton.addActionListener(new SaveButtonActionListener());
- }
- return saveButton;
- }
-
- private final class SaveButtonActionListener implements ActionListener {
- public void actionPerformed(ActionEvent e) {
- JFileChooser chooser = new FileChooser(getInitialPath()) {
- private static final long serialVersionUID = 1L;
- @Override
- public File getSelectedFile() {
- File f = super.getSelectedFile();
- if ((f!=null) && !f.getName().endsWith(CSV_EXTENSION)) {
- f = new File(f.getParent(), f.getName()+CSV_EXTENSION);
- }
- return f;
- }
- };
- chooser.setFileFilter(new FileNameExtensionFilter(Application.getString("ExcelPane.csv.wording", getLocale()),CSV_EXTENSION.substring(1)));
- File file = chooser.showSaveDialog(ExcelPane.this)==JFileChooser.APPROVE_OPTION?chooser.getSelectedFile():null;
- if (file!=null) {
- try {
- save(file);
- } catch(IOException ex) {
- String message = Formatter.format(Application.getString("ExcelPane.error.message", getLocale()), ex.toString()); //$NON-NLS-1$
- JOptionPane.showMessageDialog(ExcelPane.this, message, Application.getString("Generic.error", getLocale()), JOptionPane.ERROR_MESSAGE); //$NON-NLS-1$
- }
- }
- }
- }
-
- /** Gets the initial path of the file chooser.
- *
This method is called every time the save button is clicked.
- *
By default, this path is null.
- * @return The path or null that causes the file chooser to point to the user's default directory
- */
- protected String getInitialPath() {
- return null;
- }
-
- /** Saves the pane content to a file.
- *
This method is called every time the save button is clicked and a file is selected.
- *
By default, the content is save to the file using the csv exporter.
- * @param file The file selected by the user to save the data.
- * @see #getCSVExporter()
- * @throws IOException If something goes wrong while writing file.
- */
- protected void save(File file) throws IOException {
- try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
- getCSVExporter().export(writer, getTable().getModel(), true);
- writer.flush();
- }
- }
-
- /** Gets the CSVExporter used to export the data.
- * @return a CSVExporter
- */
- public final CSVExporter getCSVExporter() {
- if (this.exporter == null) {
- exporter = buildExporter();
- }
- return this.exporter;
- }
-
- /** Builds the table.
- *
This method is called once.
- *
You can override this method in order to create a customized Table.
- * @return a Table
- */
- protected Table buildTable() {
- return new Table();
- }
-
- /** Builds the table.
- *
This method is called once.
- *
The default implementation returns a default CSVExporter;
- * @return a CSVExporter
- * @see CSVExporter
- */
- protected CSVExporter buildExporter() {
- return new CSVExporter();
- }
+package com.fathzer.soft.ajlib.swing.widget;
+
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+import java.awt.GridBagLayout;
+import java.awt.GridBagConstraints;
+
+import javax.swing.JButton;
+import javax.swing.filechooser.FileNameExtensionFilter;
+
+import com.fathzer.jlocal.Formatter;
+import com.fathzer.soft.ajlib.swing.dialog.FileChooser;
+import com.fathzer.soft.ajlib.swing.framework.Application;
+import com.fathzer.soft.ajlib.swing.table.CSVExporter;
+import com.fathzer.soft.ajlib.swing.table.Table;
+
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/** A widget with a JTable and a button that is able to save it in csv format.
+ */
+public class ExcelPane extends JPanel {
+ private static final long serialVersionUID = 1L;
+ private static final String CSV_EXTENSION = ".csv";
+
+ private Table table;
+ private JButton saveButton;
+
+ private CSVExporter exporter;
+
+ /**
+ * Creates the panel.
+ */
+ public ExcelPane() {
+ initialize();
+ }
+
+ /** Initializes the panel.
+ *
This method is called once by the constructor.
+ *
This implementation sets the layout to a new GridBagLayout and adds the table and the button to it.
+ *
You can override this method in order to create a custom panel (for example, if you want to change the button position).
+ */
+ protected void initialize() {
+ GridBagLayout gridBagLayout = new GridBagLayout();
+ setLayout(gridBagLayout);
+ GridBagConstraints gbcScrollPane = new GridBagConstraints();
+ gbcScrollPane.gridwidth = 0;
+ gbcScrollPane.weighty = 1.0;
+ gbcScrollPane.weightx = 1.0;
+ gbcScrollPane.fill = GridBagConstraints.BOTH;
+ gbcScrollPane.gridx = 0;
+ gbcScrollPane.gridy = 0;
+ add(getTable(), gbcScrollPane);
+ GridBagConstraints gbcSaveButton = new GridBagConstraints();
+ gbcSaveButton.insets = new Insets(5, 0, 0, 0);
+ gbcSaveButton.anchor = GridBagConstraints.EAST;
+ gbcSaveButton.gridx = 1;
+ gbcSaveButton.gridy = 1;
+ add(getSaveButton(), gbcSaveButton);
+ JComponent extra = getExtraComponent();
+ if (extra!=null) {
+ GridBagConstraints gbcExtra = new GridBagConstraints();
+ gbcExtra.insets = new Insets(5, 0, 0, 0);
+ gbcExtra.anchor = GridBagConstraints.EAST;
+ gbcExtra.gridx = 0;
+ gbcExtra.gridy = 1;
+ gbcExtra.weightx = 1.0;
+ gbcExtra.fill = GridBagConstraints.HORIZONTAL;
+ add(extra, gbcExtra);
+ }
+ }
+
+ /** Gets an extra component displayed at left below the table.
+ *
By default, this method returns null.
+ * @return A JComponent or null if no component is provided.
+ */
+ protected JComponent getExtraComponent() {
+ return null;
+ }
+
+ /** Gets the table.
+ * @return a Table
+ */
+ public final Table getTable() {
+ if (table == null) {
+ table = buildTable();
+ }
+ return table;
+ }
+
+ /** Gets the save button.
+ * @return a button
+ */
+ public final JButton getSaveButton() {
+ if (saveButton == null) {
+ saveButton = new JButton(Application.getString("ExcelPane.save", getLocale())); //$NON-NLS-1$
+ saveButton.addActionListener(new SaveButtonActionListener());
+ }
+ return saveButton;
+ }
+
+ private final class SaveButtonActionListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ JFileChooser chooser = new FileChooser(getInitialPath()) {
+ private static final long serialVersionUID = 1L;
+ @Override
+ public File getSelectedFile() {
+ File f = super.getSelectedFile();
+ if ((f!=null) && !f.getName().endsWith(CSV_EXTENSION)) {
+ f = new File(f.getParent(), f.getName()+CSV_EXTENSION);
+ }
+ return f;
+ }
+ };
+ chooser.setFileFilter(new FileNameExtensionFilter(Application.getString("ExcelPane.csv.wording", getLocale()),CSV_EXTENSION.substring(1)));
+ File file = chooser.showSaveDialog(ExcelPane.this)==JFileChooser.APPROVE_OPTION?chooser.getSelectedFile():null;
+ if (file!=null) {
+ try {
+ save(file);
+ } catch(IOException ex) {
+ String message = Formatter.format(Application.getString("ExcelPane.error.message", getLocale()), ex.toString()); //$NON-NLS-1$
+ JOptionPane.showMessageDialog(ExcelPane.this, message, Application.getString("Generic.error", getLocale()), JOptionPane.ERROR_MESSAGE); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ /** Gets the initial path of the file chooser.
+ *
This method is called every time the save button is clicked.
+ *
By default, this path is null.
+ * @return The path or null that causes the file chooser to point to the user's default directory
+ */
+ protected String getInitialPath() {
+ return null;
+ }
+
+ /** Saves the pane content to a file.
+ *
This method is called every time the save button is clicked and a file is selected.
+ *
By default, the content is save to the file using the csv exporter.
+ * @param file The file selected by the user to save the data.
+ * @see #getCSVExporter()
+ * @throws IOException If something goes wrong while writing file.
+ */
+ protected void save(File file) throws IOException {
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
+ getCSVExporter().export(writer, getTable().getModel(), true);
+ writer.flush();
+ }
+ }
+
+ /** Gets the CSVExporter used to export the data.
+ * @return a CSVExporter
+ */
+ public final CSVExporter getCSVExporter() {
+ if (this.exporter == null) {
+ exporter = buildExporter();
+ }
+ return this.exporter;
+ }
+
+ /** Builds the table.
+ *
This method is called once.
+ *
You can override this method in order to create a customized Table.
+ * @return a Table
+ */
+ protected Table buildTable() {
+ return new Table();
+ }
+
+ /** Builds the table.
+ *
This method is called once.
+ *
The default implementation returns a default CSVExporter;
+ * @return a CSVExporter
+ * @see CSVExporter
+ */
+ protected CSVExporter buildExporter() {
+ return new CSVExporter();
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/FileSelectionPane.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/FileSelectionPane.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/FileSelectionPane.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/FileSelectionPane.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/HTMLPane.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/HTMLPane.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/HTMLPane.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/HTMLPane.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/IntegerWidget.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/IntegerWidget.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/IntegerWidget.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/IntegerWidget.java
index 032eef9..b984eb7 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/IntegerWidget.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/IntegerWidget.java
@@ -1,185 +1,185 @@
-package com.fathzer.soft.ajlib.swing.widget;
-
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.math.BigInteger;
-
-import com.fathzer.soft.ajlib.utilities.NullUtils;
-
-
-/** This widget is an integer input field.
- *
You can set minimum and maximum values accepted by this field.
- *
The up and down arrows are shortcuts to increase/decrease the value in the field.
- *
It is a java bean, so you can listen to its VALUE_PROPERTY change.
- */
-public class IntegerWidget extends TextWidget {
- private static final long serialVersionUID = 1L;
- /** The field value property name. */
- public static final String VALUE_PROPERTY = "VALUE_PROPERTY";
- /** An utility constant for Integer.MAX_VALUE.
- * @see BigInteger#ZERO
- * @see BigInteger#valueOf(long)
- */
- public static final BigInteger INTEGER_MAX_VALUE = BigInteger.valueOf(Integer.MAX_VALUE);
-
- private BigInteger value;
- private BigInteger maxValue;
- private BigInteger minValue;
-
- /** Constructor.
- * The min and max values are not set
- */
- public IntegerWidget() {
- this(null, null);
- }
-
- /** Constructor.
- * The field is initialized empty, with a null value.
- * @param minValue The field minimum value or null if the field has no minimal value.
- * @param maxValue The field maximum value or null if the field has no maximal value.
- */
- public IntegerWidget(BigInteger minValue, BigInteger maxValue) {
- super();
- if ((minValue!=null)&&(maxValue!=null)&&(minValue.compareTo(maxValue)>0)) {
- throw new IllegalArgumentException();
- }
- this.minValue = minValue;
- this.maxValue = maxValue;
- // Adds a key listener to ignored any invalid characters and to increase/decrease value when up/down arrow key are pressed
- this.addKeyListener(new KeyAdapter() {
- @Override
- public void keyTyped(KeyEvent e) {
- // No car are allowed before a - sign
- if ((getSelectionEnd()=0)) {
- e.consume();
- }
- char car = e.getKeyChar();
- if (car=='-') { // - char is a valid character only if the field accepts value less than zero and in the first place (if there's no other - after the current selection)
- if ((IntegerWidget.this.minValue==null) || (IntegerWidget.this.minValue.compareTo(BigInteger.ZERO)<0)) {
- if (IntegerWidget.this.getSelectionStart()!=0) {
- e.consume(); // No - after first position
- }
- } else {
- e.consume();
- }
- } else if (!Character.isDigit(car)) {
- e.consume();
- }
- }
- @Override
- public void keyPressed(KeyEvent e) {
- if (e.getKeyCode()==KeyEvent.VK_UP) {
- if ((value!=null) && ((IntegerWidget.this.maxValue==null) || (value.compareTo(IntegerWidget.this.maxValue)<0))) {
- setValue(value.add(BigInteger.ONE));
- }
- } else if (e.getKeyCode()==KeyEvent.VK_DOWN) {
- if ((value!=null) && ((IntegerWidget.this.minValue==null) || (value.compareTo(IntegerWidget.this.minValue)>0))) {
- setValue(value.subtract(BigInteger.ONE));
- }
- }
- }
- });
- this.addPropertyChangeListener(TEXT_PROPERTY, new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- updateValue();
- }
- });
- }
-
- private void updateValue() {
- BigInteger old = value;
- String text = this.getText().trim();
- try {
- value = new BigInteger(text);
- if (((this.maxValue!=null)&&(value.compareTo(this.maxValue)>0)) || ((this.minValue!=null)&&(value.compareTo(this.minValue)<0))) {
- // Value is out of bounds
- value = null;
- }
- } catch (NumberFormatException e) {
- value = null;
- }
- if (!NullUtils.areEquals(value,old)) {
- this.firePropertyChange(VALUE_PROPERTY, old, value);
- }
- }
-
- @Override
- public void setText(String t) {
- super.setText(t);
- updateValue();
- }
-
- /** Gets the current value.
- * @return an integer or null if the value is not valid.
- */
- public BigInteger getValue() {
- return this.value==null?null:this.value;
- }
-
- /** Sets the current value.
- * @param value a big integer or null to set the field empty.
- */
- public void setValue(BigInteger value) {
- if (!NullUtils.areEquals(value,this.value)) {
- this.setText(value==null?"":value.toString());
- }
- }
-
- /** Sets the current value.
- * @param value an integer or null to set the field empty.
- */
- public void setValue(Integer value) {
- setValue(value==null?null:BigInteger.valueOf(value));
- }
-
- /** Sets the min value of the widget.
- * @param min the min value.
- *
If the current value is lower than max, the current value is set to null.
- * @throws IllegalArgumentException if min is bigger than widget max value.
- * @see #setRange(BigInteger, BigInteger)
- */
- public void setMinValue(BigInteger min) {
- if (min!=null && maxValue!=null && min.compareTo(maxValue)>0) {
- throw new IllegalArgumentException();
- }
- minValue = min;
- if (value!=null && min!=null && value.compareTo(min)<0) {
- setValue((BigInteger)null);
- }
- }
-
- /** Sets the max value of the widget.
- * @param max the max value.
- *
If the current value is bigger than max, the current value is set to null.
- * @throws IllegalArgumentException if max is lower than widget min value.
- * @see #setRange(BigInteger, BigInteger)
- */
- public void setMaxValue(BigInteger max) {
- if (max!=null && minValue!=null && max.compareTo(minValue)<0) {
- throw new IllegalArgumentException();
- }
- maxValue = max;
- if (value!=null && max!= null && value.compareTo(max)>0) {
- setValue((BigInteger)null);
- }
- }
-
- /** Sets this widget min and max values.
- *
If the current value is out of the new range, the current value is set to null.
- * @param min The min value
- * @param max The max value
- */
- public void setRange(BigInteger min, BigInteger max) {
- if ((min!=null)&&(max!=null)&&(min.compareTo(max)>0)) {
- throw new IllegalArgumentException();
- }
- minValue = min;
- maxValue = max;
- if (value!=null && ((min!=null && value.compareTo(min)<0) || (max!= null && value.compareTo(max)>0))) {
- setValue((BigInteger)null);
- }
- }
-}
+package com.fathzer.soft.ajlib.swing.widget;
+
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.math.BigInteger;
+
+import com.fathzer.soft.ajlib.utilities.NullUtils;
+
+
+/** This widget is an integer input field.
+ *
You can set minimum and maximum values accepted by this field.
+ *
The up and down arrows are shortcuts to increase/decrease the value in the field.
+ *
It is a java bean, so you can listen to its VALUE_PROPERTY change.
+ */
+public class IntegerWidget extends TextWidget {
+ private static final long serialVersionUID = 1L;
+ /** The field value property name. */
+ public static final String VALUE_PROPERTY = "VALUE_PROPERTY";
+ /** An utility constant for Integer.MAX_VALUE.
+ * @see BigInteger#ZERO
+ * @see BigInteger#valueOf(long)
+ */
+ public static final BigInteger INTEGER_MAX_VALUE = BigInteger.valueOf(Integer.MAX_VALUE);
+
+ private BigInteger value;
+ private BigInteger maxValue;
+ private BigInteger minValue;
+
+ /** Constructor.
+ * The min and max values are not set
+ */
+ public IntegerWidget() {
+ this(null, null);
+ }
+
+ /** Constructor.
+ * The field is initialized empty, with a null value.
+ * @param minValue The field minimum value or null if the field has no minimal value.
+ * @param maxValue The field maximum value or null if the field has no maximal value.
+ */
+ public IntegerWidget(BigInteger minValue, BigInteger maxValue) {
+ super();
+ if ((minValue!=null)&&(maxValue!=null)&&(minValue.compareTo(maxValue)>0)) {
+ throw new IllegalArgumentException();
+ }
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ // Adds a key listener to ignored any invalid characters and to increase/decrease value when up/down arrow key are pressed
+ this.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyTyped(KeyEvent e) {
+ // No car are allowed before a - sign
+ if ((getSelectionEnd()=0)) {
+ e.consume();
+ }
+ char car = e.getKeyChar();
+ if (car=='-') { // - char is a valid character only if the field accepts value less than zero and in the first place (if there's no other - after the current selection)
+ if ((IntegerWidget.this.minValue==null) || (IntegerWidget.this.minValue.compareTo(BigInteger.ZERO)<0)) {
+ if (IntegerWidget.this.getSelectionStart()!=0) {
+ e.consume(); // No - after first position
+ }
+ } else {
+ e.consume();
+ }
+ } else if (!Character.isDigit(car)) {
+ e.consume();
+ }
+ }
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.getKeyCode()==KeyEvent.VK_UP) {
+ if ((value!=null) && ((IntegerWidget.this.maxValue==null) || (value.compareTo(IntegerWidget.this.maxValue)<0))) {
+ setValue(value.add(BigInteger.ONE));
+ }
+ } else if (e.getKeyCode()==KeyEvent.VK_DOWN) {
+ if ((value!=null) && ((IntegerWidget.this.minValue==null) || (value.compareTo(IntegerWidget.this.minValue)>0))) {
+ setValue(value.subtract(BigInteger.ONE));
+ }
+ }
+ }
+ });
+ this.addPropertyChangeListener(TEXT_PROPERTY, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ updateValue();
+ }
+ });
+ }
+
+ private void updateValue() {
+ BigInteger old = value;
+ String text = this.getText().trim();
+ try {
+ value = new BigInteger(text);
+ if (((this.maxValue!=null)&&(value.compareTo(this.maxValue)>0)) || ((this.minValue!=null)&&(value.compareTo(this.minValue)<0))) {
+ // Value is out of bounds
+ value = null;
+ }
+ } catch (NumberFormatException e) {
+ value = null;
+ }
+ if (!NullUtils.areEquals(value,old)) {
+ this.firePropertyChange(VALUE_PROPERTY, old, value);
+ }
+ }
+
+ @Override
+ public void setText(String t) {
+ super.setText(t);
+ updateValue();
+ }
+
+ /** Gets the current value.
+ * @return an integer or null if the value is not valid.
+ */
+ public BigInteger getValue() {
+ return this.value==null?null:this.value;
+ }
+
+ /** Sets the current value.
+ * @param value a big integer or null to set the field empty.
+ */
+ public void setValue(BigInteger value) {
+ if (!NullUtils.areEquals(value,this.value)) {
+ this.setText(value==null?"":value.toString());
+ }
+ }
+
+ /** Sets the current value.
+ * @param value an integer or null to set the field empty.
+ */
+ public void setValue(Integer value) {
+ setValue(value==null?null:BigInteger.valueOf(value));
+ }
+
+ /** Sets the min value of the widget.
+ * @param min the min value.
+ *
If the current value is lower than max, the current value is set to null.
+ * @throws IllegalArgumentException if min is bigger than widget max value.
+ * @see #setRange(BigInteger, BigInteger)
+ */
+ public void setMinValue(BigInteger min) {
+ if (min!=null && maxValue!=null && min.compareTo(maxValue)>0) {
+ throw new IllegalArgumentException();
+ }
+ minValue = min;
+ if (value!=null && min!=null && value.compareTo(min)<0) {
+ setValue((BigInteger)null);
+ }
+ }
+
+ /** Sets the max value of the widget.
+ * @param max the max value.
+ *
If the current value is bigger than max, the current value is set to null.
+ * @throws IllegalArgumentException if max is lower than widget min value.
+ * @see #setRange(BigInteger, BigInteger)
+ */
+ public void setMaxValue(BigInteger max) {
+ if (max!=null && minValue!=null && max.compareTo(minValue)<0) {
+ throw new IllegalArgumentException();
+ }
+ maxValue = max;
+ if (value!=null && max!= null && value.compareTo(max)>0) {
+ setValue((BigInteger)null);
+ }
+ }
+
+ /** Sets this widget min and max values.
+ *
If the current value is out of the new range, the current value is set to null.
+ * @param min The min value
+ * @param max The max value
+ */
+ public void setRange(BigInteger min, BigInteger max) {
+ if ((min!=null)&&(max!=null)&&(min.compareTo(max)>0)) {
+ throw new IllegalArgumentException();
+ }
+ minValue = min;
+ maxValue = max;
+ if (value!=null && ((min!=null && value.compareTo(min)<0) || (max!= null && value.compareTo(max)>0))) {
+ setValue((BigInteger)null);
+ }
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/NumberWidget.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/NumberWidget.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/NumberWidget.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/NumberWidget.java
index 647f6db..7c71b19 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/NumberWidget.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/NumberWidget.java
@@ -1,288 +1,288 @@
-package com.fathzer.soft.ajlib.swing.widget;
-
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.lang.reflect.InvocationTargetException;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.text.NumberFormat;
-import java.text.ParsePosition;
-import java.util.Locale;
-
-import com.fathzer.soft.ajlib.utilities.NullUtils;
-
-
-/** A widget to enter a number.
- *
This widget automatically format the value it contains according to its local.
- *
You can restrict the valid values by setting minimum and maximum values.
- *
This bean defines two properties:
- * - VALUE_PROPERTY: a double, the value currently entered in the field.
- * - CONTENT_VALID_PROPERTY: a boolean, true if the text currently entered in the field is a valid value, false if it is not.
- *
The CONTENT_VALID_PROPERTY is a read only property.
- *
- */
-public class NumberWidget extends TextWidget {
- private static final long serialVersionUID = 1L;
- private static final char NON_BREAKING_SPACE = 0x00A0;
- private static final char NARROW_NON_BREAKING_SPACE = 0x202F;
- private static final char SPACE = ' ';
-
- /** Value property identifier. */
- public static final String VALUE_PROPERTY = "value";
- /** Content validity property identifier. */
- public static final String CONTENT_VALID_PROPERTY = "contentValid";
-
- private Number value;
- /** The format used to parse the number. */
- private DecimalFormat format;
- private boolean isEmptyAllowed;
- private Number minValue;
- private Number maxValue;
- private boolean valid;
-
- /** Constructor.
- * The local is set to default locale.
- * @see #NumberWidget(Locale)
- */
- public NumberWidget() {
- this(Locale.getDefault());
- }
-
- /** Constructor.
- * Empty field is not allowed.
- * minValue is equals to Double.NEGATIVE_INFINITY, maxValue to Double.POSITIVE_INFINITY.
- * The value is set to null.
- * @param locale The locale to apply to the widget (use to format the amount typed).
- */
- public NumberWidget(Locale locale) {
- super();
- this.isEmptyAllowed = false;
- this.minValue = Double.NEGATIVE_INFINITY;
- this.maxValue = Double.POSITIVE_INFINITY;
- format = buildFormat(locale);
- this.addPropertyChangeListener(TEXT_PROPERTY, new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- updateValue();
- }
- });
- this.addFocusListener(new FocusListener() {
- @Override
- public void focusLost(FocusEvent e) {
- if (!e.isTemporary()) {
- refreshText(value);
- }
- }
- @Override
- public void focusGained(FocusEvent e) {
- // Nothing to do
- }
- });
- }
-
- /** Workaround of a weird java implementation (The bug id was 4510618, but it was removed despite not being fixed).
- *
In some locals (French for instance), the grouping or decimal separators are a non breaking space or a narrow non breaking space,
- * (depending on java version!!!) ... not a single space.
- * Users may be very surprised to see that in France, "1 000,00" is not a number.
- *
To make things easy, Java did not provide any method for getting or setting the effective grouping separator of currency instance until java 15.
- *
In one word: Nightmare!
- *
This method changes non breaking spaces in the format symbol by simple spaces.
- *
When the user type a non breaking space, it is automatically converted to a simple space before to be passed
- * to the parseValue method. So, it is highly recommended that this method is applied on the format returned by buildFormat.
- * @param format The format to patch
- * @return the modified input format.
- * @see #buildFormat(Locale)
- * @see #parseValue(String)
- */
- protected DecimalFormat patchJavaBug4510618 (DecimalFormat format) {
- DecimalFormatSymbols decimalFormatSymbols = format.getDecimalFormatSymbols();
- if (isNonBreakingSpaceFlavor(decimalFormatSymbols.getGroupingSeparator())) {
- decimalFormatSymbols.setGroupingSeparator(SPACE);
- }
- if (isNonBreakingSpaceFlavor(decimalFormatSymbols.getDecimalSeparator())) {
- decimalFormatSymbols.setDecimalSeparator(SPACE);
- }
- if (isNonBreakingSpaceFlavor(decimalFormatSymbols.getMonetaryDecimalSeparator())) {
- decimalFormatSymbols.setMonetaryDecimalSeparator(SPACE);
- }
- // Until Java 15, there was nothing to set monetary grouping separator, hopefully no need in Java 8 and 11, other pre-15 versions reached their end of life.
- try {
- char sep = (Character)decimalFormatSymbols.getClass().getDeclaredMethod("getMonetaryGroupingSeparator").invoke(decimalFormatSymbols);
- if (isNonBreakingSpaceFlavor(sep)) {
- decimalFormatSymbols.getClass().getDeclaredMethod("setMonetaryGroupingSeparator", char.class).invoke(decimalFormatSymbols, SPACE);
- }
- } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
- // Fucking java < 15
- }
- format.setDecimalFormatSymbols(decimalFormatSymbols);
- format.setPositiveSuffix(replaceNonBreakingSpaces(format.getPositiveSuffix()));
- format.setNegativeSuffix(replaceNonBreakingSpaces(format.getNegativeSuffix()));
- format.setPositivePrefix(replaceNonBreakingSpaces(format.getPositivePrefix()));
- format.setNegativePrefix(replaceNonBreakingSpaces(format.getNegativePrefix()));
- return format;
- }
-
- private boolean isNonBreakingSpaceFlavor(char character) {
- return character==NON_BREAKING_SPACE || character==NARROW_NON_BREAKING_SPACE;
- }
-
- private String replaceNonBreakingSpaces(String string) {
- return string.replace(NON_BREAKING_SPACE, SPACE).replace(NARROW_NON_BREAKING_SPACE, SPACE);
- }
-
- protected DecimalFormat buildFormat(Locale locale) {
- return patchJavaBug4510618((DecimalFormat) NumberFormat.getNumberInstance(locale));
- }
-
- protected void setFormat (DecimalFormat format) {
- this.format = format;
- }
-
- protected DecimalFormat getFormat() {
- return this.format;
- }
-
- protected void refreshText() {
- refreshText(value);
- }
-
- private void refreshText(Number value) {
- this.setText(value==null?"":format.format(value));
- }
-
- private void updateValue() {
- boolean oldValid = this.valid;
- Number changed = null;
- String text = this.getText().trim();
- if (text.length()==0) {
- this.valid = isEmptyAllowed;
- } else {
- changed = parseValue(text.replace(NON_BREAKING_SPACE, SPACE).replace(NARROW_NON_BREAKING_SPACE, SPACE));
- this.valid = (changed!=null) && (changed.doubleValue()>=minValue.doubleValue()) && (changed.doubleValue()<=maxValue.doubleValue());
- }
- internalSetValue(changed==null?null:changed.doubleValue());
- if (this.valid!=oldValid) {
- firePropertyChange(CONTENT_VALID_PROPERTY, oldValid, this.valid);
- }
- }
-
- /** Parses the text contained in the field.
- *
This method is called each time the field is modified.
- * @param text The trimmed text contained in the field
- * @return The value of the text or null if the text can't be parsed as a number.
- */
- protected Number parseValue(String text) {
- return safeParse(format, text);
- }
-
- /** Parses a text with a format and ensures the text has no extra characters after valid data.
- *
We have to be cautious with parsing. If the text begins with a valid number but is followed by garbage,
- * format.parse(String) will succeed !!! This method uses format.parse(String, ParsePosition) in order to detect
- * garbage placed after a valid number.
- * @param format The format to use for parsing
- * @param text The text to be parsed
- * @return A number, or null if the text is not valid according to the format
- */
- public static Number safeParse(NumberFormat format, String text) {
- ParsePosition pos = new ParsePosition(0);
- Number candidate = format.parse(text, pos);
- if (pos.getIndex()==text.length()) {
- return candidate;
- } else {
- return null;
- }
- }
-
- /** Determines whether empty text (or blank) are considered as valid or not.
- * @return true if blank field is valid.
- */
- public boolean isEmptyAllowed() {
- return isEmptyAllowed;
- }
-
- /** Sets the validity of blank text.
- * @param isEmptyAllowed true if blank text are allowed, false if not.
- * The value associated with a blank field is always null.
- */
- public void setEmptyAllowed(boolean isEmptyAllowed) {
- this.isEmptyAllowed = isEmptyAllowed;
- if (this.getText().trim().length()==0) {
- updateValue();
- }
- }
-
- /** Gets the minimum value allowed in the field.
- * @return a double (Double.NEGATIVE_INFINITY if there is no limit)
- */
- public Double getMinValue() {
- return minValue.doubleValue();
- }
-
- /** Sets the minimum value allowed in the field.
- * @param minValue a double (Double.NEGATIVE_INFINITY if there is no limit)
- */
- public void setMinValue(Double minValue) {
- this.minValue = minValue;
- }
-
- /** Gets the maximum value allowed in the field.
- * @return a double (Double.POSITIVE_INFINITY if there is no limit)
- */
- public Double getMaxValue() {
- return maxValue.doubleValue();
- }
-
- /** Sets the maximum value allowed in the field.
- * @param maxValue a double (Double.POSITIVE_INFINITY if there is no limit)
- */
- public void setMaxValue(Double maxValue) {
- this.maxValue = maxValue;
- }
-
- /** Gets the current value.
- * @return a number or null.
- */
- public Double getValue() {
- updateValue();
- return this.value==null?null: this.value.doubleValue();
- }
-
- /** Sets the current value.
- * @param value a value, or null.
- */
- public void setValue(Double value) {
- refreshText(value);
- }
-
- @Override
- public void setText(String t) {
- super.setText(t);
- updateValue();
- }
-
- /** Set the value without changing the content of the TextField.
- * This method does nothing if the value is equals to the current widget value.
- * @param value
- * @return true if the value was changed
- */
- private boolean internalSetValue(Double value) {
- // Does nothing if amount is equals to current widget amount
- // Be aware of null values
- if (NullUtils.areEquals(value, this.value)) {
- return false;
- }
- Number old = this.value;
- this.value = value;
- firePropertyChange(VALUE_PROPERTY, old, value);
- return true;
- }
-
- /** Gets the content validity.
- * @return true if the content is valid, false if it is not.
- */
- public boolean isContentValid() {
- return this.valid;
- }
-}
+package com.fathzer.soft.ajlib.swing.widget;
+
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.lang.reflect.InvocationTargetException;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+import com.fathzer.soft.ajlib.utilities.NullUtils;
+
+
+/** A widget to enter a number.
+ *
This widget automatically format the value it contains according to its local.
+ *
You can restrict the valid values by setting minimum and maximum values.
+ *
This bean defines two properties:
+ * - VALUE_PROPERTY: a double, the value currently entered in the field.
+ * - CONTENT_VALID_PROPERTY: a boolean, true if the text currently entered in the field is a valid value, false if it is not.
+ *
The CONTENT_VALID_PROPERTY is a read only property.
+ *
+ */
+public class NumberWidget extends TextWidget {
+ private static final long serialVersionUID = 1L;
+ private static final char NON_BREAKING_SPACE = 0x00A0;
+ private static final char NARROW_NON_BREAKING_SPACE = 0x202F;
+ private static final char SPACE = ' ';
+
+ /** Value property identifier. */
+ public static final String VALUE_PROPERTY = "value";
+ /** Content validity property identifier. */
+ public static final String CONTENT_VALID_PROPERTY = "contentValid";
+
+ private Number value;
+ /** The format used to parse the number. */
+ private DecimalFormat format;
+ private boolean isEmptyAllowed;
+ private Number minValue;
+ private Number maxValue;
+ private boolean valid;
+
+ /** Constructor.
+ * The local is set to default locale.
+ * @see #NumberWidget(Locale)
+ */
+ public NumberWidget() {
+ this(Locale.getDefault());
+ }
+
+ /** Constructor.
+ * Empty field is not allowed.
+ * minValue is equals to Double.NEGATIVE_INFINITY, maxValue to Double.POSITIVE_INFINITY.
+ * The value is set to null.
+ * @param locale The locale to apply to the widget (use to format the amount typed).
+ */
+ public NumberWidget(Locale locale) {
+ super();
+ this.isEmptyAllowed = false;
+ this.minValue = Double.NEGATIVE_INFINITY;
+ this.maxValue = Double.POSITIVE_INFINITY;
+ format = buildFormat(locale);
+ this.addPropertyChangeListener(TEXT_PROPERTY, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ updateValue();
+ }
+ });
+ this.addFocusListener(new FocusListener() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (!e.isTemporary()) {
+ refreshText(value);
+ }
+ }
+ @Override
+ public void focusGained(FocusEvent e) {
+ // Nothing to do
+ }
+ });
+ }
+
+ /** Workaround of a weird java implementation (The bug id was 4510618, but it was removed despite not being fixed).
+ *
In some locals (French for instance), the grouping or decimal separators are a non breaking space or a narrow non breaking space,
+ * (depending on java version!!!) ... not a single space.
+ * Users may be very surprised to see that in France, "1 000,00" is not a number.
+ *
To make things easy, Java did not provide any method for getting or setting the effective grouping separator of currency instance until java 15.
+ *
In one word: Nightmare!
+ *
This method changes non breaking spaces in the format symbol by simple spaces.
+ *
When the user type a non breaking space, it is automatically converted to a simple space before to be passed
+ * to the parseValue method. So, it is highly recommended that this method is applied on the format returned by buildFormat.
+ * @param format The format to patch
+ * @return the modified input format.
+ * @see #buildFormat(Locale)
+ * @see #parseValue(String)
+ */
+ protected DecimalFormat patchJavaBug4510618 (DecimalFormat format) {
+ DecimalFormatSymbols decimalFormatSymbols = format.getDecimalFormatSymbols();
+ if (isNonBreakingSpaceFlavor(decimalFormatSymbols.getGroupingSeparator())) {
+ decimalFormatSymbols.setGroupingSeparator(SPACE);
+ }
+ if (isNonBreakingSpaceFlavor(decimalFormatSymbols.getDecimalSeparator())) {
+ decimalFormatSymbols.setDecimalSeparator(SPACE);
+ }
+ if (isNonBreakingSpaceFlavor(decimalFormatSymbols.getMonetaryDecimalSeparator())) {
+ decimalFormatSymbols.setMonetaryDecimalSeparator(SPACE);
+ }
+ // Until Java 15, there was nothing to set monetary grouping separator, hopefully no need in Java 8 and 11, other pre-15 versions reached their end of life.
+ try {
+ char sep = (Character)decimalFormatSymbols.getClass().getDeclaredMethod("getMonetaryGroupingSeparator").invoke(decimalFormatSymbols);
+ if (isNonBreakingSpaceFlavor(sep)) {
+ decimalFormatSymbols.getClass().getDeclaredMethod("setMonetaryGroupingSeparator", char.class).invoke(decimalFormatSymbols, SPACE);
+ }
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+ // Fucking java < 15
+ }
+ format.setDecimalFormatSymbols(decimalFormatSymbols);
+ format.setPositiveSuffix(replaceNonBreakingSpaces(format.getPositiveSuffix()));
+ format.setNegativeSuffix(replaceNonBreakingSpaces(format.getNegativeSuffix()));
+ format.setPositivePrefix(replaceNonBreakingSpaces(format.getPositivePrefix()));
+ format.setNegativePrefix(replaceNonBreakingSpaces(format.getNegativePrefix()));
+ return format;
+ }
+
+ private boolean isNonBreakingSpaceFlavor(char character) {
+ return character==NON_BREAKING_SPACE || character==NARROW_NON_BREAKING_SPACE;
+ }
+
+ private String replaceNonBreakingSpaces(String string) {
+ return string.replace(NON_BREAKING_SPACE, SPACE).replace(NARROW_NON_BREAKING_SPACE, SPACE);
+ }
+
+ protected DecimalFormat buildFormat(Locale locale) {
+ return patchJavaBug4510618((DecimalFormat) NumberFormat.getNumberInstance(locale));
+ }
+
+ protected void setFormat (DecimalFormat format) {
+ this.format = format;
+ }
+
+ protected DecimalFormat getFormat() {
+ return this.format;
+ }
+
+ protected void refreshText() {
+ refreshText(value);
+ }
+
+ private void refreshText(Number value) {
+ this.setText(value==null?"":format.format(value));
+ }
+
+ private void updateValue() {
+ boolean oldValid = this.valid;
+ Number changed = null;
+ String text = this.getText().trim();
+ if (text.length()==0) {
+ this.valid = isEmptyAllowed;
+ } else {
+ changed = parseValue(text.replace(NON_BREAKING_SPACE, SPACE).replace(NARROW_NON_BREAKING_SPACE, SPACE));
+ this.valid = (changed!=null) && (changed.doubleValue()>=minValue.doubleValue()) && (changed.doubleValue()<=maxValue.doubleValue());
+ }
+ internalSetValue(changed==null?null:changed.doubleValue());
+ if (this.valid!=oldValid) {
+ firePropertyChange(CONTENT_VALID_PROPERTY, oldValid, this.valid);
+ }
+ }
+
+ /** Parses the text contained in the field.
+ *
This method is called each time the field is modified.
+ * @param text The trimmed text contained in the field
+ * @return The value of the text or null if the text can't be parsed as a number.
+ */
+ protected Number parseValue(String text) {
+ return safeParse(format, text);
+ }
+
+ /** Parses a text with a format and ensures the text has no extra characters after valid data.
+ *
We have to be cautious with parsing. If the text begins with a valid number but is followed by garbage,
+ * format.parse(String) will succeed !!! This method uses format.parse(String, ParsePosition) in order to detect
+ * garbage placed after a valid number.
+ * @param format The format to use for parsing
+ * @param text The text to be parsed
+ * @return A number, or null if the text is not valid according to the format
+ */
+ public static Number safeParse(NumberFormat format, String text) {
+ ParsePosition pos = new ParsePosition(0);
+ Number candidate = format.parse(text, pos);
+ if (pos.getIndex()==text.length()) {
+ return candidate;
+ } else {
+ return null;
+ }
+ }
+
+ /** Determines whether empty text (or blank) are considered as valid or not.
+ * @return true if blank field is valid.
+ */
+ public boolean isEmptyAllowed() {
+ return isEmptyAllowed;
+ }
+
+ /** Sets the validity of blank text.
+ * @param isEmptyAllowed true if blank text are allowed, false if not.
+ * The value associated with a blank field is always null.
+ */
+ public void setEmptyAllowed(boolean isEmptyAllowed) {
+ this.isEmptyAllowed = isEmptyAllowed;
+ if (this.getText().trim().length()==0) {
+ updateValue();
+ }
+ }
+
+ /** Gets the minimum value allowed in the field.
+ * @return a double (Double.NEGATIVE_INFINITY if there is no limit)
+ */
+ public Double getMinValue() {
+ return minValue.doubleValue();
+ }
+
+ /** Sets the minimum value allowed in the field.
+ * @param minValue a double (Double.NEGATIVE_INFINITY if there is no limit)
+ */
+ public void setMinValue(Double minValue) {
+ this.minValue = minValue;
+ }
+
+ /** Gets the maximum value allowed in the field.
+ * @return a double (Double.POSITIVE_INFINITY if there is no limit)
+ */
+ public Double getMaxValue() {
+ return maxValue.doubleValue();
+ }
+
+ /** Sets the maximum value allowed in the field.
+ * @param maxValue a double (Double.POSITIVE_INFINITY if there is no limit)
+ */
+ public void setMaxValue(Double maxValue) {
+ this.maxValue = maxValue;
+ }
+
+ /** Gets the current value.
+ * @return a number or null.
+ */
+ public Double getValue() {
+ updateValue();
+ return this.value==null?null: this.value.doubleValue();
+ }
+
+ /** Sets the current value.
+ * @param value a value, or null.
+ */
+ public void setValue(Double value) {
+ refreshText(value);
+ }
+
+ @Override
+ public void setText(String t) {
+ super.setText(t);
+ updateValue();
+ }
+
+ /** Set the value without changing the content of the TextField.
+ * This method does nothing if the value is equals to the current widget value.
+ * @param value
+ * @return true if the value was changed
+ */
+ private boolean internalSetValue(Double value) {
+ // Does nothing if amount is equals to current widget amount
+ // Be aware of null values
+ if (NullUtils.areEquals(value, this.value)) {
+ return false;
+ }
+ Number old = this.value;
+ this.value = value;
+ firePropertyChange(VALUE_PROPERTY, old, value);
+ return true;
+ }
+
+ /** Gets the content validity.
+ * @return true if the content is valid, false if it is not.
+ */
+ public boolean isContentValid() {
+ return this.valid;
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/PageSelector.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/PageSelector.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/PageSelector.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/PageSelector.java
index 968a769..3c2cf61 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/PageSelector.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/PageSelector.java
@@ -1,241 +1,241 @@
-package com.fathzer.soft.ajlib.swing.widget;
-
-import java.awt.Dimension;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.math.BigInteger;
-
-import javax.swing.JButton;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-
-import com.fathzer.soft.ajlib.swing.Utils;
-
-/** A widget that allows to select a page in a specified range.
- */
-public class PageSelector extends JPanel {
- private static final String RES_PATH = "/com/fathzer/soft/ajlib/swing/widget/";
- public static final String PAGE_SELECTED_PROPERTY_NAME = "PageSelected";
- private static final long serialVersionUID = 1L;
-
- private IntegerWidget pageNumber;
- private JButton nextPage;
- private JButton lastPage;
- private JButton previousPage;
- private JButton firstPage;
- private int pageCount;
- private int currentPage;
- private JLabel sizeLabel;
-
- /**
- * Constructor.
- */
- public PageSelector() {
- this.pageCount = 0;
- this.currentPage = -1;
- setLayout(new GridBagLayout());
- setOpaque(false);
-
- GridBagConstraints gbcFirstPage = new GridBagConstraints();
- gbcFirstPage.insets = new Insets(0, 0, 0, 5);
- gbcFirstPage.weighty = 1.0;
- gbcFirstPage.fill = GridBagConstraints.VERTICAL;
- gbcFirstPage.gridx = 1;
- gbcFirstPage.gridy = 0;
- add(getFirstPage(), gbcFirstPage);
-
- GridBagConstraints gbcPageNumber = new GridBagConstraints();
- gbcPageNumber.gridx = 3;
- gbcPageNumber.gridy = 0;
- gbcPageNumber.fill = GridBagConstraints.VERTICAL;
- add(getPageNumber(), gbcPageNumber);
-
- sizeLabel = new JLabel("/"+pageCount);
- GridBagConstraints gbcLabel = new GridBagConstraints();
- gbcLabel.insets = new Insets(0, 0, 0, 5);
- gbcLabel.gridx = 4;
- gbcLabel.gridy = 0;
- add(sizeLabel, gbcLabel);
-
- GridBagConstraints gbcNextPage = new GridBagConstraints();
- gbcNextPage.fill = GridBagConstraints.VERTICAL;
- gbcNextPage.insets = new Insets(0, 0, 0, 5);
- gbcNextPage.gridx = 5;
- gbcNextPage.gridy = 0;
- add(getNextPage(), gbcNextPage);
-
- GridBagConstraints gbcLastPage = new GridBagConstraints();
- gbcLastPage.fill = GridBagConstraints.VERTICAL;
- gbcLastPage.gridx = 6;
- gbcLastPage.gridy = 0;
- add(getLastPage(), gbcLastPage);
-
- GridBagConstraints gbcPreviousPage = new GridBagConstraints();
- gbcPreviousPage.fill = GridBagConstraints.VERTICAL;
- gbcPreviousPage.insets = new Insets(0, 0, 0, 5);
- gbcPreviousPage.gridx = 2;
- gbcPreviousPage.gridy = 0;
- add(getPreviousPage(), gbcPreviousPage);
-
- restoreButtonStates();
- }
-
- /** Gets "page number" field.
- * @return an IntegerWidget
- */
- public IntegerWidget getPageNumber() {
- if (pageNumber==null) {
- pageNumber = new IntegerWidget(pageCount==0?BigInteger.ZERO:BigInteger.ONE, BigInteger.valueOf(pageCount));
- pageNumber.setColumns(2);
- pageNumber.addPropertyChangeListener(IntegerWidget.VALUE_PROPERTY, new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- if (evt.getNewValue()!=null) {
- setPage(((BigInteger)evt.getNewValue()).intValue()-1);
- } else {
- setPage(-1);
- }
- }
- });
- }
- return pageNumber;
- }
-
- /** Gets "Go to next page" button.
- * @return a JButton
- */
- public JButton getNextPage() {
- if (nextPage==null) {
- nextPage = new JButton();
- nextPage.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- setPage(getCurrentPage()+1);
- }
- });
- nextPage.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"next.png"), 16*getFont().getSize()/12));
- setSelectionButtonSize(nextPage);
- }
- return nextPage;
- }
-
- /** Gets "Go to last page" button.
- * @return a JButton
- */
- public JButton getLastPage() {
- if (lastPage==null) {
- lastPage = new JButton();
- lastPage.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- setPage(pageCount-1);
- }
- });
- lastPage.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"last.png"), 16*getFont().getSize()/12));
- setSelectionButtonSize(lastPage);
- }
- return lastPage;
- }
-
- /** Gets "Go to previous page" button.
- * @return a JButton
- */
- public JButton getPreviousPage() {
- if (previousPage==null) {
- previousPage = new JButton();
- previousPage.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- setPage(getCurrentPage()-1);
- }
- });
- previousPage.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"previous.png"), 16*getFont().getSize()/12));
- setSelectionButtonSize(previousPage);
- }
- return previousPage;
- }
-
- /** Gets "Go to first page" button.
- * @return a JButton
- */
- public JButton getFirstPage() {
- if (firstPage==null) {
- firstPage = new JButton();
- firstPage.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- setPage(0);
- }
- });
- firstPage.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"first.png"), 16*getFont().getSize()/12));
- setSelectionButtonSize(firstPage);
- }
- return firstPage;
- }
-
- /** Sets the current page index.
- * @param index The index of the page (should be in the range 0 - page count-1)
- * or -1 to specify that no page is selected.
- * @throws IllegalArgumentException If index is not in the range [-1,getPageCount()-1].
- */
- public void setPage(int index) {
- if (index>=getPageCount() || index<-1) {
- throw new IllegalArgumentException();
- }
- int old = getCurrentPage();
- if (index!=old) {
- currentPage = index;
- pageNumber.setValue(index<0?null:index+1);
- restoreButtonStates();
- firePropertyChange(PAGE_SELECTED_PROPERTY_NAME, old, currentPage);
- }
- }
-
- private void restoreButtonStates() {
- firstPage.setEnabled(getCurrentPage()>0);
- previousPage.setEnabled(getCurrentPage()>0);
- nextPage.setEnabled(getCurrentPage()=pageCount) {
- setPage(pageCount-1);
- } else {
- restoreButtonStates();
- }
- }
-
- /** Gets the current page number.
- * @return the current page number (0 based) or -1 if no page is currently selected.
- */
- public int getCurrentPage() {
- return currentPage;
- }
-
- /** Gets the page count.
- * @return a positive or null integer.
- */
- public int getPageCount() {
- return this.pageCount;
- }
-}
+package com.fathzer.soft.ajlib.swing.widget;
+
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.math.BigInteger;
+
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import com.fathzer.soft.ajlib.swing.Utils;
+
+/** A widget that allows to select a page in a specified range.
+ */
+public class PageSelector extends JPanel {
+ private static final String RES_PATH = "/com/fathzer/soft/ajlib/swing/widget/";
+ public static final String PAGE_SELECTED_PROPERTY_NAME = "PageSelected";
+ private static final long serialVersionUID = 1L;
+
+ private IntegerWidget pageNumber;
+ private JButton nextPage;
+ private JButton lastPage;
+ private JButton previousPage;
+ private JButton firstPage;
+ private int pageCount;
+ private int currentPage;
+ private JLabel sizeLabel;
+
+ /**
+ * Constructor.
+ */
+ public PageSelector() {
+ this.pageCount = 0;
+ this.currentPage = -1;
+ setLayout(new GridBagLayout());
+ setOpaque(false);
+
+ GridBagConstraints gbcFirstPage = new GridBagConstraints();
+ gbcFirstPage.insets = new Insets(0, 0, 0, 5);
+ gbcFirstPage.weighty = 1.0;
+ gbcFirstPage.fill = GridBagConstraints.VERTICAL;
+ gbcFirstPage.gridx = 1;
+ gbcFirstPage.gridy = 0;
+ add(getFirstPage(), gbcFirstPage);
+
+ GridBagConstraints gbcPageNumber = new GridBagConstraints();
+ gbcPageNumber.gridx = 3;
+ gbcPageNumber.gridy = 0;
+ gbcPageNumber.fill = GridBagConstraints.VERTICAL;
+ add(getPageNumber(), gbcPageNumber);
+
+ sizeLabel = new JLabel("/"+pageCount);
+ GridBagConstraints gbcLabel = new GridBagConstraints();
+ gbcLabel.insets = new Insets(0, 0, 0, 5);
+ gbcLabel.gridx = 4;
+ gbcLabel.gridy = 0;
+ add(sizeLabel, gbcLabel);
+
+ GridBagConstraints gbcNextPage = new GridBagConstraints();
+ gbcNextPage.fill = GridBagConstraints.VERTICAL;
+ gbcNextPage.insets = new Insets(0, 0, 0, 5);
+ gbcNextPage.gridx = 5;
+ gbcNextPage.gridy = 0;
+ add(getNextPage(), gbcNextPage);
+
+ GridBagConstraints gbcLastPage = new GridBagConstraints();
+ gbcLastPage.fill = GridBagConstraints.VERTICAL;
+ gbcLastPage.gridx = 6;
+ gbcLastPage.gridy = 0;
+ add(getLastPage(), gbcLastPage);
+
+ GridBagConstraints gbcPreviousPage = new GridBagConstraints();
+ gbcPreviousPage.fill = GridBagConstraints.VERTICAL;
+ gbcPreviousPage.insets = new Insets(0, 0, 0, 5);
+ gbcPreviousPage.gridx = 2;
+ gbcPreviousPage.gridy = 0;
+ add(getPreviousPage(), gbcPreviousPage);
+
+ restoreButtonStates();
+ }
+
+ /** Gets "page number" field.
+ * @return an IntegerWidget
+ */
+ public IntegerWidget getPageNumber() {
+ if (pageNumber==null) {
+ pageNumber = new IntegerWidget(pageCount==0?BigInteger.ZERO:BigInteger.ONE, BigInteger.valueOf(pageCount));
+ pageNumber.setColumns(2);
+ pageNumber.addPropertyChangeListener(IntegerWidget.VALUE_PROPERTY, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (evt.getNewValue()!=null) {
+ setPage(((BigInteger)evt.getNewValue()).intValue()-1);
+ } else {
+ setPage(-1);
+ }
+ }
+ });
+ }
+ return pageNumber;
+ }
+
+ /** Gets "Go to next page" button.
+ * @return a JButton
+ */
+ public JButton getNextPage() {
+ if (nextPage==null) {
+ nextPage = new JButton();
+ nextPage.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ setPage(getCurrentPage()+1);
+ }
+ });
+ nextPage.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"next.png"), 16*getFont().getSize()/12));
+ setSelectionButtonSize(nextPage);
+ }
+ return nextPage;
+ }
+
+ /** Gets "Go to last page" button.
+ * @return a JButton
+ */
+ public JButton getLastPage() {
+ if (lastPage==null) {
+ lastPage = new JButton();
+ lastPage.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ setPage(pageCount-1);
+ }
+ });
+ lastPage.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"last.png"), 16*getFont().getSize()/12));
+ setSelectionButtonSize(lastPage);
+ }
+ return lastPage;
+ }
+
+ /** Gets "Go to previous page" button.
+ * @return a JButton
+ */
+ public JButton getPreviousPage() {
+ if (previousPage==null) {
+ previousPage = new JButton();
+ previousPage.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ setPage(getCurrentPage()-1);
+ }
+ });
+ previousPage.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"previous.png"), 16*getFont().getSize()/12));
+ setSelectionButtonSize(previousPage);
+ }
+ return previousPage;
+ }
+
+ /** Gets "Go to first page" button.
+ * @return a JButton
+ */
+ public JButton getFirstPage() {
+ if (firstPage==null) {
+ firstPage = new JButton();
+ firstPage.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ setPage(0);
+ }
+ });
+ firstPage.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"first.png"), 16*getFont().getSize()/12));
+ setSelectionButtonSize(firstPage);
+ }
+ return firstPage;
+ }
+
+ /** Sets the current page index.
+ * @param index The index of the page (should be in the range 0 - page count-1)
+ * or -1 to specify that no page is selected.
+ * @throws IllegalArgumentException If index is not in the range [-1,getPageCount()-1].
+ */
+ public void setPage(int index) {
+ if (index>=getPageCount() || index<-1) {
+ throw new IllegalArgumentException();
+ }
+ int old = getCurrentPage();
+ if (index!=old) {
+ currentPage = index;
+ pageNumber.setValue(index<0?null:index+1);
+ restoreButtonStates();
+ firePropertyChange(PAGE_SELECTED_PROPERTY_NAME, old, currentPage);
+ }
+ }
+
+ private void restoreButtonStates() {
+ firstPage.setEnabled(getCurrentPage()>0);
+ previousPage.setEnabled(getCurrentPage()>0);
+ nextPage.setEnabled(getCurrentPage()=pageCount) {
+ setPage(pageCount-1);
+ } else {
+ restoreButtonStates();
+ }
+ }
+
+ /** Gets the current page number.
+ * @return the current page number (0 based) or -1 if no page is currently selected.
+ */
+ public int getCurrentPage() {
+ return currentPage;
+ }
+
+ /** Gets the page count.
+ * @return a positive or null integer.
+ */
+ public int getPageCount() {
+ return this.pageCount;
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/PasswordWidget.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/PasswordWidget.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/PasswordWidget.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/PasswordWidget.java
index 6f24439..b5c9af9 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/PasswordWidget.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/PasswordWidget.java
@@ -1,60 +1,60 @@
-package com.fathzer.soft.ajlib.swing.widget;
-
-import javax.swing.JPasswordField;
-import javax.swing.text.AttributeSet;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.PlainDocument;
-
-/** A JPasswordField with a property that maps its text.
- *
I've found no way to track efficiently the modifications of the text of a JTextField ... so I developed this widget.
- *
DocumentListeners are intended to do it, unfortunately, when a text is replace in a field, the listener receive two events:
- * - One when the replaced text is removed.
- * - One when the replacing text is inserted
- *
- * The first event is ... simply absolutely misleading, it corresponds to a value that the text never had.
- *
Another problem with DocumentListener is that you can't modify the text into it (it throws IllegalStateException).
- *
Another way was to use KeyListeners ... but some key events are throw a long time (probably the key auto-repeat interval)
- * after the key was released. And others events (for example a click on an OK button) may occurs before the listener is informed of the change.
- *
This widget guarantees that no "ghost" property change is thrown !
- */
-public class PasswordWidget extends JPasswordField {
- private static final long serialVersionUID = 1L;
-
- public static final String TEXT_PROPERTY = "text";
-
- public PasswordWidget() {
- this(0);
- }
-
- public PasswordWidget(int nbColumns) {
- super("", nbColumns);
- this.setDocument(new MyDocument());
- }
-
- @SuppressWarnings("serial")
- private class MyDocument extends PlainDocument {
- private boolean ignoreEvents = false;
-
- @Override
- public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
- String oldValue = new String(PasswordWidget.this.getPassword());
- this.ignoreEvents = true;
- super.replace(offset, length, text, attrs);
- this.ignoreEvents = false;
- String newValue = new String(PasswordWidget.this.getPassword());
- if (!oldValue.equals(newValue)) {
- PasswordWidget.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue);
- }
- }
-
- @Override
- public void remove(int offs, int len) throws BadLocationException {
- String oldValue = new String(PasswordWidget.this.getPassword());
- super.remove(offs, len);
- String newValue = new String(PasswordWidget.this.getPassword());
- if (!ignoreEvents && !oldValue.equals(newValue)) {
- PasswordWidget.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue);
- }
- }
- }
-}
+package com.fathzer.soft.ajlib.swing.widget;
+
+import javax.swing.JPasswordField;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.PlainDocument;
+
+/** A JPasswordField with a property that maps its text.
+ *
I've found no way to track efficiently the modifications of the text of a JTextField ... so I developed this widget.
+ *
DocumentListeners are intended to do it, unfortunately, when a text is replace in a field, the listener receive two events:
+ * - One when the replaced text is removed.
+ * - One when the replacing text is inserted
+ *
+ * The first event is ... simply absolutely misleading, it corresponds to a value that the text never had.
+ *
Another problem with DocumentListener is that you can't modify the text into it (it throws IllegalStateException).
+ *
Another way was to use KeyListeners ... but some key events are throw a long time (probably the key auto-repeat interval)
+ * after the key was released. And others events (for example a click on an OK button) may occurs before the listener is informed of the change.
+ *
This widget guarantees that no "ghost" property change is thrown !
+ */
+public class PasswordWidget extends JPasswordField {
+ private static final long serialVersionUID = 1L;
+
+ public static final String TEXT_PROPERTY = "text";
+
+ public PasswordWidget() {
+ this(0);
+ }
+
+ public PasswordWidget(int nbColumns) {
+ super("", nbColumns);
+ this.setDocument(new MyDocument());
+ }
+
+ @SuppressWarnings("serial")
+ private class MyDocument extends PlainDocument {
+ private boolean ignoreEvents = false;
+
+ @Override
+ public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
+ String oldValue = new String(PasswordWidget.this.getPassword());
+ this.ignoreEvents = true;
+ super.replace(offset, length, text, attrs);
+ this.ignoreEvents = false;
+ String newValue = new String(PasswordWidget.this.getPassword());
+ if (!oldValue.equals(newValue)) {
+ PasswordWidget.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue);
+ }
+ }
+
+ @Override
+ public void remove(int offs, int len) throws BadLocationException {
+ String oldValue = new String(PasswordWidget.this.getPassword());
+ super.remove(offs, len);
+ String newValue = new String(PasswordWidget.this.getPassword());
+ if (!ignoreEvents && !oldValue.equals(newValue)) {
+ PasswordWidget.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/RotatingLabel.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/RotatingLabel.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/RotatingLabel.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/RotatingLabel.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/SearchPanel.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/SearchPanel.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/SearchPanel.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/SearchPanel.java
index b8b13c7..1c0a1fd 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/SearchPanel.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/SearchPanel.java
@@ -1,247 +1,247 @@
-package com.fathzer.soft.ajlib.swing.widget;
-
-import javax.swing.JPanel;
-
-import javax.swing.JLabel;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.GridBagLayout;
-import java.awt.GridBagConstraints;
-import java.awt.Insets;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-
-import javax.swing.JCheckBox;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.JTextComponent;
-
-import java.awt.event.ItemListener;
-import java.awt.event.ItemEvent;
-import javax.swing.JTextField;
-import javax.swing.JButton;
-import javax.swing.ImageIcon;
-
-import com.fathzer.soft.ajlib.swing.TextSearcher;
-import com.fathzer.soft.ajlib.swing.framework.Application;
-
-import java.awt.event.ActionListener;
-import java.awt.event.ActionEvent;
-
-/** A panel with every need to search text in a text component.
- *
It provides a text field to enter the searched text, buttons to navigate through occurrences and setting buttons.
- *
When text is entered in search the text field, the first occurrence is automatically highlight in the text component.
- */
-@SuppressWarnings("serial")
-public class SearchPanel extends JPanel {
- private JLabel lblNewLabel;
- private TextWidget searchedTextField;
- private JPanel settingsPanel;
- private JCheckBox chckbxCase;
- private JCheckBox chckbxDiacritical;
- private JTextField resultField;
- private JButton upButton;
- private JButton downButton;
- private JPanel resultPanel;
-
- private JTextComponent textComponent;
- private TextSearcher searcher;
- private int currentOffset;
-
- /**
- * Constructor.
- * @param textComponent The component in which to search.
- */
- public SearchPanel(JTextComponent textComponent) {
- this.textComponent = textComponent;
- this.searcher = new TextSearcher(this.textComponent);
- initialize();
- }
-
- private void initialize() {
- GridBagLayout gblSearchPanel = new GridBagLayout();
- setLayout(gblSearchPanel);
- GridBagConstraints gbcLblNewLabel = new GridBagConstraints();
- gbcLblNewLabel.insets = new Insets(0, 0, 0, 5);
- gbcLblNewLabel.anchor = GridBagConstraints.EAST;
- gbcLblNewLabel.gridx = 0;
- gbcLblNewLabel.gridy = 0;
- add(getLblNewLabel(), gbcLblNewLabel);
- GridBagConstraints gbcSearchedTextField = new GridBagConstraints();
- gbcSearchedTextField.fill = GridBagConstraints.HORIZONTAL;
- gbcSearchedTextField.weightx = 1.0;
- gbcSearchedTextField.gridx = 1;
- gbcSearchedTextField.gridy = 0;
- add(getSearchedTextField(), gbcSearchedTextField);
- GridBagConstraints gbcResultPanel = new GridBagConstraints();
- gbcResultPanel.fill = GridBagConstraints.BOTH;
- gbcResultPanel.gridx = 2;
- gbcResultPanel.gridy = 0;
- add(getResultPanel(), gbcResultPanel);
- GridBagConstraints gbcSettingsPanel = new GridBagConstraints();
- gbcSettingsPanel.fill = GridBagConstraints.BOTH;
- gbcSettingsPanel.gridx = 3;
- gbcSettingsPanel.gridy = 0;
- add(getSettingsPanel(), gbcSettingsPanel);
- }
-
- private JLabel getLblNewLabel() {
- if (lblNewLabel == null) {
- lblNewLabel = new JLabel(Application.getString("SearchPanel.find", getLocale())); //$NON-NLS-1$
- }
- return lblNewLabel;
- }
-
- private TextWidget getSearchedTextField() {
- if (searchedTextField == null) {
- searchedTextField = new TextWidget();
- searchedTextField.addPropertyChangeListener(TextWidget.TEXT_PROPERTY, new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- doSearch();
- }
- });
- }
- return searchedTextField;
- }
-
- private JCheckBox getCaseInsensitiveCheckBox() {
- if (chckbxCase == null) {
- chckbxCase = new JCheckBox(Application.getString("SearchPanel.ingnoreCase", getLocale())); //$NON-NLS-1$
- chckbxCase.addItemListener(new ItemListener() {
- public void itemStateChanged(ItemEvent e) {
- searcher.setCaseSentitive(!getCaseInsensitiveCheckBox().isSelected());
- doSearch();
- }
- });
- chckbxCase.setSelected(true);
- }
- return chckbxCase;
- }
-
- private JPanel getSettingsPanel() {
- if (settingsPanel == null) {
- settingsPanel = new JPanel();
- GridBagLayout gblSettingsPanel = new GridBagLayout();
- settingsPanel.setLayout(gblSettingsPanel);
- GridBagConstraints gbcChckbxCase = new GridBagConstraints();
- gbcChckbxCase.anchor = GridBagConstraints.WEST;
- gbcChckbxCase.insets = new Insets(0, 0, 5, 5);
- gbcChckbxCase.gridx = 0;
- gbcChckbxCase.gridy = 0;
- settingsPanel.add(getCaseInsensitiveCheckBox(), gbcChckbxCase);
- GridBagConstraints gbcChckbxDiacritical = new GridBagConstraints();
- gbcChckbxDiacritical.insets = new Insets(0, 0, 0, 5);
- gbcChckbxDiacritical.anchor = GridBagConstraints.WEST;
- gbcChckbxDiacritical.gridx = 0;
- gbcChckbxDiacritical.gridy = 1;
- settingsPanel.add(getDiacriticalInsensitiveCheckbox(), gbcChckbxDiacritical);
- }
- return settingsPanel;
- }
- private JCheckBox getDiacriticalInsensitiveCheckbox() {
- if (chckbxDiacritical == null) {
- chckbxDiacritical = new JCheckBox(Application.getString("SearchPanel.ignoreMarks", getLocale())); //$NON-NLS-1$
- chckbxDiacritical.setSelected(true);
- chckbxDiacritical.addItemListener(new ItemListener() {
- public void itemStateChanged(ItemEvent e) {
- searcher.setDiacriticalSensitive(!getDiacriticalInsensitiveCheckbox().isSelected());
- doSearch();
- }
- });
- }
- return chckbxDiacritical;
- }
- private void doSearch() {
- String text = getSearchedTextField().getText();
- searcher.setSearchedText(text);
- int[] offsets = searcher.getOffsets();
- searchedTextField.setBackground((text.length()>0) && (offsets.length==0)?Color.red:Color.white);
- getResultPanel().setVisible(offsets.length>0);
- if (offsets.length>0) {
- setSelected(0);
- } else {
- textComponent.getHighlighter().removeAllHighlights();
- }
- SearchPanel.this.validate();
- }
-
- private void setSelected(int offsetNum) {
- try {
- int[] offsets = searcher.getOffsets();
- searcher.highlight(offsets[offsetNum], null);
- currentOffset = offsetNum;
- getDownButton().setEnabled(currentOffset!=offsets.length-1);
- getUpButton().setEnabled(currentOffset!=0);
- getResultField().setText((currentOffset+1)+"/"+offsets.length); //$NON-NLS-1$
- } catch (BadLocationException e) {
- throw new RuntimeException(e);
- }
- }
-
- private JTextField getResultField() {
- if (resultField == null) {
- resultField = new JTextField();
- resultField.setEditable(false);
- resultField.setFocusable(false);
- resultField.setColumns(5);
- }
- return resultField;
- }
- private JButton getUpButton() {
- if (upButton == null) {
- upButton = new JButton(new ImageIcon(getClass().getResource("/com/fathzer/soft/ajlib/swing/widget/up.png"))); //$NON-NLS-1$
- upButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- setSelected(currentOffset-1);
- }
- });
- upButton.setContentAreaFilled(false);
- upButton.setPreferredSize(new Dimension(16,12));
- }
- return upButton;
- }
- private JButton getDownButton() {
- if (downButton == null) {
- downButton = new JButton(new ImageIcon(getClass().getResource("/com/fathzer/soft/ajlib/swing/widget/down.png"))); //$NON-NLS-1$
- downButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- setSelected(currentOffset+1);
- }
- });
- downButton.setContentAreaFilled(false);
- downButton.setPreferredSize(new Dimension(16,12));
- }
- return downButton;
- }
- private JPanel getResultPanel() {
- if (resultPanel == null) {
- resultPanel = new JPanel();
- GridBagLayout gblResultPanel = new GridBagLayout();
- resultPanel.setLayout(gblResultPanel);
- GridBagConstraints gbcResultField = new GridBagConstraints();
- gbcResultField.fill = GridBagConstraints.HORIZONTAL;
- gbcResultField.gridheight = 2;
- gbcResultField.gridx = 0;
- gbcResultField.gridy = 0;
- resultPanel.add(getResultField(), gbcResultField);
- GridBagConstraints gbcUpButton = new GridBagConstraints();
- gbcUpButton.gridx = 1;
- gbcUpButton.gridy = 0;
- resultPanel.add(getUpButton(), gbcUpButton);
- GridBagConstraints gbcDownButton = new GridBagConstraints();
- gbcDownButton.gridx = 1;
- gbcDownButton.gridy = 1;
- resultPanel.add(getDownButton(), gbcDownButton);
- }
- return resultPanel;
- }
-
- /** Show/hide the search settings.
- * @param visible true to show the settings, false to hide them.
- */
- public void setSettingsVisible(boolean visible) {
- this.getDiacriticalInsensitiveCheckbox().setVisible(visible);
- this.getCaseInsensitiveCheckBox().setVisible(visible);
- }
-}
+package com.fathzer.soft.ajlib.swing.widget;
+
+import javax.swing.JPanel;
+
+import javax.swing.JLabel;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.GridBagLayout;
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.JCheckBox;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.JTextComponent;
+
+import java.awt.event.ItemListener;
+import java.awt.event.ItemEvent;
+import javax.swing.JTextField;
+import javax.swing.JButton;
+import javax.swing.ImageIcon;
+
+import com.fathzer.soft.ajlib.swing.TextSearcher;
+import com.fathzer.soft.ajlib.swing.framework.Application;
+
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+
+/** A panel with every need to search text in a text component.
+ *
It provides a text field to enter the searched text, buttons to navigate through occurrences and setting buttons.
+ *
When text is entered in search the text field, the first occurrence is automatically highlight in the text component.
+ */
+@SuppressWarnings("serial")
+public class SearchPanel extends JPanel {
+ private JLabel lblNewLabel;
+ private TextWidget searchedTextField;
+ private JPanel settingsPanel;
+ private JCheckBox chckbxCase;
+ private JCheckBox chckbxDiacritical;
+ private JTextField resultField;
+ private JButton upButton;
+ private JButton downButton;
+ private JPanel resultPanel;
+
+ private JTextComponent textComponent;
+ private TextSearcher searcher;
+ private int currentOffset;
+
+ /**
+ * Constructor.
+ * @param textComponent The component in which to search.
+ */
+ public SearchPanel(JTextComponent textComponent) {
+ this.textComponent = textComponent;
+ this.searcher = new TextSearcher(this.textComponent);
+ initialize();
+ }
+
+ private void initialize() {
+ GridBagLayout gblSearchPanel = new GridBagLayout();
+ setLayout(gblSearchPanel);
+ GridBagConstraints gbcLblNewLabel = new GridBagConstraints();
+ gbcLblNewLabel.insets = new Insets(0, 0, 0, 5);
+ gbcLblNewLabel.anchor = GridBagConstraints.EAST;
+ gbcLblNewLabel.gridx = 0;
+ gbcLblNewLabel.gridy = 0;
+ add(getLblNewLabel(), gbcLblNewLabel);
+ GridBagConstraints gbcSearchedTextField = new GridBagConstraints();
+ gbcSearchedTextField.fill = GridBagConstraints.HORIZONTAL;
+ gbcSearchedTextField.weightx = 1.0;
+ gbcSearchedTextField.gridx = 1;
+ gbcSearchedTextField.gridy = 0;
+ add(getSearchedTextField(), gbcSearchedTextField);
+ GridBagConstraints gbcResultPanel = new GridBagConstraints();
+ gbcResultPanel.fill = GridBagConstraints.BOTH;
+ gbcResultPanel.gridx = 2;
+ gbcResultPanel.gridy = 0;
+ add(getResultPanel(), gbcResultPanel);
+ GridBagConstraints gbcSettingsPanel = new GridBagConstraints();
+ gbcSettingsPanel.fill = GridBagConstraints.BOTH;
+ gbcSettingsPanel.gridx = 3;
+ gbcSettingsPanel.gridy = 0;
+ add(getSettingsPanel(), gbcSettingsPanel);
+ }
+
+ private JLabel getLblNewLabel() {
+ if (lblNewLabel == null) {
+ lblNewLabel = new JLabel(Application.getString("SearchPanel.find", getLocale())); //$NON-NLS-1$
+ }
+ return lblNewLabel;
+ }
+
+ private TextWidget getSearchedTextField() {
+ if (searchedTextField == null) {
+ searchedTextField = new TextWidget();
+ searchedTextField.addPropertyChangeListener(TextWidget.TEXT_PROPERTY, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ doSearch();
+ }
+ });
+ }
+ return searchedTextField;
+ }
+
+ private JCheckBox getCaseInsensitiveCheckBox() {
+ if (chckbxCase == null) {
+ chckbxCase = new JCheckBox(Application.getString("SearchPanel.ingnoreCase", getLocale())); //$NON-NLS-1$
+ chckbxCase.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ searcher.setCaseSentitive(!getCaseInsensitiveCheckBox().isSelected());
+ doSearch();
+ }
+ });
+ chckbxCase.setSelected(true);
+ }
+ return chckbxCase;
+ }
+
+ private JPanel getSettingsPanel() {
+ if (settingsPanel == null) {
+ settingsPanel = new JPanel();
+ GridBagLayout gblSettingsPanel = new GridBagLayout();
+ settingsPanel.setLayout(gblSettingsPanel);
+ GridBagConstraints gbcChckbxCase = new GridBagConstraints();
+ gbcChckbxCase.anchor = GridBagConstraints.WEST;
+ gbcChckbxCase.insets = new Insets(0, 0, 5, 5);
+ gbcChckbxCase.gridx = 0;
+ gbcChckbxCase.gridy = 0;
+ settingsPanel.add(getCaseInsensitiveCheckBox(), gbcChckbxCase);
+ GridBagConstraints gbcChckbxDiacritical = new GridBagConstraints();
+ gbcChckbxDiacritical.insets = new Insets(0, 0, 0, 5);
+ gbcChckbxDiacritical.anchor = GridBagConstraints.WEST;
+ gbcChckbxDiacritical.gridx = 0;
+ gbcChckbxDiacritical.gridy = 1;
+ settingsPanel.add(getDiacriticalInsensitiveCheckbox(), gbcChckbxDiacritical);
+ }
+ return settingsPanel;
+ }
+ private JCheckBox getDiacriticalInsensitiveCheckbox() {
+ if (chckbxDiacritical == null) {
+ chckbxDiacritical = new JCheckBox(Application.getString("SearchPanel.ignoreMarks", getLocale())); //$NON-NLS-1$
+ chckbxDiacritical.setSelected(true);
+ chckbxDiacritical.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ searcher.setDiacriticalSensitive(!getDiacriticalInsensitiveCheckbox().isSelected());
+ doSearch();
+ }
+ });
+ }
+ return chckbxDiacritical;
+ }
+ private void doSearch() {
+ String text = getSearchedTextField().getText();
+ searcher.setSearchedText(text);
+ int[] offsets = searcher.getOffsets();
+ searchedTextField.setBackground((text.length()>0) && (offsets.length==0)?Color.red:Color.white);
+ getResultPanel().setVisible(offsets.length>0);
+ if (offsets.length>0) {
+ setSelected(0);
+ } else {
+ textComponent.getHighlighter().removeAllHighlights();
+ }
+ SearchPanel.this.validate();
+ }
+
+ private void setSelected(int offsetNum) {
+ try {
+ int[] offsets = searcher.getOffsets();
+ searcher.highlight(offsets[offsetNum], null);
+ currentOffset = offsetNum;
+ getDownButton().setEnabled(currentOffset!=offsets.length-1);
+ getUpButton().setEnabled(currentOffset!=0);
+ getResultField().setText((currentOffset+1)+"/"+offsets.length); //$NON-NLS-1$
+ } catch (BadLocationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private JTextField getResultField() {
+ if (resultField == null) {
+ resultField = new JTextField();
+ resultField.setEditable(false);
+ resultField.setFocusable(false);
+ resultField.setColumns(5);
+ }
+ return resultField;
+ }
+ private JButton getUpButton() {
+ if (upButton == null) {
+ upButton = new JButton(new ImageIcon(getClass().getResource("/com/fathzer/soft/ajlib/swing/widget/up.png"))); //$NON-NLS-1$
+ upButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ setSelected(currentOffset-1);
+ }
+ });
+ upButton.setContentAreaFilled(false);
+ upButton.setPreferredSize(new Dimension(16,12));
+ }
+ return upButton;
+ }
+ private JButton getDownButton() {
+ if (downButton == null) {
+ downButton = new JButton(new ImageIcon(getClass().getResource("/com/fathzer/soft/ajlib/swing/widget/down.png"))); //$NON-NLS-1$
+ downButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ setSelected(currentOffset+1);
+ }
+ });
+ downButton.setContentAreaFilled(false);
+ downButton.setPreferredSize(new Dimension(16,12));
+ }
+ return downButton;
+ }
+ private JPanel getResultPanel() {
+ if (resultPanel == null) {
+ resultPanel = new JPanel();
+ GridBagLayout gblResultPanel = new GridBagLayout();
+ resultPanel.setLayout(gblResultPanel);
+ GridBagConstraints gbcResultField = new GridBagConstraints();
+ gbcResultField.fill = GridBagConstraints.HORIZONTAL;
+ gbcResultField.gridheight = 2;
+ gbcResultField.gridx = 0;
+ gbcResultField.gridy = 0;
+ resultPanel.add(getResultField(), gbcResultField);
+ GridBagConstraints gbcUpButton = new GridBagConstraints();
+ gbcUpButton.gridx = 1;
+ gbcUpButton.gridy = 0;
+ resultPanel.add(getUpButton(), gbcUpButton);
+ GridBagConstraints gbcDownButton = new GridBagConstraints();
+ gbcDownButton.gridx = 1;
+ gbcDownButton.gridy = 1;
+ resultPanel.add(getDownButton(), gbcDownButton);
+ }
+ return resultPanel;
+ }
+
+ /** Show/hide the search settings.
+ * @param visible true to show the settings, false to hide them.
+ */
+ public void setSettingsVisible(boolean visible) {
+ this.getDiacriticalInsensitiveCheckbox().setVisible(visible);
+ this.getCaseInsensitiveCheckBox().setVisible(visible);
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/TextWidget.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/TextWidget.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/TextWidget.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/TextWidget.java
index 08164fd..4327839 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/TextWidget.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/TextWidget.java
@@ -1,326 +1,326 @@
-package com.fathzer.soft.ajlib.swing.widget;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.util.ArrayList;
-import java.util.TreeSet;
-
-import javax.swing.AbstractListModel;
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.JComponent;
-import javax.swing.JList;
-import javax.swing.JPopupMenu;
-import javax.swing.JScrollPane;
-import javax.swing.JTextField;
-import javax.swing.border.AbstractBorder;
-import javax.swing.border.Border;
-import javax.swing.border.CompoundBorder;
-import javax.swing.text.AttributeSet;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.PlainDocument;
-
-import com.fathzer.soft.ajlib.utilities.NullUtils;
-import com.fathzer.soft.ajlib.utilities.TextMatcher;
-
-/** A JTextField with a property that maps its text and the ability to define predefined values.
- *
I've found no way to track efficiently the modifications of the text of a JTextField ... so I developed this widget.
- *
DocumentListeners are intended to do it, unfortunately, when a text is replace in a field, the listener receive two events:
- * - One when the replaced text is removed.
- * - One when the replacing text is inserted
- *
- * The first event is ... simply absolutely misleading, it corresponds to a value that the text never had.
- *
Another problem with DocumentListener is that you can't modify the text into it (it throws IllegalStateException).
- *
Another way was to use KeyListeners ... but some key events are throw a long time (probably the key auto-repeat interval)
- * after the key was released. And others events (for example a click on an OK button) may occurs before the listener is informed of the change.
- *
This widget guarantees that no "ghost" property change is thrown !
- *
This class implements a popup menu that allows to select the field content into a list of predefined values.
- *
The difference with a JComboBox is the popup content and selection is updated when the user changes the text field content.
- * It always contains only predefined text that contains the current widget text.
- */
-public class TextWidget extends JTextField {
- private static final long serialVersionUID = 1L;
-
- public static final String TEXT_PROPERTY = "text"; //$NON-NLS-1$
- /** A PropertyChangeEvent of this name is fired when a predefined value is selected.
- * The values of the event are the field content.
- */
- public static final String PREDEFINED_VALUE = "PREDEFINED_VALUE"; //$NON-NLS-1$
-
- private JPopupMenu popup;
- private JList list;
- private String predefined=null;
- private String lastText=""; //$NON-NLS-1$
- private int unsortedMax;
- private String[] proposals;
-
- private static class UpperLineBorder extends AbstractBorder {
- private static final long serialVersionUID = 1L;
- protected Color lineColor;
-
- public UpperLineBorder(Color color) {
- lineColor = color;
- }
-
- @Override
- public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
- g.setColor(lineColor);
- g.drawLine(x+1, y, x+width-2, y);
- }
- }
-
- private class MyRenderer extends DefaultListCellRenderer {
- private static final long serialVersionUID = 1L;
-
- @Override
- public Component getListCellRendererComponent(JList> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
- if (((String)value).length()==0) {
- value = " "; //$NON-NLS-1$
- }
- JComponent label = (JComponent) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
- if ((unsortedMax>0) && (index==unsortedMax)) {
- Border border = new UpperLineBorder(label.getForeground().brighter());
- label.setBorder(new CompoundBorder(border, label.getBorder()));
- }
- return label;
- }
- }
-
- /** Constructor.
- */
- public TextWidget () {
- // Revision 244 of this method contains a not efficient try to implement command-V in textfield on MacOS
- this.setDocument(new MyDocument());
- }
-
- private void installPopup() {
- if (popup==null) {
- unsortedMax = Integer.MAX_VALUE;
- popup = new JPopupMenu();
- list = new JList<>(new PopupListModel());
- list.setAutoscrolls(true);
- list.setCellRenderer(new MyRenderer());
- popup.add(new JScrollPane(list));
- popup.setFocusable(false);
-
- // If the component looses the focus and the popup is shown, we have to hide the popup
- // The following FocusListener will do that
- addFocusListener(new FocusListener() {
- @Override
- public void focusLost(FocusEvent e) {
- if (popup.isVisible() && !e.isTemporary() && (!list.equals(e.getOppositeComponent()))) {
- popup.setVisible(false);
- if (e.getOppositeComponent()!=null) {
- e.getOppositeComponent().requestFocus();
- }
- }
- }
-
- @Override
- public void focusGained(FocusEvent e) {
- // Nothing to do in this case
- }
- });
- // When the user clicks the list, we have to set the value clicked in the list, hide the popup, then transfer back the focus to the textField
- list.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- if (e.getButton()==MouseEvent.BUTTON1) {
- setPredefined(list.getSelectedValue());
- popup.setVisible(false);
- }
- }
- @Override
- public void mouseReleased(MouseEvent e) {
- requestFocus();
- }
- });
- // When the user press the down arrow, show the popup, if it's hidden.
- // Up, down and enter key respectivly selects next element, selects previous element, set the textField to the selected element
- // When a key is type, and changed the content of the field, this adapter also refresh the list selected element
- addKeyListener(new KeyAdapter() {
- @Override
- public void keyPressed(KeyEvent e) {
- if (e.getKeyCode() == KeyEvent.VK_DOWN) { // down arrow key was pressed
- if (!popup.isVisible()) {
- showPopup();
- } else {
- int index = list.getSelectedIndex();
- if (index < list.getModel().getSize()) {
- index++;
- list.setSelectedIndex(index);
- }
- }
- } else if (e.getKeyCode() == KeyEvent.VK_UP) { // Up arrow key was pressed
- if (popup.isVisible()) {
- int index = list.getSelectedIndex();
- if (index > 0) {
- index--;
- list.setSelectedIndex(index);
- }
- }
- } else if (e.getKeyCode() == KeyEvent.VK_ENTER) { // Enter key pressed
- if (popup.isVisible()) {
- if (list.getSelectedIndex()>=0) {
- setPredefined(list.getSelectedValue());
- }
- popup.setVisible(false);
- e.consume();
- }
- }
- }
-
- @Override
- public void keyReleased(KeyEvent e) {
- String text = getText();
- if (!text.equals(lastText)) {
- fillModel(text);
- lastText = text;
- setPredefined((String)null);
- showPopup();
- }
- }
- });
- }
- }
-
- public TextWidget(int columns) {
- this();
- this.setColumns(columns);
- }
-
- private void setPredefined(String value) {
- if (value!=null) {
- lastText = value;
- setText(value);
- }
- if (!NullUtils.areEquals(predefined, value)) {
- String oldPredefined = predefined;
- predefined = value;
- this.firePropertyChange(PREDEFINED_VALUE, oldPredefined, predefined);
- }
- }
-
- /** Sets the predefined values allowed by the field.
- * @param array The predefined values.
- * @see #setPredefined(String[], int)
- */
- public void setPredefined(String[] array) {
- setPredefined (array, Integer.MAX_VALUE);
- }
-
- /** Sets the predefined values allowed by the field.
- * @param array The predefined values.
- * @param unsortedMax Maximum number of unsorted values.
- *
The values can be divided in two groups (which will be separated by a thin line).
- *
- * - A group of values, that matches the current typed text, sorted in the same order as in the array argument.
- * - A group of values, that matches the current typed text, sorted in alphabetical order.
- *
- *
This argument contains the size of the first group. Use Integer.MAX_VALUE to always display values in the same order as in the array. 0 to always sorted values.
- */
- public void setPredefined(String[] array, int unsortedMax) {
- installPopup();
- this.unsortedMax = unsortedMax;
- this.proposals = array==null ? null : array.clone();
- fillModel(this.getText());
- }
-
- private void showPopup() {
- if (list.getModel().getSize()!=0) {
- Dimension size = popup.getPreferredSize();
- if (getWidth()>size.width) {
- popup.setPreferredSize(new Dimension(getWidth(), size.height));
- }
- popup.show(TextWidget.this, 0, getHeight());
- requestFocus(false);
- } else {
- popup.setVisible(false);
- }
- }
-
- private void fillModel(String text) {
- TextMatcher matcher = new TextMatcher(TextMatcher.Kind.CONTAINS, text, false, false); //TODO Must match "starts with" ... to be implemented in TextMatcher
- ArrayList okProbaSort = new ArrayList<>();
- TreeSet okAlphabeticSort = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
- for (String value : this.proposals) {
- if (matcher.matches(value)) {
- if (okProbaSort.size()<=unsortedMax) {
- okProbaSort.add(value);
- } else {
- okAlphabeticSort.add(value);
- }
- }
- }
- okProbaSort.addAll(okAlphabeticSort);
- ((PopupListModel)list.getModel()).setValues(okProbaSort.toArray(new String[okProbaSort.size()]));
-
- if (0 != list.getSelectedIndex()) {
- list.setSelectedIndex(0);
- }
- }
-
- private static final class PopupListModel extends AbstractListModel {
- private static final long serialVersionUID = 1L;
- String[] values;
-
- PopupListModel() {
- this.values = new String[0];
- }
-
- @Override
- public int getSize() {
- return values.length;
- }
-
- @Override
- public String getElementAt(int index) {
- return values[index];
- }
-
- public void setValues(String[] values) {
- int n = this.values.length;
- if (n>0) {
- this.values = new String[0];
- fireIntervalRemoved(this, 0, n);
- }
- this.values = values.clone();
- fireIntervalAdded(this, 0, this.values.length);
- }
- }
-
- private class MyDocument extends PlainDocument {
- private static final long serialVersionUID = 1L;
- private boolean ignoreEvents = false;
-
- @Override
- public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
- String oldValue = TextWidget.this.getText();
- this.ignoreEvents = true;
- super.replace(offset, length, text, attrs);
- this.ignoreEvents = false;
- String newValue = TextWidget.this.getText();
- if (!oldValue.equals(newValue)) {
- TextWidget.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue);
- }
- }
-
- @Override
- public void remove(int offs, int len) throws BadLocationException {
- String oldValue = TextWidget.this.getText();
- super.remove(offs, len);
- String newValue = TextWidget.this.getText();
- if (!ignoreEvents && !oldValue.equals(newValue)) {
- TextWidget.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue);
- }
- }
- }
-
-}
+package com.fathzer.soft.ajlib.swing.widget;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.TreeSet;
+
+import javax.swing.AbstractListModel;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JComponent;
+import javax.swing.JList;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.border.AbstractBorder;
+import javax.swing.border.Border;
+import javax.swing.border.CompoundBorder;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.PlainDocument;
+
+import com.fathzer.soft.ajlib.utilities.NullUtils;
+import com.fathzer.soft.ajlib.utilities.TextMatcher;
+
+/** A JTextField with a property that maps its text and the ability to define predefined values.
+ *
I've found no way to track efficiently the modifications of the text of a JTextField ... so I developed this widget.
+ *
DocumentListeners are intended to do it, unfortunately, when a text is replace in a field, the listener receive two events:
+ * - One when the replaced text is removed.
+ * - One when the replacing text is inserted
+ *
+ * The first event is ... simply absolutely misleading, it corresponds to a value that the text never had.
+ *
Another problem with DocumentListener is that you can't modify the text into it (it throws IllegalStateException).
+ *
Another way was to use KeyListeners ... but some key events are throw a long time (probably the key auto-repeat interval)
+ * after the key was released. And others events (for example a click on an OK button) may occurs before the listener is informed of the change.
+ *
This widget guarantees that no "ghost" property change is thrown !
+ *
This class implements a popup menu that allows to select the field content into a list of predefined values.
+ *
The difference with a JComboBox is the popup content and selection is updated when the user changes the text field content.
+ * It always contains only predefined text that contains the current widget text.
+ */
+public class TextWidget extends JTextField {
+ private static final long serialVersionUID = 1L;
+
+ public static final String TEXT_PROPERTY = "text"; //$NON-NLS-1$
+ /** A PropertyChangeEvent of this name is fired when a predefined value is selected.
+ * The values of the event are the field content.
+ */
+ public static final String PREDEFINED_VALUE = "PREDEFINED_VALUE"; //$NON-NLS-1$
+
+ private JPopupMenu popup;
+ private JList list;
+ private String predefined=null;
+ private String lastText=""; //$NON-NLS-1$
+ private int unsortedMax;
+ private String[] proposals;
+
+ private static class UpperLineBorder extends AbstractBorder {
+ private static final long serialVersionUID = 1L;
+ protected Color lineColor;
+
+ public UpperLineBorder(Color color) {
+ lineColor = color;
+ }
+
+ @Override
+ public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
+ g.setColor(lineColor);
+ g.drawLine(x+1, y, x+width-2, y);
+ }
+ }
+
+ private class MyRenderer extends DefaultListCellRenderer {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Component getListCellRendererComponent(JList> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ if (((String)value).length()==0) {
+ value = " "; //$NON-NLS-1$
+ }
+ JComponent label = (JComponent) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+ if ((unsortedMax>0) && (index==unsortedMax)) {
+ Border border = new UpperLineBorder(label.getForeground().brighter());
+ label.setBorder(new CompoundBorder(border, label.getBorder()));
+ }
+ return label;
+ }
+ }
+
+ /** Constructor.
+ */
+ public TextWidget () {
+ // Revision 244 of this method contains a not efficient try to implement command-V in textfield on MacOS
+ this.setDocument(new MyDocument());
+ }
+
+ private void installPopup() {
+ if (popup==null) {
+ unsortedMax = Integer.MAX_VALUE;
+ popup = new JPopupMenu();
+ list = new JList<>(new PopupListModel());
+ list.setAutoscrolls(true);
+ list.setCellRenderer(new MyRenderer());
+ popup.add(new JScrollPane(list));
+ popup.setFocusable(false);
+
+ // If the component looses the focus and the popup is shown, we have to hide the popup
+ // The following FocusListener will do that
+ addFocusListener(new FocusListener() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (popup.isVisible() && !e.isTemporary() && (!list.equals(e.getOppositeComponent()))) {
+ popup.setVisible(false);
+ if (e.getOppositeComponent()!=null) {
+ e.getOppositeComponent().requestFocus();
+ }
+ }
+ }
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ // Nothing to do in this case
+ }
+ });
+ // When the user clicks the list, we have to set the value clicked in the list, hide the popup, then transfer back the focus to the textField
+ list.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if (e.getButton()==MouseEvent.BUTTON1) {
+ setPredefined(list.getSelectedValue());
+ popup.setVisible(false);
+ }
+ }
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ requestFocus();
+ }
+ });
+ // When the user press the down arrow, show the popup, if it's hidden.
+ // Up, down and enter key respectivly selects next element, selects previous element, set the textField to the selected element
+ // When a key is type, and changed the content of the field, this adapter also refresh the list selected element
+ addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.getKeyCode() == KeyEvent.VK_DOWN) { // down arrow key was pressed
+ if (!popup.isVisible()) {
+ showPopup();
+ } else {
+ int index = list.getSelectedIndex();
+ if (index < list.getModel().getSize()) {
+ index++;
+ list.setSelectedIndex(index);
+ }
+ }
+ } else if (e.getKeyCode() == KeyEvent.VK_UP) { // Up arrow key was pressed
+ if (popup.isVisible()) {
+ int index = list.getSelectedIndex();
+ if (index > 0) {
+ index--;
+ list.setSelectedIndex(index);
+ }
+ }
+ } else if (e.getKeyCode() == KeyEvent.VK_ENTER) { // Enter key pressed
+ if (popup.isVisible()) {
+ if (list.getSelectedIndex()>=0) {
+ setPredefined(list.getSelectedValue());
+ }
+ popup.setVisible(false);
+ e.consume();
+ }
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ String text = getText();
+ if (!text.equals(lastText)) {
+ fillModel(text);
+ lastText = text;
+ setPredefined((String)null);
+ showPopup();
+ }
+ }
+ });
+ }
+ }
+
+ public TextWidget(int columns) {
+ this();
+ this.setColumns(columns);
+ }
+
+ private void setPredefined(String value) {
+ if (value!=null) {
+ lastText = value;
+ setText(value);
+ }
+ if (!NullUtils.areEquals(predefined, value)) {
+ String oldPredefined = predefined;
+ predefined = value;
+ this.firePropertyChange(PREDEFINED_VALUE, oldPredefined, predefined);
+ }
+ }
+
+ /** Sets the predefined values allowed by the field.
+ * @param array The predefined values.
+ * @see #setPredefined(String[], int)
+ */
+ public void setPredefined(String[] array) {
+ setPredefined (array, Integer.MAX_VALUE);
+ }
+
+ /** Sets the predefined values allowed by the field.
+ * @param array The predefined values.
+ * @param unsortedMax Maximum number of unsorted values.
+ *
The values can be divided in two groups (which will be separated by a thin line).
+ *
+ * - A group of values, that matches the current typed text, sorted in the same order as in the array argument.
+ * - A group of values, that matches the current typed text, sorted in alphabetical order.
+ *
+ *
This argument contains the size of the first group. Use Integer.MAX_VALUE to always display values in the same order as in the array. 0 to always sorted values.
+ */
+ public void setPredefined(String[] array, int unsortedMax) {
+ installPopup();
+ this.unsortedMax = unsortedMax;
+ this.proposals = array==null ? null : array.clone();
+ fillModel(this.getText());
+ }
+
+ private void showPopup() {
+ if (list.getModel().getSize()!=0) {
+ Dimension size = popup.getPreferredSize();
+ if (getWidth()>size.width) {
+ popup.setPreferredSize(new Dimension(getWidth(), size.height));
+ }
+ popup.show(TextWidget.this, 0, getHeight());
+ requestFocus(false);
+ } else {
+ popup.setVisible(false);
+ }
+ }
+
+ private void fillModel(String text) {
+ TextMatcher matcher = new TextMatcher(TextMatcher.Kind.CONTAINS, text, false, false); //TODO Must match "starts with" ... to be implemented in TextMatcher
+ ArrayList okProbaSort = new ArrayList<>();
+ TreeSet okAlphabeticSort = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
+ for (String value : this.proposals) {
+ if (matcher.matches(value)) {
+ if (okProbaSort.size()<=unsortedMax) {
+ okProbaSort.add(value);
+ } else {
+ okAlphabeticSort.add(value);
+ }
+ }
+ }
+ okProbaSort.addAll(okAlphabeticSort);
+ ((PopupListModel)list.getModel()).setValues(okProbaSort.toArray(new String[okProbaSort.size()]));
+
+ if (0 != list.getSelectedIndex()) {
+ list.setSelectedIndex(0);
+ }
+ }
+
+ private static final class PopupListModel extends AbstractListModel {
+ private static final long serialVersionUID = 1L;
+ String[] values;
+
+ PopupListModel() {
+ this.values = new String[0];
+ }
+
+ @Override
+ public int getSize() {
+ return values.length;
+ }
+
+ @Override
+ public String getElementAt(int index) {
+ return values[index];
+ }
+
+ public void setValues(String[] values) {
+ int n = this.values.length;
+ if (n>0) {
+ this.values = new String[0];
+ fireIntervalRemoved(this, 0, n);
+ }
+ this.values = values.clone();
+ fireIntervalAdded(this, 0, this.values.length);
+ }
+ }
+
+ private class MyDocument extends PlainDocument {
+ private static final long serialVersionUID = 1L;
+ private boolean ignoreEvents = false;
+
+ @Override
+ public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
+ String oldValue = TextWidget.this.getText();
+ this.ignoreEvents = true;
+ super.replace(offset, length, text, attrs);
+ this.ignoreEvents = false;
+ String newValue = TextWidget.this.getText();
+ if (!oldValue.equals(newValue)) {
+ TextWidget.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue);
+ }
+ }
+
+ @Override
+ public void remove(int offs, int len) throws BadLocationException {
+ String oldValue = TextWidget.this.getText();
+ super.remove(offs, len);
+ String newValue = TextWidget.this.getText();
+ if (!ignoreEvents && !oldValue.equals(newValue)) {
+ TextWidget.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/CalendarWidget.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/CalendarWidget.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/date/CalendarWidget.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/CalendarWidget.java
index e0e2e8b..07167a6 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/CalendarWidget.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/CalendarWidget.java
@@ -1,437 +1,437 @@
-/* This is a modified version of the original DateChooserPanel.java from JFree.
- * Changes:
- * - The month selection is implemented with buttons instead of the originals JComboBox.
- * This allows the component to be used in a popup.
- * - The "today button" is now in the month selection panel and hasn't an non localized english label
- * - Null dates are now allowed (no date is selected in the panel)
- *
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
-
- * ========================================================================
- * JCommon: a free general purpose class library for the Java(tm) platform
- * ========================================================================
- *
- * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
- *
- * Project Info: http://www.jfree.org/jcommon/index.html
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- *
- * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
- * in the United States and other countries.]
- *
- * ---------------------
- * DateChooserPanel.java
- * ---------------------
- * (C) Copyright 2000-2004, by Object Refinery Limited.
- *
- * Original Author: David Gilbert (for Object Refinery Limited);
- * Contributor(s): -;
- *
- * $Id: DateChooserPanel.java,v 1.11 2007/11/02 17:50:36 taqua Exp $
- *
- * Changes (from 26-Oct-2001)
- * --------------------------
- * 26-Oct-2001: Changed package to com.jrefinery.ui.* (DG);
- * 08-Dec-2001: Dropped the getMonths() method (DG);
- * 13-Oct-2002: Fixed errors reported by Checkstyle (DG);
- * 02-Nov-2005: Fixed a bug where the current day-of-the-month is past
- * the end of the newly selected month when the month or year
- * combo boxes are changed - see bug id 1344319 (DG);
- *
- */
-
-package com.fathzer.soft.ajlib.swing.widget.date;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.GridLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.text.DateFormatSymbols;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Locale;
-
-import javax.swing.JButton;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.SwingConstants;
-
-import com.fathzer.soft.ajlib.utilities.NullUtils;
-
-/**
- * A panel that allows the user to select a date.
- * @author David Gilbert (modified by Jean-Marc Astesana)
- */
-public class CalendarWidget extends JPanel {
- private static final long serialVersionUID = 1L;
- public static final String DATE_PROPERTY = "DATE_PROPERTY";
-
- /**
- * The date selected in the panel.
- */
- private Calendar chosenDate;
-
- /**
- * The color for the selected date.
- */
- private Color chosenDateButtonColor;
-
- /**
- * The color for dates in the current month.
- */
- private Color chosenMonthButtonColor;
-
- /**
- * The color for dates that are visible, but not in the current month.
- */
- private Color chosenOtherButtonColor;
-
- /**
- * The first day-of-the-week.
- */
- private int firstDayOfWeek;
-
- /**
- * The font used to display the date.
- */
- private Float fontRatio = 0.85f;
-
- /**
- * An array of buttons used to display the days-of-the-month.
- */
- private JButton[] buttons;
-
- /**
- * An array of labels used to display day of week names.
- */
- private JLabel[] days;
-
- private MonthWidget monthSelector;
-
- /**
- * The ordered set of all seven days of a week, beginning with the
- * 'firstDayOfWeek'.
- */
- private int[] weekDays;
-
- /**
- * Constructs a new date chooser panel, using today's date as the initial
- * selection.
- */
- public CalendarWidget() {
- super(new BorderLayout());
-
- //TODO It would be cool to choose colors from the current Look and Feel ... but I didn't succeed in doing that :-(
- this.chosenDateButtonColor = Color.red;
- this.chosenMonthButtonColor = Color.white;
- this.chosenOtherButtonColor = Color.gray;
-
- // the default date is today...
- this.chosenDate = Calendar.getInstance(getLocale());
- initializeDays();
-
- monthSelector = new MonthWidget();
- add(monthSelector, BorderLayout.NORTH);
- add(getCalendarPanel(), BorderLayout.CENTER);
- monthSelector.addPropertyChangeListener(MonthWidget.DATE_PROPERTY, new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- refreshButtons();
- }
- });
- monthSelector.getNow().addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- setDate(new Date());
- }
- });
- refreshButtons();
- }
-
- @Override
- public void setLocale(Locale l) {
- super.setLocale(l);
- monthSelector.setLocale(l);
- initializeDays();
- updateDays();
- refreshButtons();
- }
-
- private void initializeDays() {
- this.firstDayOfWeek = Calendar.getInstance(getLocale()).getFirstDayOfWeek();
- this.weekDays = new int[7];
- for (int i = 0; i < 7; i++) {
- this.weekDays[i] = ((this.firstDayOfWeek + i - 1) % 7) + 1;
- }
- }
-
- /**
- * Sets the date chosen in the panel.
- *
- * @param theDate
- * the new date.
- */
- public void setDate(final Date theDate) {
- Date old = this.getDate();
- if (!NullUtils.areEquals(theDate, old)) {
- if (theDate == null) {
- this.chosenDate = null;
- } else {
- if (this.chosenDate == null) {
- this.chosenDate = Calendar.getInstance(getLocale());
- }
- this.chosenDate.setTime(theDate);
- this.monthSelector.setMonth(theDate);
- }
- refreshButtons();
- this.firePropertyChange(DATE_PROPERTY, old, theDate);
- }
- }
-
- /**
- * Returns the date selected in the panel.
- *
- * @return the selected date.
- */
- public Date getDate() {
- return this.chosenDate == null ? null : this.chosenDate.getTime();
- }
-
- /**
- * Returns a panel of buttons, each button representing a day in the month.
- * This is a sub-component of the DatePanel.
- *
- * @return the panel.
- */
- private JPanel getCalendarPanel() {
- final JPanel p = new JPanel(new GridLayout(7, 7));
- final DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(getLocale());
- final String[] weekDays = dateFormatSymbols.getShortWeekdays();
- this.days = new JLabel[this.weekDays.length];
-
- for (int i = 0; i < this.weekDays.length; i++) {
- this.days[i] = new JLabel(weekDays[this.weekDays[i]], SwingConstants.CENTER);
- p.add(this.days[i]);
- }
-
- this.buttons = new JButton[42];
- ActionListener listener = new ActionListener() {
- /**
- * Handles action-events from the date panel.
- * @param e information about the event that occurred.
- */
- public void actionPerformed(final ActionEvent e) {
- final JButton b = (JButton) e.getSource();
- final int i = Integer.parseInt(b.getName());
- final Calendar cal = getFirstVisibleDate();
- cal.add(Calendar.DATE, i);
- setDate(cal.getTime());
- }
- };
- Font bFont = null;
- for (int i = 0; i < 42; i++) {
- final JButton b = new JButton("");
- if (bFont==null) {
- bFont = b.getFont().deriveFont(fontRatio*b.getFont().getSize());
- }
- b.setMargin(new Insets(1, 1, 1, 1));
- b.setName(Integer.toString(i));
- b.setFont(bFont);
- b.setFocusPainted(false);
- b.setActionCommand("dateButtonClicked");
- b.addActionListener(listener);
- this.buttons[i] = b;
- p.add(b);
- }
- return p;
- }
-
- private void updateDays() {
- final DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(getLocale());
- final String[] weekDaysWordings = dateFormatSymbols.getShortWeekdays();
- for (int i = 0; i < days.length; i++) {
- days[i].setText(weekDaysWordings[this.weekDays[i]]);
- }
- }
-
- /**
- * Returns true if the two dates are equal (time of day is ignored).
- *
- * @param c1
- * the first date.
- * @param c2
- * the second date.
- * @return boolean.
- */
- private boolean equalDates(final Calendar c1, final Calendar c2) {
- // Be aware that c1 or c2 can be null
- if ((c1 == null) && (c2 == null)) {
- return true;
- }
- if ((c1 == null) || (c2 == null)) {
- return false;
- }
- return (c1.get(Calendar.DATE) == c2.get(Calendar.DATE)) && (c1.get(Calendar.MONTH) == c2.get(Calendar.MONTH))
- && (c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR));
- }
-
- /**
- * Returns the first date that is visible in the grid. This should always be
- * in the month preceding the month of the selected date.
- *
- * @return the date.
- */
- private Calendar getFirstVisibleDate() {
- final Calendar c = Calendar.getInstance(getLocale());
- c.setTime(this.monthSelector.getMonth());
- c.add(Calendar.DATE, -1);
- while (c.get(Calendar.DAY_OF_WEEK) != getFirstDayOfWeek()) {
- c.add(Calendar.DATE, -1);
- }
- return c;
- }
-
- /**
- * Returns the first day of the week (controls the labels in the date panel).
- *
- * @return the first day of the week.
- */
- private int getFirstDayOfWeek() {
- return this.firstDayOfWeek;
- }
-
- /**
- * Update the button labels and colors to reflect date selection.
- */
- private void refreshButtons() {
- final Calendar c = getFirstVisibleDate();
- final Calendar current = Calendar.getInstance(getLocale());
- current.setTime(this.monthSelector.getMonth());
- for (int i = 0; i < 42; i++) {
- final JButton b = this.buttons[i];
- setButtonAppearance(b, c, current);
- c.add(Calendar.DATE, 1);
- }
- }
-
- /** Sets a date button appearance.
- * @param button The button to be set up
- * @param date The date represented by the button
- * @param currentMonth The currently displayed month
- */
- private void setButtonAppearance(JButton button, Calendar date, Calendar currentMonth) {
- String day = Integer.toString(date.get(Calendar.DATE));
- Color color;
- if (equalDates(date, this.chosenDate)) {
- color = this.chosenDateButtonColor;
- } else if ((date.get(Calendar.MONTH) == currentMonth.get(Calendar.MONTH))
- && (date.get(Calendar.YEAR) == currentMonth.get(Calendar.YEAR))) {
- color = this.chosenMonthButtonColor;
- } else {
- color = this.chosenOtherButtonColor;
- }
- button.setBackground(color);
- if (equalDates(date, Calendar.getInstance())) {
- day = ""+day+"";
- }
- button.setText(day);
- }
-
- /**
- * Returns the color for the currently selected date.
- *
- * @return a color.
- */
- public Color getChosenDateButtonColor() {
- return this.chosenDateButtonColor;
- }
-
- /**
- * Redefines the color for the currently selected date.
- *
- * @param chosenDateButtonColor
- * the new color
- */
- public void setChosenDateButtonColor(final Color chosenDateButtonColor) {
- checkButtonColor(chosenDateButtonColor);
- final Color oldValue = this.chosenDateButtonColor;
- this.chosenDateButtonColor = chosenDateButtonColor;
- refreshButtons();
- firePropertyChange("chosenDateButtonColor", oldValue, chosenDateButtonColor);
- }
-
- /**
- * Returns the color for the buttons representing the current month.
- *
- * @return the color for the current month.
- */
- public Color getChosenMonthButtonColor() {
- return this.chosenMonthButtonColor;
- }
-
- /**
- * Defines the color for the buttons representing the current month.
- *
- * @param chosenMonthButtonColor
- * the color for the current month.
- */
- public void setChosenMonthButtonColor(final Color chosenMonthButtonColor) {
- checkButtonColor(chosenMonthButtonColor);
- final Color oldValue = this.chosenMonthButtonColor;
- this.chosenMonthButtonColor = chosenMonthButtonColor;
- refreshButtons();
- firePropertyChange("chosenMonthButtonColor", oldValue, chosenMonthButtonColor);
- }
-
- /**
- * Returns the color for the buttons representing the other months.
- *
- * @return a color.
- */
- public Color getChosenOtherButtonColor() {
- return this.chosenOtherButtonColor;
- }
-
- /**
- * Redefines the color for the buttons representing the other months.
- *
- * @param chosenOtherButtonColor
- * a color.
- */
- public void setChosenOtherButtonColor(final Color chosenOtherButtonColor) {
- checkButtonColor(chosenOtherButtonColor);
- final Color oldValue = this.chosenOtherButtonColor;
- this.chosenOtherButtonColor = chosenOtherButtonColor;
- refreshButtons();
- firePropertyChange("chosenOtherButtonColor", oldValue, chosenOtherButtonColor);
- }
-
- private static void checkButtonColor(Color color) {
- if (color == null) {
- throw new NullPointerException("UIColor must not be null.");
- }
- }
-}
+/* This is a modified version of the original DateChooserPanel.java from JFree.
+ * Changes:
+ * - The month selection is implemented with buttons instead of the originals JComboBox.
+ * This allows the component to be used in a popup.
+ * - The "today button" is now in the month selection panel and hasn't an non localized english label
+ * - Null dates are now allowed (no date is selected in the panel)
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+
+ * ========================================================================
+ * JCommon: a free general purpose class library for the Java(tm) platform
+ * ========================================================================
+ *
+ * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
+ *
+ * Project Info: http://www.jfree.org/jcommon/index.html
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
+ * in the United States and other countries.]
+ *
+ * ---------------------
+ * DateChooserPanel.java
+ * ---------------------
+ * (C) Copyright 2000-2004, by Object Refinery Limited.
+ *
+ * Original Author: David Gilbert (for Object Refinery Limited);
+ * Contributor(s): -;
+ *
+ * $Id: DateChooserPanel.java,v 1.11 2007/11/02 17:50:36 taqua Exp $
+ *
+ * Changes (from 26-Oct-2001)
+ * --------------------------
+ * 26-Oct-2001: Changed package to com.jrefinery.ui.* (DG);
+ * 08-Dec-2001: Dropped the getMonths() method (DG);
+ * 13-Oct-2002: Fixed errors reported by Checkstyle (DG);
+ * 02-Nov-2005: Fixed a bug where the current day-of-the-month is past
+ * the end of the newly selected month when the month or year
+ * combo boxes are changed - see bug id 1344319 (DG);
+ *
+ */
+
+package com.fathzer.soft.ajlib.swing.widget.date;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.text.DateFormatSymbols;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+
+import com.fathzer.soft.ajlib.utilities.NullUtils;
+
+/**
+ * A panel that allows the user to select a date.
+ * @author David Gilbert (modified by Jean-Marc Astesana)
+ */
+public class CalendarWidget extends JPanel {
+ private static final long serialVersionUID = 1L;
+ public static final String DATE_PROPERTY = "DATE_PROPERTY";
+
+ /**
+ * The date selected in the panel.
+ */
+ private Calendar chosenDate;
+
+ /**
+ * The color for the selected date.
+ */
+ private Color chosenDateButtonColor;
+
+ /**
+ * The color for dates in the current month.
+ */
+ private Color chosenMonthButtonColor;
+
+ /**
+ * The color for dates that are visible, but not in the current month.
+ */
+ private Color chosenOtherButtonColor;
+
+ /**
+ * The first day-of-the-week.
+ */
+ private int firstDayOfWeek;
+
+ /**
+ * The font used to display the date.
+ */
+ private Float fontRatio = 0.85f;
+
+ /**
+ * An array of buttons used to display the days-of-the-month.
+ */
+ private JButton[] buttons;
+
+ /**
+ * An array of labels used to display day of week names.
+ */
+ private JLabel[] days;
+
+ private MonthWidget monthSelector;
+
+ /**
+ * The ordered set of all seven days of a week, beginning with the
+ * 'firstDayOfWeek'.
+ */
+ private int[] weekDays;
+
+ /**
+ * Constructs a new date chooser panel, using today's date as the initial
+ * selection.
+ */
+ public CalendarWidget() {
+ super(new BorderLayout());
+
+ //TODO It would be cool to choose colors from the current Look and Feel ... but I didn't succeed in doing that :-(
+ this.chosenDateButtonColor = Color.red;
+ this.chosenMonthButtonColor = Color.white;
+ this.chosenOtherButtonColor = Color.gray;
+
+ // the default date is today...
+ this.chosenDate = Calendar.getInstance(getLocale());
+ initializeDays();
+
+ monthSelector = new MonthWidget();
+ add(monthSelector, BorderLayout.NORTH);
+ add(getCalendarPanel(), BorderLayout.CENTER);
+ monthSelector.addPropertyChangeListener(MonthWidget.DATE_PROPERTY, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ refreshButtons();
+ }
+ });
+ monthSelector.getNow().addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ setDate(new Date());
+ }
+ });
+ refreshButtons();
+ }
+
+ @Override
+ public void setLocale(Locale l) {
+ super.setLocale(l);
+ monthSelector.setLocale(l);
+ initializeDays();
+ updateDays();
+ refreshButtons();
+ }
+
+ private void initializeDays() {
+ this.firstDayOfWeek = Calendar.getInstance(getLocale()).getFirstDayOfWeek();
+ this.weekDays = new int[7];
+ for (int i = 0; i < 7; i++) {
+ this.weekDays[i] = ((this.firstDayOfWeek + i - 1) % 7) + 1;
+ }
+ }
+
+ /**
+ * Sets the date chosen in the panel.
+ *
+ * @param theDate
+ * the new date.
+ */
+ public void setDate(final Date theDate) {
+ Date old = this.getDate();
+ if (!NullUtils.areEquals(theDate, old)) {
+ if (theDate == null) {
+ this.chosenDate = null;
+ } else {
+ if (this.chosenDate == null) {
+ this.chosenDate = Calendar.getInstance(getLocale());
+ }
+ this.chosenDate.setTime(theDate);
+ this.monthSelector.setMonth(theDate);
+ }
+ refreshButtons();
+ this.firePropertyChange(DATE_PROPERTY, old, theDate);
+ }
+ }
+
+ /**
+ * Returns the date selected in the panel.
+ *
+ * @return the selected date.
+ */
+ public Date getDate() {
+ return this.chosenDate == null ? null : this.chosenDate.getTime();
+ }
+
+ /**
+ * Returns a panel of buttons, each button representing a day in the month.
+ * This is a sub-component of the DatePanel.
+ *
+ * @return the panel.
+ */
+ private JPanel getCalendarPanel() {
+ final JPanel p = new JPanel(new GridLayout(7, 7));
+ final DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(getLocale());
+ final String[] weekDays = dateFormatSymbols.getShortWeekdays();
+ this.days = new JLabel[this.weekDays.length];
+
+ for (int i = 0; i < this.weekDays.length; i++) {
+ this.days[i] = new JLabel(weekDays[this.weekDays[i]], SwingConstants.CENTER);
+ p.add(this.days[i]);
+ }
+
+ this.buttons = new JButton[42];
+ ActionListener listener = new ActionListener() {
+ /**
+ * Handles action-events from the date panel.
+ * @param e information about the event that occurred.
+ */
+ public void actionPerformed(final ActionEvent e) {
+ final JButton b = (JButton) e.getSource();
+ final int i = Integer.parseInt(b.getName());
+ final Calendar cal = getFirstVisibleDate();
+ cal.add(Calendar.DATE, i);
+ setDate(cal.getTime());
+ }
+ };
+ Font bFont = null;
+ for (int i = 0; i < 42; i++) {
+ final JButton b = new JButton("");
+ if (bFont==null) {
+ bFont = b.getFont().deriveFont(fontRatio*b.getFont().getSize());
+ }
+ b.setMargin(new Insets(1, 1, 1, 1));
+ b.setName(Integer.toString(i));
+ b.setFont(bFont);
+ b.setFocusPainted(false);
+ b.setActionCommand("dateButtonClicked");
+ b.addActionListener(listener);
+ this.buttons[i] = b;
+ p.add(b);
+ }
+ return p;
+ }
+
+ private void updateDays() {
+ final DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(getLocale());
+ final String[] weekDaysWordings = dateFormatSymbols.getShortWeekdays();
+ for (int i = 0; i < days.length; i++) {
+ days[i].setText(weekDaysWordings[this.weekDays[i]]);
+ }
+ }
+
+ /**
+ * Returns true if the two dates are equal (time of day is ignored).
+ *
+ * @param c1
+ * the first date.
+ * @param c2
+ * the second date.
+ * @return boolean.
+ */
+ private boolean equalDates(final Calendar c1, final Calendar c2) {
+ // Be aware that c1 or c2 can be null
+ if ((c1 == null) && (c2 == null)) {
+ return true;
+ }
+ if ((c1 == null) || (c2 == null)) {
+ return false;
+ }
+ return (c1.get(Calendar.DATE) == c2.get(Calendar.DATE)) && (c1.get(Calendar.MONTH) == c2.get(Calendar.MONTH))
+ && (c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR));
+ }
+
+ /**
+ * Returns the first date that is visible in the grid. This should always be
+ * in the month preceding the month of the selected date.
+ *
+ * @return the date.
+ */
+ private Calendar getFirstVisibleDate() {
+ final Calendar c = Calendar.getInstance(getLocale());
+ c.setTime(this.monthSelector.getMonth());
+ c.add(Calendar.DATE, -1);
+ while (c.get(Calendar.DAY_OF_WEEK) != getFirstDayOfWeek()) {
+ c.add(Calendar.DATE, -1);
+ }
+ return c;
+ }
+
+ /**
+ * Returns the first day of the week (controls the labels in the date panel).
+ *
+ * @return the first day of the week.
+ */
+ private int getFirstDayOfWeek() {
+ return this.firstDayOfWeek;
+ }
+
+ /**
+ * Update the button labels and colors to reflect date selection.
+ */
+ private void refreshButtons() {
+ final Calendar c = getFirstVisibleDate();
+ final Calendar current = Calendar.getInstance(getLocale());
+ current.setTime(this.monthSelector.getMonth());
+ for (int i = 0; i < 42; i++) {
+ final JButton b = this.buttons[i];
+ setButtonAppearance(b, c, current);
+ c.add(Calendar.DATE, 1);
+ }
+ }
+
+ /** Sets a date button appearance.
+ * @param button The button to be set up
+ * @param date The date represented by the button
+ * @param currentMonth The currently displayed month
+ */
+ private void setButtonAppearance(JButton button, Calendar date, Calendar currentMonth) {
+ String day = Integer.toString(date.get(Calendar.DATE));
+ Color color;
+ if (equalDates(date, this.chosenDate)) {
+ color = this.chosenDateButtonColor;
+ } else if ((date.get(Calendar.MONTH) == currentMonth.get(Calendar.MONTH))
+ && (date.get(Calendar.YEAR) == currentMonth.get(Calendar.YEAR))) {
+ color = this.chosenMonthButtonColor;
+ } else {
+ color = this.chosenOtherButtonColor;
+ }
+ button.setBackground(color);
+ if (equalDates(date, Calendar.getInstance())) {
+ day = ""+day+"";
+ }
+ button.setText(day);
+ }
+
+ /**
+ * Returns the color for the currently selected date.
+ *
+ * @return a color.
+ */
+ public Color getChosenDateButtonColor() {
+ return this.chosenDateButtonColor;
+ }
+
+ /**
+ * Redefines the color for the currently selected date.
+ *
+ * @param chosenDateButtonColor
+ * the new color
+ */
+ public void setChosenDateButtonColor(final Color chosenDateButtonColor) {
+ checkButtonColor(chosenDateButtonColor);
+ final Color oldValue = this.chosenDateButtonColor;
+ this.chosenDateButtonColor = chosenDateButtonColor;
+ refreshButtons();
+ firePropertyChange("chosenDateButtonColor", oldValue, chosenDateButtonColor);
+ }
+
+ /**
+ * Returns the color for the buttons representing the current month.
+ *
+ * @return the color for the current month.
+ */
+ public Color getChosenMonthButtonColor() {
+ return this.chosenMonthButtonColor;
+ }
+
+ /**
+ * Defines the color for the buttons representing the current month.
+ *
+ * @param chosenMonthButtonColor
+ * the color for the current month.
+ */
+ public void setChosenMonthButtonColor(final Color chosenMonthButtonColor) {
+ checkButtonColor(chosenMonthButtonColor);
+ final Color oldValue = this.chosenMonthButtonColor;
+ this.chosenMonthButtonColor = chosenMonthButtonColor;
+ refreshButtons();
+ firePropertyChange("chosenMonthButtonColor", oldValue, chosenMonthButtonColor);
+ }
+
+ /**
+ * Returns the color for the buttons representing the other months.
+ *
+ * @return a color.
+ */
+ public Color getChosenOtherButtonColor() {
+ return this.chosenOtherButtonColor;
+ }
+
+ /**
+ * Redefines the color for the buttons representing the other months.
+ *
+ * @param chosenOtherButtonColor
+ * a color.
+ */
+ public void setChosenOtherButtonColor(final Color chosenOtherButtonColor) {
+ checkButtonColor(chosenOtherButtonColor);
+ final Color oldValue = this.chosenOtherButtonColor;
+ this.chosenOtherButtonColor = chosenOtherButtonColor;
+ refreshButtons();
+ firePropertyChange("chosenOtherButtonColor", oldValue, chosenOtherButtonColor);
+ }
+
+ private static void checkButtonColor(Color color) {
+ if (color == null) {
+ throw new NullPointerException("UIColor must not be null.");
+ }
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/DateField.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/DateField.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/date/DateField.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/DateField.java
index 63bf027..fe00f18 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/DateField.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/DateField.java
@@ -1,257 +1,257 @@
-package com.fathzer.soft.ajlib.swing.widget.date;
-
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.Locale;
-
-import com.fathzer.soft.ajlib.swing.widget.TextWidget;
-import com.fathzer.soft.ajlib.utilities.CoolDateFormatter;
-import com.fathzer.soft.ajlib.utilities.NullUtils;
-
-/** This class allows the user to just enter a day, or a day and a month, instead of a complete date (day, month, year).
- * It auto completes the typed date with the current month and year.
- * This field allows you to define what an empty field means. By default, an empty field means a null date, but, using the
- * setEmptyDate method, you can change this behavior.
- * This field has an inputVerifier in order to prevent entering something that is not a date in the field. By default, an empty
- * field is allowed, you can change that calling setIsEmptyNullDateValid. Keep in mind that if you called the setEmptyDate method
- * with a non null argument, the empty field will always be valid.
- * The up/down arrow keys increments/decrements the date.
- */
-public class DateField extends TextWidget {
- private static final long serialVersionUID = 1L;
- public static final String DATE_PROPERTY = "date";
- public static final String CONTENT_VALID_PROPERTY = "contentValid";
-
- private CoolDateFormatter formatter;
- private Date date;
- private boolean valid;
- private Date emptyValue;
- private boolean isEmptyNullDateValid;
-
- /** Constructor.
- * Creates a new Date widget. The date is set to today, the empty date is set to null.
- * @see #setEmptyDate(Date)
- */
- public DateField() {
- this(null);
- }
-
- /** Constructor.
- * Creates a new Date widget. The date is set to today.
- * @param emptyDate The date to be set if the field becomes empty
- * @see #setEmptyDate(Date)
- */
- public DateField(Date emptyDate) {
- super();
- this.setColumns(7);
- this.isEmptyNullDateValid = true;
- this.emptyValue = emptyDate;
- formatter = new CoolDateFormatter(getLocale());
- // Set the field to today's date
- Calendar calendar = Calendar.getInstance(getLocale());
- CoolDateFormatter.eraseTime(calendar);
- this.setDate(calendar.getTime());
- this.addKeyListener(new KeyAdapter() {
- @Override
- public void keyTyped(KeyEvent e) {
- // Nothing to do, all the job is done in keyPressed
- }
-
- @Override
- public void keyPressed(KeyEvent e) {
- int increment = 0;
- if (e.getKeyCode()==KeyEvent.VK_DOWN) {
- // Set the date to next day after the current date
- increment = -1;
- } else if (e.getKeyCode()==KeyEvent.VK_UP) {
- // Set the date to previous day before the current date
- increment = 1;
- }
- if ((increment!=0) && (getDate()!=null)) {
- Calendar calendar = Calendar.getInstance();
- calendar.setTime(getDate());
- calendar.add(Calendar.DATE, increment);
- setDate(calendar.getTime());
- }
- }
-
- });
- this.addPropertyChangeListener(TEXT_PROPERTY, new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- updateDate();
- }
- });
- this.addFocusListener(new FocusListener() {
- @Override
- public void focusLost(FocusEvent e) {
- if (!e.isTemporary()) {
- DateField.super.setText(date==null?"":formatter.format(date));
- }
- }
- @Override
- public void focusGained(FocusEvent e) {
- // Nothing to do
- }
- });
- }
-
- @Override
- public void setLocale(Locale locale) {
- super.setLocale(locale);
- this.formatter = new CoolDateFormatter(locale);
- if (date!=null) {
- this.setText(formatter.format(date));
- }
- }
-
- /** Set the meaning of an empty field.
- * @param date The date that a is equivalent to an empty field.
- * By default, this date is null.
- */
- public void setEmptyDate(Date date) {
- this.emptyValue = date;
- if (this.getText().trim().length()==0) {
- updateDate();
- }
- }
-
- /** Allow/Disallow this field to be empty (if it means a null date).
- *
Keep in mind that a non null date for an empty field is always valid.
- * @param valid true if null is a valid date.
- * @see #setEmptyDate(Date)
- */
- public void setIsEmptyNullDateIsValid(boolean valid) {
- this.isEmptyNullDateValid = valid;
- if (this.getText().trim().isEmpty()) {
- updateDate();
- }
- }
-
- private static Date parseRelativeDate(CharSequence text) {
- Date result = null;
- if (text.length()>1) {
- char c = text.charAt(0);
- if (c=='+' || c=='-') {
- int count = 1;
- while (text.length()>count && text.charAt(count)==c) {
- count++;
- }
- String num =text.toString().substring(count);
- if (count<=3 && num.matches("\\d+")) {
- int nb = Integer.parseInt(num);
- GregorianCalendar cal = new GregorianCalendar();
- cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DATE), 0,0,0);
- cal.add(new int[]{Calendar.DATE, Calendar.MONTH, Calendar.YEAR}[count-1], c=='+'?nb:-nb);
- return cal.getTime();
- }
- }
- }
- return result;
- }
-
- @SuppressWarnings("deprecation")
- private void updateDate() {
- String text = this.getText().trim();
- if (text.isEmpty()) {
- internalSetDate(emptyValue, (emptyValue!=null) || isEmptyNullDateValid);
- } else {
- Date changed = parseRelativeDate(text);
- if (changed==null) {
- try {
- changed = formatter.parse(text);
- int year = changed.getYear()+1900;
- if (year<10) {
- // When the user enters a date with only one char for the year, it is interpreted as the full year (ie 9 -> year 9)
- // So, we have to add the right century to this year
- SimpleDateFormat simpleFormat = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT);
- Date formatterStartYear = simpleFormat.get2DigitYearStart();
- year += ((formatterStartYear.getYear()+1900)/100)*100;
- changed.setYear(year-1900);
- // If that date is not in the 100 year period of the formatter, add one century
- // Note: I compare the getTime() results, because, sometime, an exception is thrown that tells that instances are not of the same class
- if (changed.getTime()-formatterStartYear.getTime()<0) {
- changed.setYear(year-1800);
- }
- }
- } catch (ParseException e) {
- try {
- int day = Integer.parseInt(text);
- GregorianCalendar today = new GregorianCalendar();
- if ((day>0) && (day<=today.getActualMaximum(Calendar.DAY_OF_MONTH))) {
- changed = new GregorianCalendar(today.get(Calendar.YEAR),today.get(Calendar.MONTH),day).getTime();
- }
- } catch (NumberFormatException e1) {
- try {
- text = text+"/"+new GregorianCalendar().get(Calendar.YEAR);
- changed = formatter.parse(text+"/"+new GregorianCalendar().get(Calendar.YEAR));
- } catch (ParseException e2) {
- }
- }
- }
- }
- internalSetDate(changed, changed!=null);
- }
- }
-
- /** Get the widget current date.
- * @return The date. If the value contained by the field is not valid, returns null.
- */
- public Date getDate() {
- return this.date;
- }
-
- /** Set the widget date.
- * The text field is updated.
- * @param date The date to set.
- */
- public void setDate(Date date) {
- super.setText(date==null?"":formatter.format(date));
- if (date==null) {
- date = emptyValue;
- }
- internalSetDate(date, date!=null || isEmptyNullDateValid);
- }
-
- @Override
- public void setText(String t) {
- super.setText(t);
- updateDate();
- }
-
- /** Set the date without changing the content of the TextField.
- * This method does nothing if the date is equals to the current widget date.
- * @param date
- * @return true if the value was changed
- */
- private boolean internalSetDate(Date date, boolean isValid) {
- boolean changed = ! NullUtils.areEquals(date, this.date);
- if (changed) {
- Date old = this.date;
- this.date = date;
- firePropertyChange(DATE_PROPERTY, old, date);
- }
- if (isValid!=this.valid) {
- this.valid = isValid;
- firePropertyChange(CONTENT_VALID_PROPERTY, !this.valid, this.valid);
- }
- return changed;
- }
-
- /** Gets the content validity.
- * @return true if the content is valid, false if it is not.
- */
- public boolean isContentValid() {
- return this.valid;
- }
-}
+package com.fathzer.soft.ajlib.swing.widget.date;
+
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+
+import com.fathzer.soft.ajlib.swing.widget.TextWidget;
+import com.fathzer.soft.ajlib.utilities.CoolDateFormatter;
+import com.fathzer.soft.ajlib.utilities.NullUtils;
+
+/** This class allows the user to just enter a day, or a day and a month, instead of a complete date (day, month, year).
+ * It auto completes the typed date with the current month and year.
+ * This field allows you to define what an empty field means. By default, an empty field means a null date, but, using the
+ * setEmptyDate method, you can change this behavior.
+ * This field has an inputVerifier in order to prevent entering something that is not a date in the field. By default, an empty
+ * field is allowed, you can change that calling setIsEmptyNullDateValid. Keep in mind that if you called the setEmptyDate method
+ * with a non null argument, the empty field will always be valid.
+ * The up/down arrow keys increments/decrements the date.
+ */
+public class DateField extends TextWidget {
+ private static final long serialVersionUID = 1L;
+ public static final String DATE_PROPERTY = "date";
+ public static final String CONTENT_VALID_PROPERTY = "contentValid";
+
+ private CoolDateFormatter formatter;
+ private Date date;
+ private boolean valid;
+ private Date emptyValue;
+ private boolean isEmptyNullDateValid;
+
+ /** Constructor.
+ * Creates a new Date widget. The date is set to today, the empty date is set to null.
+ * @see #setEmptyDate(Date)
+ */
+ public DateField() {
+ this(null);
+ }
+
+ /** Constructor.
+ * Creates a new Date widget. The date is set to today.
+ * @param emptyDate The date to be set if the field becomes empty
+ * @see #setEmptyDate(Date)
+ */
+ public DateField(Date emptyDate) {
+ super();
+ this.setColumns(7);
+ this.isEmptyNullDateValid = true;
+ this.emptyValue = emptyDate;
+ formatter = new CoolDateFormatter(getLocale());
+ // Set the field to today's date
+ Calendar calendar = Calendar.getInstance(getLocale());
+ CoolDateFormatter.eraseTime(calendar);
+ this.setDate(calendar.getTime());
+ this.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyTyped(KeyEvent e) {
+ // Nothing to do, all the job is done in keyPressed
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+ int increment = 0;
+ if (e.getKeyCode()==KeyEvent.VK_DOWN) {
+ // Set the date to next day after the current date
+ increment = -1;
+ } else if (e.getKeyCode()==KeyEvent.VK_UP) {
+ // Set the date to previous day before the current date
+ increment = 1;
+ }
+ if ((increment!=0) && (getDate()!=null)) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(getDate());
+ calendar.add(Calendar.DATE, increment);
+ setDate(calendar.getTime());
+ }
+ }
+
+ });
+ this.addPropertyChangeListener(TEXT_PROPERTY, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ updateDate();
+ }
+ });
+ this.addFocusListener(new FocusListener() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (!e.isTemporary()) {
+ DateField.super.setText(date==null?"":formatter.format(date));
+ }
+ }
+ @Override
+ public void focusGained(FocusEvent e) {
+ // Nothing to do
+ }
+ });
+ }
+
+ @Override
+ public void setLocale(Locale locale) {
+ super.setLocale(locale);
+ this.formatter = new CoolDateFormatter(locale);
+ if (date!=null) {
+ this.setText(formatter.format(date));
+ }
+ }
+
+ /** Set the meaning of an empty field.
+ * @param date The date that a is equivalent to an empty field.
+ * By default, this date is null.
+ */
+ public void setEmptyDate(Date date) {
+ this.emptyValue = date;
+ if (this.getText().trim().length()==0) {
+ updateDate();
+ }
+ }
+
+ /** Allow/Disallow this field to be empty (if it means a null date).
+ *
Keep in mind that a non null date for an empty field is always valid.
+ * @param valid true if null is a valid date.
+ * @see #setEmptyDate(Date)
+ */
+ public void setIsEmptyNullDateIsValid(boolean valid) {
+ this.isEmptyNullDateValid = valid;
+ if (this.getText().trim().isEmpty()) {
+ updateDate();
+ }
+ }
+
+ private static Date parseRelativeDate(CharSequence text) {
+ Date result = null;
+ if (text.length()>1) {
+ char c = text.charAt(0);
+ if (c=='+' || c=='-') {
+ int count = 1;
+ while (text.length()>count && text.charAt(count)==c) {
+ count++;
+ }
+ String num =text.toString().substring(count);
+ if (count<=3 && num.matches("\\d+")) {
+ int nb = Integer.parseInt(num);
+ GregorianCalendar cal = new GregorianCalendar();
+ cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DATE), 0,0,0);
+ cal.add(new int[]{Calendar.DATE, Calendar.MONTH, Calendar.YEAR}[count-1], c=='+'?nb:-nb);
+ return cal.getTime();
+ }
+ }
+ }
+ return result;
+ }
+
+ @SuppressWarnings("deprecation")
+ private void updateDate() {
+ String text = this.getText().trim();
+ if (text.isEmpty()) {
+ internalSetDate(emptyValue, (emptyValue!=null) || isEmptyNullDateValid);
+ } else {
+ Date changed = parseRelativeDate(text);
+ if (changed==null) {
+ try {
+ changed = formatter.parse(text);
+ int year = changed.getYear()+1900;
+ if (year<10) {
+ // When the user enters a date with only one char for the year, it is interpreted as the full year (ie 9 -> year 9)
+ // So, we have to add the right century to this year
+ SimpleDateFormat simpleFormat = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT);
+ Date formatterStartYear = simpleFormat.get2DigitYearStart();
+ year += ((formatterStartYear.getYear()+1900)/100)*100;
+ changed.setYear(year-1900);
+ // If that date is not in the 100 year period of the formatter, add one century
+ // Note: I compare the getTime() results, because, sometime, an exception is thrown that tells that instances are not of the same class
+ if (changed.getTime()-formatterStartYear.getTime()<0) {
+ changed.setYear(year-1800);
+ }
+ }
+ } catch (ParseException e) {
+ try {
+ int day = Integer.parseInt(text);
+ GregorianCalendar today = new GregorianCalendar();
+ if ((day>0) && (day<=today.getActualMaximum(Calendar.DAY_OF_MONTH))) {
+ changed = new GregorianCalendar(today.get(Calendar.YEAR),today.get(Calendar.MONTH),day).getTime();
+ }
+ } catch (NumberFormatException e1) {
+ try {
+ text = text+"/"+new GregorianCalendar().get(Calendar.YEAR);
+ changed = formatter.parse(text+"/"+new GregorianCalendar().get(Calendar.YEAR));
+ } catch (ParseException e2) {
+ }
+ }
+ }
+ }
+ internalSetDate(changed, changed!=null);
+ }
+ }
+
+ /** Get the widget current date.
+ * @return The date. If the value contained by the field is not valid, returns null.
+ */
+ public Date getDate() {
+ return this.date;
+ }
+
+ /** Set the widget date.
+ * The text field is updated.
+ * @param date The date to set.
+ */
+ public void setDate(Date date) {
+ super.setText(date==null?"":formatter.format(date));
+ if (date==null) {
+ date = emptyValue;
+ }
+ internalSetDate(date, date!=null || isEmptyNullDateValid);
+ }
+
+ @Override
+ public void setText(String t) {
+ super.setText(t);
+ updateDate();
+ }
+
+ /** Set the date without changing the content of the TextField.
+ * This method does nothing if the date is equals to the current widget date.
+ * @param date
+ * @return true if the value was changed
+ */
+ private boolean internalSetDate(Date date, boolean isValid) {
+ boolean changed = ! NullUtils.areEquals(date, this.date);
+ if (changed) {
+ Date old = this.date;
+ this.date = date;
+ firePropertyChange(DATE_PROPERTY, old, date);
+ }
+ if (isValid!=this.valid) {
+ this.valid = isValid;
+ firePropertyChange(CONTENT_VALID_PROPERTY, !this.valid, this.valid);
+ }
+ return changed;
+ }
+
+ /** Gets the content validity.
+ * @return true if the content is valid, false if it is not.
+ */
+ public boolean isContentValid() {
+ return this.valid;
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/DateWidget.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/DateWidget.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/date/DateWidget.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/DateWidget.java
index 19841f9..54404d0 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/DateWidget.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/DateWidget.java
@@ -1,171 +1,171 @@
-package com.fathzer.soft.ajlib.swing.widget.date;
-
-import java.awt.GridBagLayout;
-import javax.swing.JPanel;
-import javax.swing.JPopupMenu;
-
-import java.awt.GridBagConstraints;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.util.Date;
-import java.util.Locale;
-
-import javax.swing.JLabel;
-
-import com.fathzer.soft.ajlib.swing.Utils;
-
-
-/** This panel contains a DateField and a button that shows a calendar popup.
- * As this widget (especially the DateWidget it contains) represents years with two digits, it can only represent dates near today (ie, impossible to represent a date before 1900)
- * @see DateField
- * @see CalendarWidget
- */
-public class DateWidget extends JPanel {
- private static final long serialVersionUID = 1L;
- /** Date change property name.
- * The panel is a bean. Every time the chosen date changed, it sends a PropertyChangedEvent.
- */
- public static final String DATE_PROPERTY = DateField.DATE_PROPERTY; // @jve:decl-index=0:
- /** Content validity property name.
- * The panel is a bean. Every time the content validity changed, it sends a PropertyChangedEvent.
- */
- public static final String CONTENT_VALID_PROPERTY = DateField.CONTENT_VALID_PROPERTY;
-
- private DateField dateField = null;
- private CalendarWidget dateChooser;
- private JPopupMenu popup;
- private JLabel jLabel = null;
-
- /**
- * This is the default constructor.
- * Creates a new panel with the system default locale.
- * The date is set to today
- */
- public DateWidget() {
- super();
- popup = new JPopupMenu();
- dateChooser = new CalendarWidget();
- popup.add(dateChooser);
- initialize();
- dateChooser.addPropertyChangeListener(CalendarWidget.DATE_PROPERTY, new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- getDateField().setDate((Date)evt.getNewValue());
- popup.setVisible(false);
- }
- });
- }
-
- /** Get the currently chosen date.
- * @return the currently chosen date (null if the date is wrong). It is guaranteed that the hours, minutes, seconds,
- * milliseconds of the date are set to 0.
- */
- public Date getDate() {
- return getDateField().getDate();
- }
-
- /** Set the currently chosen date.
- * @param date the date to be set.
- */
- public void setDate(Date date) {
- getDateField().setDate(date);
- // No need to fire a property change.
- // The change property event will be sent by the property change listener
- // that is waiting for change of the DateWidget
- }
-
- /** Set the number of columns of the date text field.
- * @param nb number of columns of the text field
- */
- public void setColumns(int nb) {
- this.getDateField().setColumns(nb);
- }
-
- /** Set the locale.
- * Changes the calendar popup appearence and the text field format.
- */
- @Override
- public void setLocale(Locale locale) {
- getDateField().setLocale(locale);
- dateChooser.setLocale(locale);
- }
-
- /** Set the DateWidget tooltip.
- * @param text the new tooltip text
- */
- @Override
- public void setToolTipText(String text) {
- getDateField().setToolTipText(text);
- }
-
- /**
- * This method initializes this
- */
- private void initialize() {
- GridBagConstraints gridBagConstraints11 = new GridBagConstraints();
- gridBagConstraints11.gridx = 1;
- gridBagConstraints11.fill = GridBagConstraints.VERTICAL;
- gridBagConstraints11.gridy = 0;
- jLabel = new JLabel();
- jLabel.setIcon(Utils.createIcon(DateWidget.class.getResource(MonthWidget.RES_PATH+"calendar.png"), 16*getFont().getSize()/12));
- jLabel.addMouseListener(new java.awt.event.MouseAdapter() {
- @Override
- public void mouseClicked(java.awt.event.MouseEvent e) {
- if (jLabel.isEnabled() && !popup.isVisible()) {
- DateField widget = getDateField();
- dateChooser.setDate(widget.getDate());
- popup.show(widget, 0, widget.getHeight());
- }
- }
- });
- GridBagConstraints gridBagConstraints = new GridBagConstraints();
- gridBagConstraints.fill = GridBagConstraints.BOTH;
- gridBagConstraints.gridy = 0;
- gridBagConstraints.weightx = 1.0;
- gridBagConstraints.gridx = 0;
- this.setLayout(new GridBagLayout());
- this.add(getDateField(), gridBagConstraints);
- this.add(jLabel, gridBagConstraints11);
- }
-
- /**
- * Gets the DateWidget used by this component.
- * @return a DateWidget instance
- */
- public DateField getDateField() {
- if (dateField == null) {
- dateField = new DateField();
- PropertyChangeListener listener = new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
- }
- };
- dateField.addPropertyChangeListener(DateField.DATE_PROPERTY, listener);
- dateField.addPropertyChangeListener(DateField.CONTENT_VALID_PROPERTY, listener);
- }
- return dateField;
- }
-
- /** Sets the validity of null date.
- * @param valid true if null should be considered valid.
- * @see DateField#setIsEmptyNullDateIsValid(boolean)
- */
- public void setIsEmptyNullDateIsValid(boolean valid) {
- this.getDateField().setIsEmptyNullDateIsValid(valid);
- }
-
- @Override
- public void setEnabled(boolean enabled) {
- super.setEnabled(enabled);
- dateField.setEnabled(enabled);
- jLabel.setEnabled(enabled);
- }
-
- /** Gets the content validity.
- * @return true if the content is valid, false if it is not.
- */
- public boolean isContentValid() {
- return this.dateField.isContentValid();
- }
-}
+package com.fathzer.soft.ajlib.swing.widget.date;
+
+import java.awt.GridBagLayout;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+
+import java.awt.GridBagConstraints;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Date;
+import java.util.Locale;
+
+import javax.swing.JLabel;
+
+import com.fathzer.soft.ajlib.swing.Utils;
+
+
+/** This panel contains a DateField and a button that shows a calendar popup.
+ * As this widget (especially the DateWidget it contains) represents years with two digits, it can only represent dates near today (ie, impossible to represent a date before 1900)
+ * @see DateField
+ * @see CalendarWidget
+ */
+public class DateWidget extends JPanel {
+ private static final long serialVersionUID = 1L;
+ /** Date change property name.
+ * The panel is a bean. Every time the chosen date changed, it sends a PropertyChangedEvent.
+ */
+ public static final String DATE_PROPERTY = DateField.DATE_PROPERTY; // @jve:decl-index=0:
+ /** Content validity property name.
+ * The panel is a bean. Every time the content validity changed, it sends a PropertyChangedEvent.
+ */
+ public static final String CONTENT_VALID_PROPERTY = DateField.CONTENT_VALID_PROPERTY;
+
+ private DateField dateField = null;
+ private CalendarWidget dateChooser;
+ private JPopupMenu popup;
+ private JLabel jLabel = null;
+
+ /**
+ * This is the default constructor.
+ * Creates a new panel with the system default locale.
+ * The date is set to today
+ */
+ public DateWidget() {
+ super();
+ popup = new JPopupMenu();
+ dateChooser = new CalendarWidget();
+ popup.add(dateChooser);
+ initialize();
+ dateChooser.addPropertyChangeListener(CalendarWidget.DATE_PROPERTY, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ getDateField().setDate((Date)evt.getNewValue());
+ popup.setVisible(false);
+ }
+ });
+ }
+
+ /** Get the currently chosen date.
+ * @return the currently chosen date (null if the date is wrong). It is guaranteed that the hours, minutes, seconds,
+ * milliseconds of the date are set to 0.
+ */
+ public Date getDate() {
+ return getDateField().getDate();
+ }
+
+ /** Set the currently chosen date.
+ * @param date the date to be set.
+ */
+ public void setDate(Date date) {
+ getDateField().setDate(date);
+ // No need to fire a property change.
+ // The change property event will be sent by the property change listener
+ // that is waiting for change of the DateWidget
+ }
+
+ /** Set the number of columns of the date text field.
+ * @param nb number of columns of the text field
+ */
+ public void setColumns(int nb) {
+ this.getDateField().setColumns(nb);
+ }
+
+ /** Set the locale.
+ * Changes the calendar popup appearence and the text field format.
+ */
+ @Override
+ public void setLocale(Locale locale) {
+ getDateField().setLocale(locale);
+ dateChooser.setLocale(locale);
+ }
+
+ /** Set the DateWidget tooltip.
+ * @param text the new tooltip text
+ */
+ @Override
+ public void setToolTipText(String text) {
+ getDateField().setToolTipText(text);
+ }
+
+ /**
+ * This method initializes this
+ */
+ private void initialize() {
+ GridBagConstraints gridBagConstraints11 = new GridBagConstraints();
+ gridBagConstraints11.gridx = 1;
+ gridBagConstraints11.fill = GridBagConstraints.VERTICAL;
+ gridBagConstraints11.gridy = 0;
+ jLabel = new JLabel();
+ jLabel.setIcon(Utils.createIcon(DateWidget.class.getResource(MonthWidget.RES_PATH+"calendar.png"), 16*getFont().getSize()/12));
+ jLabel.addMouseListener(new java.awt.event.MouseAdapter() {
+ @Override
+ public void mouseClicked(java.awt.event.MouseEvent e) {
+ if (jLabel.isEnabled() && !popup.isVisible()) {
+ DateField widget = getDateField();
+ dateChooser.setDate(widget.getDate());
+ popup.show(widget, 0, widget.getHeight());
+ }
+ }
+ });
+ GridBagConstraints gridBagConstraints = new GridBagConstraints();
+ gridBagConstraints.fill = GridBagConstraints.BOTH;
+ gridBagConstraints.gridy = 0;
+ gridBagConstraints.weightx = 1.0;
+ gridBagConstraints.gridx = 0;
+ this.setLayout(new GridBagLayout());
+ this.add(getDateField(), gridBagConstraints);
+ this.add(jLabel, gridBagConstraints11);
+ }
+
+ /**
+ * Gets the DateWidget used by this component.
+ * @return a DateWidget instance
+ */
+ public DateField getDateField() {
+ if (dateField == null) {
+ dateField = new DateField();
+ PropertyChangeListener listener = new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
+ }
+ };
+ dateField.addPropertyChangeListener(DateField.DATE_PROPERTY, listener);
+ dateField.addPropertyChangeListener(DateField.CONTENT_VALID_PROPERTY, listener);
+ }
+ return dateField;
+ }
+
+ /** Sets the validity of null date.
+ * @param valid true if null should be considered valid.
+ * @see DateField#setIsEmptyNullDateIsValid(boolean)
+ */
+ public void setIsEmptyNullDateIsValid(boolean valid) {
+ this.getDateField().setIsEmptyNullDateIsValid(valid);
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ dateField.setEnabled(enabled);
+ jLabel.setEnabled(enabled);
+ }
+
+ /** Gets the content validity.
+ * @return true if the content is valid, false if it is not.
+ */
+ public boolean isContentValid() {
+ return this.dateField.isContentValid();
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/MonthWidget.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/MonthWidget.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/date/MonthWidget.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/MonthWidget.java
index cd95a70..0d6afb1 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/MonthWidget.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/MonthWidget.java
@@ -1,235 +1,235 @@
-package com.fathzer.soft.ajlib.swing.widget.date;
-
-import java.awt.GridBagLayout;
-import javax.swing.JPanel;
-import javax.swing.JButton;
-import java.awt.GridBagConstraints;
-import javax.swing.JLabel;
-import java.awt.Insets;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Locale;
-
-import javax.swing.SwingConstants;
-
-import com.fathzer.soft.ajlib.swing.Utils;
-
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-
-/** A month selector.
- */
-public class MonthWidget extends JPanel {
- private static final long serialVersionUID = 1L;
- static final String RES_PATH = "/com/fathzer/soft/ajlib/swing/widget/date/";
-
- public static final String DATE_PROPERTY = "MONTH";
-
- private JButton previousYear = null;
- private JButton previousMonth = null;
- private JLabel currentMonth = null;
- private JButton nextMonth = null;
- private JButton nextYear = null;
-
- private Calendar currentDate;
- private DateFormat formater;
-
- private JButton now = null;
- private JPanel buttonsPanel;
-
- /**
- * This is the default constructor
- */
- public MonthWidget() {
- this.currentDate = Calendar.getInstance();
- this.currentDate.set(this.currentDate.get(Calendar.YEAR), this.currentDate.get(Calendar.MONTH), 1, 0, 0, 0);
- this.currentDate.set(Calendar.MILLISECOND, 0);
- this.formater = new SimpleDateFormat("MMMM yyyy");
- initialize();
- }
-
- @Override
- public void setLocale(Locale l) {
- super.setLocale(l);
- this.formater = new SimpleDateFormat("MMMM yyyy", l);
- this.currentMonth.setText(this.formater.format(currentDate.getTime()));
- }
-
- @SuppressWarnings("deprecation")
- public void setMonth(Date date) {
- if ((date.getYear()+1900!=this.currentDate.get(Calendar.YEAR)) || (date.getMonth()!=this.currentDate.get(Calendar.MONTH))) {
- Date old = this.currentDate.getTime();
- this.currentDate.set(date.getYear()+1900, date.getMonth(), 1);
- this.currentMonth.setText(formater.format(date));
- this.firePropertyChange(DATE_PROPERTY, old, this.currentDate.getTime());
- }
- }
-
- /** Get the currently selected month.
- * @return The first day of the selected month at 0:0:0 AM.
- */
- public Date getMonth() {
- return this.currentDate.getTime();
- }
-
- /** Move forward or backward the currently selected month.
- * @param months The number of months to increment the current month. This amount can be negative.
- */
- public void add(int months) {
- Date old = this.currentDate.getTime();
- this.currentDate.add(Calendar.MONTH, months);
- Date newDate = this.currentDate.getTime();
- this.currentMonth.setText(formater.format(newDate));
- this.firePropertyChange(DATE_PROPERTY, old, newDate);
- }
-
- /**
- * This method initializes this
- */
- private void initialize() {
- GridBagConstraints gridBagConstraints2 = new GridBagConstraints();
- gridBagConstraints2.gridx = 0;
- gridBagConstraints2.fill = GridBagConstraints.HORIZONTAL;
- gridBagConstraints2.weightx = 1.0D;
- gridBagConstraints2.anchor = GridBagConstraints.CENTER;
- gridBagConstraints2.insets = new Insets(5, 5, 5, 0);
- gridBagConstraints2.gridy = 0;
- currentMonth = new JLabel();
- currentMonth.setText(formater.format(this.currentDate.getTime()));
- currentMonth.setHorizontalTextPosition(SwingConstants.CENTER);
- currentMonth.setHorizontalAlignment(SwingConstants.CENTER);
- this.setLayout(new GridBagLayout());
- GridBagConstraints gbcButtonsPanel = new GridBagConstraints();
- gbcButtonsPanel.gridx = 0;
- gbcButtonsPanel.gridy = 1;
- add(getButtonsPanel(), gbcButtonsPanel);
- this.add(currentMonth, gridBagConstraints2);
- }
-
- /**
- * This method initializes previousYear
- *
- * @return javax.swing.JButton
- */
- private JButton getPreviousYear() {
- if (previousYear == null) {
- previousYear = new JButton();
- previousYear.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"fast-rewind.png"), 16*getFont().getSize()/12));
- previousYear.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent e) {
- add(-12);
- }
- });
- }
- return previousYear;
- }
-
- /**
- * This method initializes previousMonth
- *
- * @return javax.swing.JButton
- */
- private JButton getPreviousMonth() {
- if (previousMonth == null) {
- previousMonth = new JButton();
- previousMonth.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"rewind.png"), 16*getFont().getSize()/12));
- previousMonth.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent e) {
- add(-1);
- }
- });
- }
- return previousMonth;
- }
-
- /**
- * This method initializes nextMonth
- *
- * @return javax.swing.JButton
- */
- private JButton getNextMonth() {
- if (nextMonth == null) {
- nextMonth = new JButton();
- nextMonth.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"forward.png"), 16*getFont().getSize()/12));
- nextMonth.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent e) {
- add(1);
- }
- });
- }
- return nextMonth;
- }
-
- /**
- * This method initializes nextYear
- *
- * @return javax.swing.JButton
- */
- private JButton getNextYear() {
- if (nextYear == null) {
- nextYear = new JButton();
- nextYear.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"fast-forward.png"), 16*getFont().getSize()/12));
- nextYear.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent e) {
- add(12);
- }
- });
- }
- return nextYear;
- }
-
- /**
- * This method initializes now
- * @return javax.swing.JButton
- */
- public JButton getNow() {
- if (now == null) {
- now = new JButton();
- now.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"stop.png"), 16*getFont().getSize()/12));
- now.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- setMonth(new Date());
- }
- });
- }
- return now;
- }
- private JPanel getButtonsPanel() {
- if (buttonsPanel == null) {
- buttonsPanel = new JPanel();
- GridBagLayout gblButtonsPanel = new GridBagLayout();
- buttonsPanel.setLayout(gblButtonsPanel);
- GridBagConstraints gbcPreviousYear = new GridBagConstraints();
- gbcPreviousYear.insets = new Insets(0, 0, 0, 5);
- gbcPreviousYear.gridx = 0;
- gbcPreviousYear.gridy = 0;
- buttonsPanel.add(getPreviousYear(), gbcPreviousYear);
- GridBagConstraints gbcPreviousMonth = new GridBagConstraints();
- gbcPreviousMonth.insets = new Insets(0, 0, 0, 5);
- gbcPreviousMonth.gridx = 1;
- gbcPreviousMonth.gridy = 0;
- buttonsPanel.add(getPreviousMonth(), gbcPreviousMonth);
- GridBagConstraints gbcNow = new GridBagConstraints();
- gbcNow.fill = GridBagConstraints.HORIZONTAL;
- gbcNow.insets = new Insets(0, 0, 0, 5);
- gbcNow.gridx = 2;
- gbcNow.gridy = 0;
- buttonsPanel.add(getNow(), gbcNow);
- GridBagConstraints gbcNextMonth = new GridBagConstraints();
- gbcNextMonth.insets = new Insets(0, 0, 0, 5);
- gbcNextMonth.gridx = 3;
- gbcNextMonth.gridy = 0;
- buttonsPanel.add(getNextMonth(), gbcNextMonth);
- GridBagConstraints gbcNextYear = new GridBagConstraints();
- gbcNextYear.anchor = GridBagConstraints.WEST;
- gbcNextYear.gridx = 4;
- gbcNextYear.gridy = 0;
- buttonsPanel.add(getNextYear(), gbcNextYear);
- }
- return buttonsPanel;
- }
-}
+package com.fathzer.soft.ajlib.swing.widget.date;
+
+import java.awt.GridBagLayout;
+import javax.swing.JPanel;
+import javax.swing.JButton;
+import java.awt.GridBagConstraints;
+import javax.swing.JLabel;
+import java.awt.Insets;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+import javax.swing.SwingConstants;
+
+import com.fathzer.soft.ajlib.swing.Utils;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+
+/** A month selector.
+ */
+public class MonthWidget extends JPanel {
+ private static final long serialVersionUID = 1L;
+ static final String RES_PATH = "/com/fathzer/soft/ajlib/swing/widget/date/";
+
+ public static final String DATE_PROPERTY = "MONTH";
+
+ private JButton previousYear = null;
+ private JButton previousMonth = null;
+ private JLabel currentMonth = null;
+ private JButton nextMonth = null;
+ private JButton nextYear = null;
+
+ private Calendar currentDate;
+ private DateFormat formater;
+
+ private JButton now = null;
+ private JPanel buttonsPanel;
+
+ /**
+ * This is the default constructor
+ */
+ public MonthWidget() {
+ this.currentDate = Calendar.getInstance();
+ this.currentDate.set(this.currentDate.get(Calendar.YEAR), this.currentDate.get(Calendar.MONTH), 1, 0, 0, 0);
+ this.currentDate.set(Calendar.MILLISECOND, 0);
+ this.formater = new SimpleDateFormat("MMMM yyyy");
+ initialize();
+ }
+
+ @Override
+ public void setLocale(Locale l) {
+ super.setLocale(l);
+ this.formater = new SimpleDateFormat("MMMM yyyy", l);
+ this.currentMonth.setText(this.formater.format(currentDate.getTime()));
+ }
+
+ @SuppressWarnings("deprecation")
+ public void setMonth(Date date) {
+ if ((date.getYear()+1900!=this.currentDate.get(Calendar.YEAR)) || (date.getMonth()!=this.currentDate.get(Calendar.MONTH))) {
+ Date old = this.currentDate.getTime();
+ this.currentDate.set(date.getYear()+1900, date.getMonth(), 1);
+ this.currentMonth.setText(formater.format(date));
+ this.firePropertyChange(DATE_PROPERTY, old, this.currentDate.getTime());
+ }
+ }
+
+ /** Get the currently selected month.
+ * @return The first day of the selected month at 0:0:0 AM.
+ */
+ public Date getMonth() {
+ return this.currentDate.getTime();
+ }
+
+ /** Move forward or backward the currently selected month.
+ * @param months The number of months to increment the current month. This amount can be negative.
+ */
+ public void add(int months) {
+ Date old = this.currentDate.getTime();
+ this.currentDate.add(Calendar.MONTH, months);
+ Date newDate = this.currentDate.getTime();
+ this.currentMonth.setText(formater.format(newDate));
+ this.firePropertyChange(DATE_PROPERTY, old, newDate);
+ }
+
+ /**
+ * This method initializes this
+ */
+ private void initialize() {
+ GridBagConstraints gridBagConstraints2 = new GridBagConstraints();
+ gridBagConstraints2.gridx = 0;
+ gridBagConstraints2.fill = GridBagConstraints.HORIZONTAL;
+ gridBagConstraints2.weightx = 1.0D;
+ gridBagConstraints2.anchor = GridBagConstraints.CENTER;
+ gridBagConstraints2.insets = new Insets(5, 5, 5, 0);
+ gridBagConstraints2.gridy = 0;
+ currentMonth = new JLabel();
+ currentMonth.setText(formater.format(this.currentDate.getTime()));
+ currentMonth.setHorizontalTextPosition(SwingConstants.CENTER);
+ currentMonth.setHorizontalAlignment(SwingConstants.CENTER);
+ this.setLayout(new GridBagLayout());
+ GridBagConstraints gbcButtonsPanel = new GridBagConstraints();
+ gbcButtonsPanel.gridx = 0;
+ gbcButtonsPanel.gridy = 1;
+ add(getButtonsPanel(), gbcButtonsPanel);
+ this.add(currentMonth, gridBagConstraints2);
+ }
+
+ /**
+ * This method initializes previousYear
+ *
+ * @return javax.swing.JButton
+ */
+ private JButton getPreviousYear() {
+ if (previousYear == null) {
+ previousYear = new JButton();
+ previousYear.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"fast-rewind.png"), 16*getFont().getSize()/12));
+ previousYear.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent e) {
+ add(-12);
+ }
+ });
+ }
+ return previousYear;
+ }
+
+ /**
+ * This method initializes previousMonth
+ *
+ * @return javax.swing.JButton
+ */
+ private JButton getPreviousMonth() {
+ if (previousMonth == null) {
+ previousMonth = new JButton();
+ previousMonth.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"rewind.png"), 16*getFont().getSize()/12));
+ previousMonth.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent e) {
+ add(-1);
+ }
+ });
+ }
+ return previousMonth;
+ }
+
+ /**
+ * This method initializes nextMonth
+ *
+ * @return javax.swing.JButton
+ */
+ private JButton getNextMonth() {
+ if (nextMonth == null) {
+ nextMonth = new JButton();
+ nextMonth.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"forward.png"), 16*getFont().getSize()/12));
+ nextMonth.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent e) {
+ add(1);
+ }
+ });
+ }
+ return nextMonth;
+ }
+
+ /**
+ * This method initializes nextYear
+ *
+ * @return javax.swing.JButton
+ */
+ private JButton getNextYear() {
+ if (nextYear == null) {
+ nextYear = new JButton();
+ nextYear.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"fast-forward.png"), 16*getFont().getSize()/12));
+ nextYear.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent e) {
+ add(12);
+ }
+ });
+ }
+ return nextYear;
+ }
+
+ /**
+ * This method initializes now
+ * @return javax.swing.JButton
+ */
+ public JButton getNow() {
+ if (now == null) {
+ now = new JButton();
+ now.setIcon(Utils.createIcon(getClass().getResource(RES_PATH+"stop.png"), 16*getFont().getSize()/12));
+ now.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ setMonth(new Date());
+ }
+ });
+ }
+ return now;
+ }
+ private JPanel getButtonsPanel() {
+ if (buttonsPanel == null) {
+ buttonsPanel = new JPanel();
+ GridBagLayout gblButtonsPanel = new GridBagLayout();
+ buttonsPanel.setLayout(gblButtonsPanel);
+ GridBagConstraints gbcPreviousYear = new GridBagConstraints();
+ gbcPreviousYear.insets = new Insets(0, 0, 0, 5);
+ gbcPreviousYear.gridx = 0;
+ gbcPreviousYear.gridy = 0;
+ buttonsPanel.add(getPreviousYear(), gbcPreviousYear);
+ GridBagConstraints gbcPreviousMonth = new GridBagConstraints();
+ gbcPreviousMonth.insets = new Insets(0, 0, 0, 5);
+ gbcPreviousMonth.gridx = 1;
+ gbcPreviousMonth.gridy = 0;
+ buttonsPanel.add(getPreviousMonth(), gbcPreviousMonth);
+ GridBagConstraints gbcNow = new GridBagConstraints();
+ gbcNow.fill = GridBagConstraints.HORIZONTAL;
+ gbcNow.insets = new Insets(0, 0, 0, 5);
+ gbcNow.gridx = 2;
+ gbcNow.gridy = 0;
+ buttonsPanel.add(getNow(), gbcNow);
+ GridBagConstraints gbcNextMonth = new GridBagConstraints();
+ gbcNextMonth.insets = new Insets(0, 0, 0, 5);
+ gbcNextMonth.gridx = 3;
+ gbcNextMonth.gridy = 0;
+ buttonsPanel.add(getNextMonth(), gbcNextMonth);
+ GridBagConstraints gbcNextYear = new GridBagConstraints();
+ gbcNextYear.anchor = GridBagConstraints.WEST;
+ gbcNextYear.gridx = 4;
+ gbcNextYear.gridy = 0;
+ buttonsPanel.add(getNextYear(), gbcNextYear);
+ }
+ return buttonsPanel;
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/package-info.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/package-info.java
similarity index 98%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/date/package-info.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/package-info.java
index ffd6d63..bf16d82 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/package-info.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/date/package-info.java
@@ -1,2 +1,2 @@
-/** Swing date widgets*/
+/** Swing date widgets*/
package com.fathzer.soft.ajlib.swing.widget.date;
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/widget/package-info.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/package-info.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/widget/package-info.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/package-info.java
index a06a5d6..e15eff2 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/widget/package-info.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/widget/package-info.java
@@ -1,2 +1,2 @@
-/** Swing widgets*/
-package com.fathzer.soft.ajlib.swing.widget;
+/** Swing widgets*/
+package com.fathzer.soft.ajlib.swing.widget;
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/worker/DefaultWorkInProgressPanel.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/worker/DefaultWorkInProgressPanel.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/swing/worker/DefaultWorkInProgressPanel.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/worker/DefaultWorkInProgressPanel.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/worker/WorkInProgressFrame.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/worker/WorkInProgressFrame.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/swing/worker/WorkInProgressFrame.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/worker/WorkInProgressFrame.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/worker/WorkInProgressPanel.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/worker/WorkInProgressPanel.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/worker/WorkInProgressPanel.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/worker/WorkInProgressPanel.java
index dbcf69c..c908aba 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/worker/WorkInProgressPanel.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/worker/WorkInProgressPanel.java
@@ -1,12 +1,12 @@
-package com.fathzer.soft.ajlib.swing.worker;
-
-import javax.swing.JPanel;
-
-/** A panel reporting the progress of a background task.
- * @see Worker
- */
-@SuppressWarnings("serial")
-public abstract class WorkInProgressPanel extends JPanel {
- public abstract Worker, ?> getWorker();
- public abstract void setSwingWorker(Worker, ?> worker);
+package com.fathzer.soft.ajlib.swing.worker;
+
+import javax.swing.JPanel;
+
+/** A panel reporting the progress of a background task.
+ * @see Worker
+ */
+@SuppressWarnings("serial")
+public abstract class WorkInProgressPanel extends JPanel {
+ public abstract Worker, ?> getWorker();
+ public abstract void setSwingWorker(Worker, ?> worker);
}
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/worker/Worker.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/worker/Worker.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/swing/worker/Worker.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/worker/Worker.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/worker/package-info.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/worker/package-info.java
similarity index 98%
rename from src/main/java/com/fathzer/soft/ajlib/swing/worker/package-info.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/swing/worker/package-info.java
index 0753b48..7b5d7a0 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/worker/package-info.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/swing/worker/package-info.java
@@ -1,2 +1,2 @@
-/** Utilities to implement background tasks*/
+/** Utilities to implement background tasks*/
package com.fathzer.soft.ajlib.swing.worker;
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/utilities/CSVWriter.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/CSVWriter.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/utilities/CSVWriter.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/CSVWriter.java
index 02d462e..eb98594 100644
--- a/src/main/java/com/fathzer/soft/ajlib/utilities/CSVWriter.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/CSVWriter.java
@@ -1,135 +1,135 @@
-package com.fathzer.soft.ajlib.utilities;
-
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.Writer;
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.util.Locale;
-
-/** CSV Writer.
- *
This class is able to write data in the CSV format.
- *
If you're looking for a CSV parser, I recommend using OpenCSV.
- */
-public class CSVWriter {
- private static final String BLANK = " ";
-
- private boolean lineIsEmpty;
- private BufferedWriter writer;
- private char separator;
- private char quote;
- private boolean alwaysQuoteCells;
-
- private String quoteSeq;
- private String doubleQuoteSeq;
-
- /** Constructor.
- *
Builds a new instance with the following default attributes:
- * - separator: ;
- * - quoting character: "
- * - alwaysQuote: false
- *
- * @param writer The writer where to write the data
- */
- public CSVWriter(Writer writer) {
- this.writer = writer instanceof BufferedWriter?(BufferedWriter)writer:new BufferedWriter(writer);
- this.lineIsEmpty = true;
- this.separator = ';';
- this.alwaysQuoteCells = false;
- this.setQuote('"');
- }
-
- public void writeCell(String cell) throws IOException {
- if (!lineIsEmpty) {
- writer.append(separator);
- }
- lineIsEmpty = false;
- if (cell==null) {
- cell = "";
- }
- boolean quoteCells = alwaysQuoteCells || (cell.indexOf(separator)>=0) || (cell.indexOf(quote)>=0) || cell.startsWith(BLANK) || cell.endsWith(BLANK);
- cell = cell.replace(quoteSeq, doubleQuoteSeq);
- if (quoteCells) {
- writer.append(quote);
- }
- writer.append(cell);
- if (quoteCells) {
- writer.append(quote);
- }
- }
-
- public void newLine() throws IOException {
- writer.newLine();
- lineIsEmpty = true;
- }
-
- /** Ensures all the data is written to the underlying writer.
- * @throws IOException If something goes wrong
- */
- public void flush() throws IOException {
- writer.flush();
- }
-
- /**
- * @return the separator
- */
- public char getSeparator() {
- return separator;
- }
-
- /**
- * @param separator the separator to set
- */
- public void setSeparator(char separator) {
- this.separator = separator;
- }
-
- /**
- * @return the quote
- */
- public char getQuote() {
- return quote;
- }
-
- /**
- * @param quote the quote to set
- */
- public void setQuote(char quote) {
- this.quote = quote;
- this.quoteSeq = new String(new char[]{quote});
- this.doubleQuoteSeq = this.quoteSeq + this.quoteSeq;
- }
-
- /**
- * @return the alwaysQuoteCells
- */
- public boolean isAlwaysQuoteCells() {
- return alwaysQuoteCells;
- }
-
- /**
- * @param alwaysQuoteCells the alwaysQuoteCells to set
- */
- public void setAlwaysQuoteCells(boolean alwaysQuoteCells) {
- this.alwaysQuoteCells = alwaysQuoteCells;
- }
-
- /** Returns a formatter to use to output decimal number.
- *
Excel is very demanding on the number formats. It doesn't tolerate currency suffix or prefix, nor grouping separators.
- *
This method returns a formatter that outputs strings that will be recognized as numbers by excel.
- * @param locale The locale.
- * @return a NumberFormat instance
- */
- public static NumberFormat getDecimalFormater(Locale locale) {
- NumberFormat result = NumberFormat.getInstance(locale);
- if (result instanceof DecimalFormat) {
- // We don't use the currency instance, because it would have output some currency prefix or suffix, not very easy
- // to manipulate with an excel like application
- NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(locale);
- result.setMinimumFractionDigits(currencyFormat.getMinimumFractionDigits());
- result.setMaximumFractionDigits(currencyFormat.getMaximumFractionDigits());
- }
- result.setGroupingUsed(false);
- return result;
- }
+package com.fathzer.soft.ajlib.utilities;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Locale;
+
+/** CSV Writer.
+ *
This class is able to write data in the CSV format.
+ *
If you're looking for a CSV parser, I recommend using OpenCSV.
+ */
+public class CSVWriter {
+ private static final String BLANK = " ";
+
+ private boolean lineIsEmpty;
+ private BufferedWriter writer;
+ private char separator;
+ private char quote;
+ private boolean alwaysQuoteCells;
+
+ private String quoteSeq;
+ private String doubleQuoteSeq;
+
+ /** Constructor.
+ *
Builds a new instance with the following default attributes:
+ * - separator: ;
+ * - quoting character: "
+ * - alwaysQuote: false
+ *
+ * @param writer The writer where to write the data
+ */
+ public CSVWriter(Writer writer) {
+ this.writer = writer instanceof BufferedWriter?(BufferedWriter)writer:new BufferedWriter(writer);
+ this.lineIsEmpty = true;
+ this.separator = ';';
+ this.alwaysQuoteCells = false;
+ this.setQuote('"');
+ }
+
+ public void writeCell(String cell) throws IOException {
+ if (!lineIsEmpty) {
+ writer.append(separator);
+ }
+ lineIsEmpty = false;
+ if (cell==null) {
+ cell = "";
+ }
+ boolean quoteCells = alwaysQuoteCells || (cell.indexOf(separator)>=0) || (cell.indexOf(quote)>=0) || cell.startsWith(BLANK) || cell.endsWith(BLANK);
+ cell = cell.replace(quoteSeq, doubleQuoteSeq);
+ if (quoteCells) {
+ writer.append(quote);
+ }
+ writer.append(cell);
+ if (quoteCells) {
+ writer.append(quote);
+ }
+ }
+
+ public void newLine() throws IOException {
+ writer.newLine();
+ lineIsEmpty = true;
+ }
+
+ /** Ensures all the data is written to the underlying writer.
+ * @throws IOException If something goes wrong
+ */
+ public void flush() throws IOException {
+ writer.flush();
+ }
+
+ /**
+ * @return the separator
+ */
+ public char getSeparator() {
+ return separator;
+ }
+
+ /**
+ * @param separator the separator to set
+ */
+ public void setSeparator(char separator) {
+ this.separator = separator;
+ }
+
+ /**
+ * @return the quote
+ */
+ public char getQuote() {
+ return quote;
+ }
+
+ /**
+ * @param quote the quote to set
+ */
+ public void setQuote(char quote) {
+ this.quote = quote;
+ this.quoteSeq = new String(new char[]{quote});
+ this.doubleQuoteSeq = this.quoteSeq + this.quoteSeq;
+ }
+
+ /**
+ * @return the alwaysQuoteCells
+ */
+ public boolean isAlwaysQuoteCells() {
+ return alwaysQuoteCells;
+ }
+
+ /**
+ * @param alwaysQuoteCells the alwaysQuoteCells to set
+ */
+ public void setAlwaysQuoteCells(boolean alwaysQuoteCells) {
+ this.alwaysQuoteCells = alwaysQuoteCells;
+ }
+
+ /** Returns a formatter to use to output decimal number.
+ *
Excel is very demanding on the number formats. It doesn't tolerate currency suffix or prefix, nor grouping separators.
+ *
This method returns a formatter that outputs strings that will be recognized as numbers by excel.
+ * @param locale The locale.
+ * @return a NumberFormat instance
+ */
+ public static NumberFormat getDecimalFormater(Locale locale) {
+ NumberFormat result = NumberFormat.getInstance(locale);
+ if (result instanceof DecimalFormat) {
+ // We don't use the currency instance, because it would have output some currency prefix or suffix, not very easy
+ // to manipulate with an excel like application
+ NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(locale);
+ result.setMinimumFractionDigits(currencyFormat.getMinimumFractionDigits());
+ result.setMaximumFractionDigits(currencyFormat.getMaximumFractionDigits());
+ }
+ result.setGroupingUsed(false);
+ return result;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/utilities/CoolDateFormatter.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/CoolDateFormatter.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/utilities/CoolDateFormatter.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/CoolDateFormatter.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/utilities/FileUtils.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/FileUtils.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/utilities/FileUtils.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/FileUtils.java
index 495bde4..cdd8833 100644
--- a/src/main/java/com/fathzer/soft/ajlib/utilities/FileUtils.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/FileUtils.java
@@ -1,288 +1,288 @@
-package com.fathzer.soft.ajlib.utilities;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.channels.FileLock;
-import java.text.MessageFormat;
-import java.text.ParseException;
-
-/** Utility to perform some operations on files.
- */
-public class FileUtils {
- private static final String ACCESS_DENIED_MESSAGE = "Write access to file refused";
-
- private FileUtils() {
- }
-
- /** Gets the canonical file of a file even on windows where links are ignored by File.getCanonicalPath().
- *
Even if the link is broken, the method returns the linked file. You should use File.exists() to test if the returned file is available.
- *
If the link is a link to a link to a file, this method returns the final file.
- * @param file the file to test
- * @return a File
- * @throws IOException If something goes wrong
- */
- public static File getCanonical(File file) throws IOException {
- if (!file.exists()) {
- return file;
- }
- try {
- // Java has nothing to decode shortcut (what a pity!).
- // we will try to decode ourselves
- if (WindowsShortcut.isPotentialValidLink(file)) {
- return new File(new WindowsShortcut(file).getRealFilename());
- }
- } catch (ParseException e) {
- // Something went wrong
- // In such a case, let file.CanonicalFile a chance to do better.
- }
- return file.getCanonicalFile();
- }
-
- /** Move a file from one path to another.
- *
Unlike java.io.File.renameTo, this method always moves the file (if it doesn't fail).
- * If the source and the destination paths are not on the same file system, the file is copied to the new file system
- * and then erased from the old one.
- * @param src The src path
- * @param dest The dest path
- * @throws IOException If the move fails
- */
- public static void move(File src, File dest) throws IOException {
- // Check whether the destination directory exists or not.
- // If not, create it.
- File parent = dest.getAbsoluteFile().getParentFile();
- if (!parent.exists()) {
- parent.mkdirs();
- }
- // Try to simply rename the file
- if (!src.renameTo(dest)) {
- // renameTo may fail if src and dest files are not on the same file system.
- // Then we have to copy the src file.
- // Before, we will ensure we will be able to erase the src file after the copy
- if (src.canWrite()) {
- copy(src, dest, true);
- // Now, deletes the src file
- if (!src.delete()) {
- // Oh ... we were thinking we had the right to delete the file ... but we can't:
- // Delete the dest file
- dest.delete();
- throw new SecurityException(ACCESS_DENIED_MESSAGE);
- }
- } else {
- throw new SecurityException(ACCESS_DENIED_MESSAGE);
- }
- }
- }
-
- /** Copy a file to another.
- * @param src The src path
- * @param dest The dest path
- * @param overrideExisting true if copying to an existing file is ok.
- * @throws IOException If the copy fails
- */
- public static void copy(File src, File dest, boolean overrideExisting) throws IOException {
- if (dest.exists() && !overrideExisting) {
- throw new IOException(MessageFormat.format("File {0} already exists", dest));
- }
- try (InputStream in = new BufferedInputStream(new FileInputStream(src))) {
- try (OutputStream out = new BufferedOutputStream(new FileOutputStream(dest))) {
- int c;
- while ((c = in.read()) != -1) {
- out.write(c);
- }
- }
- }
- dest.setLastModified(src.lastModified());
- }
-
- /** Deletes recursively a directory.
- *
This means that the directory and all of its files or subfolders are deleted.
- * @param file the directory to be deleted (if is is a file, the file will be deleted).
- * @return true if the directory has been successfully deleted.
- */
- public static boolean deleteDirectory(File file) {
- if (file.isDirectory()) {
- File[] files = file.listFiles();
- for (int i = 0; i < files.length; i++) {
- deleteDirectory(files[i]);
- }
- }
- return file.delete();
- }
-
- /** Tests whether a file is contained in a directory.
- *
The directory and the file may not exists, the search is done on the absolute paths.
- * @param file The file to be tested
- * @param directory The tested directory
- * @return true if the file is contained in the directory.
- */
- public static boolean isIncluded(File file, File directory) {
- for (File parent = file.getParentFile(); parent!=null; parent = parent.getParentFile()) {
- if (parent.equals(directory)) {
- return true;
- }
- }
- return false;
- }
-
- /** Gets a FileOutputStream even on a windows hidden file.
- *
Under windows, it is impossible to write directly in a hidden file with Java.
- * You have to make the file visible first. That's what this method try to do.
- *
When the file was initially hidden, the close method of the returned stream hide it again.
- * @param file The file to be opened for writing
- * @return a new stream
- * @throws IOException If something goes wrong
- */
- public static FileOutputStream getHiddenCompliantStream(File file) throws IOException {
- if (file.isHidden() && System.getProperty("os.name", "?").startsWith("Windows")) {
- try {
- Process process = Runtime.getRuntime().exec("attrib -H \""+file.getAbsolutePath()+"\"");
- try {
- int result = process.waitFor();
- if (result==0) {
- return new HiddenFileOutputStream(file);
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- } catch (IOException e) {
- // This try catch block is empty because this exception, in this context, means that the attrib command is not available.
- // In such a case, we just have to do ... nothing: If the OutputStream creation fails, an IOException will be thrown
- }
- }
- // If the file was not hidden, or if making the file visible failed, try to open a classic stream.
- return new FileOutputStream(file);
- }
-
- /** The FileOutputStream returned by getHiddenCompliantStream method when it is called on a Windows hidden file.
- * @see FileUtils#getHiddenCompliantStream(File)
- */
- private static class HiddenFileOutputStream extends FileOutputStream {
- private File file;
-
- HiddenFileOutputStream(File file) throws FileNotFoundException {
- super(file);
- this.file = file;
- }
-
- @Override
- public void close() throws IOException {
- super.close();
- Process process = Runtime.getRuntime().exec("attrib +H \""+file.getAbsolutePath()+"\"");
- try {
- process.waitFor();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- }
-
- /** Tests whether the application can write to a file (or a folder).
- *
It differs from File.canWrite because File.canWrite ignore the security policies of the platform.
- * This method returns true only if the calling thread have all the rights necessary to write to the file, and the file
- * is not already locked.
- * @param file The file or folder to test
- * @return true if the file or folder exists and the calling thread can write into it.
- *
If the file doesn't exist, it returns true if the parent folder is writable.
- */
- public static boolean isWritable(File file) {
- if (!file.exists()) {
- File parentFile = file.getAbsoluteFile().getParentFile();
- return parentFile==null?false:isWritable(parentFile);
- }
- if (!file.canWrite()) {
- return false;
- }
- if (file.isDirectory()) {
- // If the file is a folder, the easiest way is to create a temporary file.
- try {
- File f = File.createTempFile("ajlib", null, file);
- f.delete();
- return true;
- } catch (IOException e) {
- return false;
- } catch (SecurityException e) {
- return false;
- }
- } else {
- // If the argument is a file, we will simply open it for writing
- try (FileOutputStream x = new FileOutputStream(file,true)) {
- FileLock lock = null;
- lock = x.getChannel().tryLock();
- if (lock==null) {
- return false;
- } else {
- lock.release();
- return true;
- }
- } catch (FileNotFoundException e) {
- // File is locked by another application
- return false;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
-
- /** Tests whether the application can read from a file (or a folder).
- *
It differs from File.canRead because File.canRead ignore the security policies of the platform.
- * This method returns true only if the calling thread have all the rights necessary to read from the file.
- * @param file The file or folder to test
- * @return true if the file or folder exists and the calling thread can write into it
- */
- public static boolean isReadable(File file) {
- if (!file.canRead()) {
- return false;
- }
- if (file.isDirectory()) {
- return true;
- }
- // If the argument is a file, we will simply to open it for reading
- try {
- FileInputStream x = new FileInputStream(file);
- x.close();
- return true;
- } catch (FileNotFoundException e) {
- // The application have the right to read the file
- return false;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- /** Gets the extension of a file.
- *
For example, the extension of file "file.xml" is ".xml".
- * @param file The file.
- * @return The extension including the point, or null if fileName does not have an extension.
- */
- public static String getExtension(File file) {
- String name = file.getName();
- int index = name.lastIndexOf('.');
- if (index<0) {
- return null;
- } else {
- return name.substring(index);
- }
- }
-
- /** Gets the root name of a file.
- *
For example, the root name of file "file.xml" is "file".
- * @param file The file.
- * @return The extension including the point, or null if fileName does not have an extension.
- */
- public static String getRootName(File file) {
- String name = file.getName();
- int index = name.lastIndexOf('.');
- if (index<0) {
- return name;
- } else {
- return name.substring(0,index);
- }
- }
-}
+package com.fathzer.soft.ajlib.utilities;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.channels.FileLock;
+import java.text.MessageFormat;
+import java.text.ParseException;
+
+/** Utility to perform some operations on files.
+ */
+public class FileUtils {
+ private static final String ACCESS_DENIED_MESSAGE = "Write access to file refused";
+
+ private FileUtils() {
+ }
+
+ /** Gets the canonical file of a file even on windows where links are ignored by File.getCanonicalPath().
+ *
Even if the link is broken, the method returns the linked file. You should use File.exists() to test if the returned file is available.
+ *
If the link is a link to a link to a file, this method returns the final file.
+ * @param file the file to test
+ * @return a File
+ * @throws IOException If something goes wrong
+ */
+ public static File getCanonical(File file) throws IOException {
+ if (!file.exists()) {
+ return file;
+ }
+ try {
+ // Java has nothing to decode shortcut (what a pity!).
+ // we will try to decode ourselves
+ if (WindowsShortcut.isPotentialValidLink(file)) {
+ return new File(new WindowsShortcut(file).getRealFilename());
+ }
+ } catch (ParseException e) {
+ // Something went wrong
+ // In such a case, let file.CanonicalFile a chance to do better.
+ }
+ return file.getCanonicalFile();
+ }
+
+ /** Move a file from one path to another.
+ *
Unlike java.io.File.renameTo, this method always moves the file (if it doesn't fail).
+ * If the source and the destination paths are not on the same file system, the file is copied to the new file system
+ * and then erased from the old one.
+ * @param src The src path
+ * @param dest The dest path
+ * @throws IOException If the move fails
+ */
+ public static void move(File src, File dest) throws IOException {
+ // Check whether the destination directory exists or not.
+ // If not, create it.
+ File parent = dest.getAbsoluteFile().getParentFile();
+ if (!parent.exists()) {
+ parent.mkdirs();
+ }
+ // Try to simply rename the file
+ if (!src.renameTo(dest)) {
+ // renameTo may fail if src and dest files are not on the same file system.
+ // Then we have to copy the src file.
+ // Before, we will ensure we will be able to erase the src file after the copy
+ if (src.canWrite()) {
+ copy(src, dest, true);
+ // Now, deletes the src file
+ if (!src.delete()) {
+ // Oh ... we were thinking we had the right to delete the file ... but we can't:
+ // Delete the dest file
+ dest.delete();
+ throw new SecurityException(ACCESS_DENIED_MESSAGE);
+ }
+ } else {
+ throw new SecurityException(ACCESS_DENIED_MESSAGE);
+ }
+ }
+ }
+
+ /** Copy a file to another.
+ * @param src The src path
+ * @param dest The dest path
+ * @param overrideExisting true if copying to an existing file is ok.
+ * @throws IOException If the copy fails
+ */
+ public static void copy(File src, File dest, boolean overrideExisting) throws IOException {
+ if (dest.exists() && !overrideExisting) {
+ throw new IOException(MessageFormat.format("File {0} already exists", dest));
+ }
+ try (InputStream in = new BufferedInputStream(new FileInputStream(src))) {
+ try (OutputStream out = new BufferedOutputStream(new FileOutputStream(dest))) {
+ int c;
+ while ((c = in.read()) != -1) {
+ out.write(c);
+ }
+ }
+ }
+ dest.setLastModified(src.lastModified());
+ }
+
+ /** Deletes recursively a directory.
+ *
This means that the directory and all of its files or subfolders are deleted.
+ * @param file the directory to be deleted (if is is a file, the file will be deleted).
+ * @return true if the directory has been successfully deleted.
+ */
+ public static boolean deleteDirectory(File file) {
+ if (file.isDirectory()) {
+ File[] files = file.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ deleteDirectory(files[i]);
+ }
+ }
+ return file.delete();
+ }
+
+ /** Tests whether a file is contained in a directory.
+ *
The directory and the file may not exists, the search is done on the absolute paths.
+ * @param file The file to be tested
+ * @param directory The tested directory
+ * @return true if the file is contained in the directory.
+ */
+ public static boolean isIncluded(File file, File directory) {
+ for (File parent = file.getParentFile(); parent!=null; parent = parent.getParentFile()) {
+ if (parent.equals(directory)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Gets a FileOutputStream even on a windows hidden file.
+ *
Under windows, it is impossible to write directly in a hidden file with Java.
+ * You have to make the file visible first. That's what this method try to do.
+ *
When the file was initially hidden, the close method of the returned stream hide it again.
+ * @param file The file to be opened for writing
+ * @return a new stream
+ * @throws IOException If something goes wrong
+ */
+ public static FileOutputStream getHiddenCompliantStream(File file) throws IOException {
+ if (file.isHidden() && System.getProperty("os.name", "?").startsWith("Windows")) {
+ try {
+ Process process = Runtime.getRuntime().exec("attrib -H \""+file.getAbsolutePath()+"\"");
+ try {
+ int result = process.waitFor();
+ if (result==0) {
+ return new HiddenFileOutputStream(file);
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ } catch (IOException e) {
+ // This try catch block is empty because this exception, in this context, means that the attrib command is not available.
+ // In such a case, we just have to do ... nothing: If the OutputStream creation fails, an IOException will be thrown
+ }
+ }
+ // If the file was not hidden, or if making the file visible failed, try to open a classic stream.
+ return new FileOutputStream(file);
+ }
+
+ /** The FileOutputStream returned by getHiddenCompliantStream method when it is called on a Windows hidden file.
+ * @see FileUtils#getHiddenCompliantStream(File)
+ */
+ private static class HiddenFileOutputStream extends FileOutputStream {
+ private File file;
+
+ HiddenFileOutputStream(File file) throws FileNotFoundException {
+ super(file);
+ this.file = file;
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ Process process = Runtime.getRuntime().exec("attrib +H \""+file.getAbsolutePath()+"\"");
+ try {
+ process.waitFor();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /** Tests whether the application can write to a file (or a folder).
+ *
It differs from File.canWrite because File.canWrite ignore the security policies of the platform.
+ * This method returns true only if the calling thread have all the rights necessary to write to the file, and the file
+ * is not already locked.
+ * @param file The file or folder to test
+ * @return true if the file or folder exists and the calling thread can write into it.
+ *
If the file doesn't exist, it returns true if the parent folder is writable.
+ */
+ public static boolean isWritable(File file) {
+ if (!file.exists()) {
+ File parentFile = file.getAbsoluteFile().getParentFile();
+ return parentFile==null?false:isWritable(parentFile);
+ }
+ if (!file.canWrite()) {
+ return false;
+ }
+ if (file.isDirectory()) {
+ // If the file is a folder, the easiest way is to create a temporary file.
+ try {
+ File f = File.createTempFile("ajlib", null, file);
+ f.delete();
+ return true;
+ } catch (IOException e) {
+ return false;
+ } catch (SecurityException e) {
+ return false;
+ }
+ } else {
+ // If the argument is a file, we will simply open it for writing
+ try (FileOutputStream x = new FileOutputStream(file,true)) {
+ FileLock lock = null;
+ lock = x.getChannel().tryLock();
+ if (lock==null) {
+ return false;
+ } else {
+ lock.release();
+ return true;
+ }
+ } catch (FileNotFoundException e) {
+ // File is locked by another application
+ return false;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /** Tests whether the application can read from a file (or a folder).
+ *
It differs from File.canRead because File.canRead ignore the security policies of the platform.
+ * This method returns true only if the calling thread have all the rights necessary to read from the file.
+ * @param file The file or folder to test
+ * @return true if the file or folder exists and the calling thread can write into it
+ */
+ public static boolean isReadable(File file) {
+ if (!file.canRead()) {
+ return false;
+ }
+ if (file.isDirectory()) {
+ return true;
+ }
+ // If the argument is a file, we will simply to open it for reading
+ try {
+ FileInputStream x = new FileInputStream(file);
+ x.close();
+ return true;
+ } catch (FileNotFoundException e) {
+ // The application have the right to read the file
+ return false;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Gets the extension of a file.
+ *
For example, the extension of file "file.xml" is ".xml".
+ * @param file The file.
+ * @return The extension including the point, or null if fileName does not have an extension.
+ */
+ public static String getExtension(File file) {
+ String name = file.getName();
+ int index = name.lastIndexOf('.');
+ if (index<0) {
+ return null;
+ } else {
+ return name.substring(index);
+ }
+ }
+
+ /** Gets the root name of a file.
+ *
For example, the root name of file "file.xml" is "file".
+ * @param file The file.
+ * @return The extension including the point, or null if fileName does not have an extension.
+ */
+ public static String getRootName(File file) {
+ String name = file.getName();
+ int index = name.lastIndexOf('.');
+ if (index<0) {
+ return name;
+ } else {
+ return name.substring(0,index);
+ }
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/utilities/ListUtils.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/ListUtils.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/utilities/ListUtils.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/ListUtils.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/utilities/LocalizationData.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/LocalizationData.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/utilities/LocalizationData.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/LocalizationData.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/utilities/NullUtils.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/NullUtils.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/utilities/NullUtils.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/NullUtils.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/utilities/RuntimeUtils.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/RuntimeUtils.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/utilities/RuntimeUtils.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/RuntimeUtils.java
index 0595d6e..0136c12 100644
--- a/src/main/java/com/fathzer/soft/ajlib/utilities/RuntimeUtils.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/RuntimeUtils.java
@@ -1,45 +1,45 @@
-package com.fathzer.soft.ajlib.utilities;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.List;
-
-public abstract class RuntimeUtils {
- private RuntimeUtils() {
- // To prevent class being instantiated
- }
-
- private static class UnexpectedException extends RuntimeException {
- private static final long serialVersionUID = 1L;
-
- public UnexpectedException(Throwable cause) {
- super("Unexpected exception", cause);
- }
-
- }
-
- public static int getJavaMajorVersion() {
- try {
- // Try with java 9 API
- final Method m = Runtime.class.getMethod("version");
- final Object version = m.invoke(null);
- return ((List) version.getClass().getMethod("version").invoke(version)).get(0);
- } catch (NoSuchMethodException e) {
- // Try parsing System.getProperty
- String version = System.getProperty("java.version");
- if (version.startsWith("1.")) {
- version = version.substring(2, 3);
- } else {
- final int dot = version.indexOf(".");
- if (dot != -1) {
- version = version.substring(0, dot);
- }
- }
- return Integer.parseInt(version);
- } catch (IllegalAccessException e) {
- throw new UnexpectedException(e);
- } catch (InvocationTargetException e) {
- throw new UnexpectedException(e);
- }
- }
-}
+package com.fathzer.soft.ajlib.utilities;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+
+public abstract class RuntimeUtils {
+ private RuntimeUtils() {
+ // To prevent class being instantiated
+ }
+
+ private static class UnexpectedException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public UnexpectedException(Throwable cause) {
+ super("Unexpected exception", cause);
+ }
+
+ }
+
+ public static int getJavaMajorVersion() {
+ try {
+ // Try with java 9 API
+ final Method m = Runtime.class.getMethod("version");
+ final Object version = m.invoke(null);
+ return ((List) version.getClass().getMethod("version").invoke(version)).get(0);
+ } catch (NoSuchMethodException e) {
+ // Try parsing System.getProperty
+ String version = System.getProperty("java.version");
+ if (version.startsWith("1.")) {
+ version = version.substring(2, 3);
+ } else {
+ final int dot = version.indexOf(".");
+ if (dot != -1) {
+ version = version.substring(0, dot);
+ }
+ }
+ return Integer.parseInt(version);
+ } catch (IllegalAccessException e) {
+ throw new UnexpectedException(e);
+ } catch (InvocationTargetException e) {
+ throw new UnexpectedException(e);
+ }
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/utilities/StringUtils.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/StringUtils.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/utilities/StringUtils.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/StringUtils.java
index e7604ca..1074e7f 100644
--- a/src/main/java/com/fathzer/soft/ajlib/utilities/StringUtils.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/StringUtils.java
@@ -1,42 +1,42 @@
-package com.fathzer.soft.ajlib.utilities;
-
-import java.util.LinkedList;
-import java.util.List;
-
-/** Utility to parse the fields separated by a char in a string.
- */
-public abstract class StringUtils {
- public static final String EMPTY = ""; //$NON-NLS-1$
-
- private StringUtils() {
- super();
- }
-
- /** Splits a string into fields.
- *
The main advantage vs String#split is that the developer has not to deal with separators that
- * are reserved characters of the regular expressions syntax
- *
Some examples:
- * - split("",',') -> {""}
- * - split(",a,",',') -> {"","a",""}
- *
- * @param string The String to split
- * @param separator The field separator
- * @return an array of Strings.
- */
- public static String[] split(String string, char separator) {
- List result = new LinkedList<>();
- StringBuilder buffer = new StringBuilder();
- for (int i = 0; i < string.length(); i++) {
- if (string.charAt(i)==separator) {
- result.add(buffer.toString());
- if (buffer.length()>0) {
- buffer.delete(0, buffer.length());
- }
- } else {
- buffer.append(string.charAt(i));
- }
- }
- result.add(buffer.toString());
- return result.toArray(new String[result.size()]);
- }
-}
+package com.fathzer.soft.ajlib.utilities;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/** Utility to parse the fields separated by a char in a string.
+ */
+public abstract class StringUtils {
+ public static final String EMPTY = ""; //$NON-NLS-1$
+
+ private StringUtils() {
+ super();
+ }
+
+ /** Splits a string into fields.
+ *
The main advantage vs String#split is that the developer has not to deal with separators that
+ * are reserved characters of the regular expressions syntax
+ *
Some examples:
+ * - split("",',') -> {""}
+ * - split(",a,",',') -> {"","a",""}
+ *
+ * @param string The String to split
+ * @param separator The field separator
+ * @return an array of Strings.
+ */
+ public static String[] split(String string, char separator) {
+ List result = new LinkedList<>();
+ StringBuilder buffer = new StringBuilder();
+ for (int i = 0; i < string.length(); i++) {
+ if (string.charAt(i)==separator) {
+ result.add(buffer.toString());
+ if (buffer.length()>0) {
+ buffer.delete(0, buffer.length());
+ }
+ } else {
+ buffer.append(string.charAt(i));
+ }
+ }
+ result.add(buffer.toString());
+ return result.toArray(new String[result.size()]);
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/utilities/TextMatcher.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/TextMatcher.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/utilities/TextMatcher.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/TextMatcher.java
index 04a4b91..8a3b034 100644
--- a/src/main/java/com/fathzer/soft/ajlib/utilities/TextMatcher.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/TextMatcher.java
@@ -1,159 +1,159 @@
-package com.fathzer.soft.ajlib.utilities;
-
-import java.text.Normalizer;
-import java.util.regex.Pattern;
-
-/** A text matcher.
- *
A text matcher allows you to test whether a string matches a filter accordingly to some options as:
- * - What condition means "matches":
- * - String matches is equals to the filter.
- * - String contains the filter.
- * - String matches the filter (interpreted as a regular expression).
- *
- * - Case could be ignored ... or not.
- * - Diacritical marks could be ignored ... or not.
- *
- * @see Kind#REGULAR
- * @see Kind#EQUALS
- * @see Kind#CONTAINS
- */
-public class TextMatcher {
- /** A kind of comparison a TextMatcher can perform. */
- public enum Kind {
- /** Kind of comparison: Does a string matches the filter (filter is interpreted as a regular expression) ? */
- REGULAR,
- /** Kind of comparison: Does a string is equal to the filter ? */
- EQUALS,
- /** Kind of comparison: Does a string contains the filter ? */
- CONTAINS
- }
-
- private Kind kind;
- private String filter;
- private boolean caseSensitive;
- private boolean diacriticalSensitive;
- private Object internalFilter;
-
- /** Constructor.
- * @param kind The kind of matcher.
- * @param filter The filter string
- * @param caseSensitive sets the case sensitivity of the comparison (true if the comparison is case sensitive)
- * @param diacriticalSensitive sets the diacritical sensitivity of the comparison (false to ignore diacritical marks).
- * @see Kind#REGULAR
- * @see Kind#EQUALS
- * @see Kind#CONTAINS
- */
- public TextMatcher(Kind kind, String filter, boolean caseSensitive, boolean diacriticalSensitive) {
- super();
- if (kind==null) {
- throw new IllegalArgumentException();
- }
- this.kind = kind;
- this.filter = filter;
- this.caseSensitive = caseSensitive;
- this.diacriticalSensitive = diacriticalSensitive;
- // If diacriticals have to be ignored, we need to remove the diacritical marks from the filter string
- if (!diacriticalSensitive) {
- filter = removeDiacriticals(filter);
- }
- if (kind==Kind.REGULAR) {
- if (caseSensitive) {
- internalFilter = Pattern.compile(filter);
- } else {
- internalFilter = Pattern.compile(filter, Pattern.UNICODE_CASE+Pattern.CASE_INSENSITIVE);
- }
- } else if ((kind==Kind.EQUALS) || ((kind==Kind.CONTAINS) && caseSensitive)) {
- internalFilter = filter;
- } else {
- internalFilter = filter.toUpperCase();
- }
- }
-
- /** Removes the diacritical marks from a string.
- * @param string The string to process
- * @return a new String with no diacritical marks
- */
- public static String removeDiacriticals(String string) {
- return Normalizer.normalize(string, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
- }
-
- /** Gets the kind of comparison.
- * @return a Kind of comparison.
- * @see Kind#REGULAR
- * @see Kind#EQUALS
- * @see Kind#CONTAINS
- */
- public Kind getKind() {
- return kind;
- }
-
- /** Gets the filter string.
- * @return a String
- */
- public String getFilter() {
- return filter;
- }
-
- /** Tests whether this matcher is case sensitive.
- * @return true if the matcher is case sensitive.
- */
- public boolean isCaseSensitive() {
- return caseSensitive;
- }
-
- /** Tests whether this matcher is diacritical sensitive.
- * @return true if the matcher is diacritical sensitive.
- */
- public boolean isDiacriticalSensitive() {
- return diacriticalSensitive;
- }
-
- /** Tests whether a string matches this matcher.
- * @param text the string to test
- * @return true if the string matches. If the string is null, this method always returns false
- */
- public boolean matches(String text) {
- if (text==null) {
- return false;
- }
- if (!diacriticalSensitive) {
- text = removeDiacriticals(text);
- }
- if (kind==Kind.REGULAR) {
- return ((Pattern)internalFilter).matcher(text).matches();
- } else if (kind==Kind.EQUALS) {
- return caseSensitive?text.equals(internalFilter):text.equalsIgnoreCase((String) internalFilter);
- } else if (kind==Kind.CONTAINS) {
- if (caseSensitive) {
- return text.contains((CharSequence) internalFilter);
- } else {
- return text.toUpperCase().contains((CharSequence) internalFilter);
- }
- } else {
- throw new UnsupportedOperationException();
- }
- }
-
- @Override
- public int hashCode() {
- return filter.hashCode();
- }
-
- /**
- * Tests whether the argument object is equals to this.
- *
Two TextMatcher are equals if their kind, filter, caseSensitive and diacriticalSensitive attributes are equals.
- *
Note that two equivalent TextMatchers can not be equals; For instance one with "FILTER" as filter, the other with "filter"
- * and the caseSensitive attribute set to false.
- * @param obj a textMatcher to test.
- * @see #TextMatcher(Kind, String, boolean, boolean)
- */
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof TextMatcher) {
- TextMatcher other = (TextMatcher) obj;
- return this.kind.equals(other.kind) && this.filter.equals(other.filter)
- && (this.caseSensitive==other.caseSensitive) && (this.diacriticalSensitive==other.diacriticalSensitive);
- }
- return false;
- }
-}
+package com.fathzer.soft.ajlib.utilities;
+
+import java.text.Normalizer;
+import java.util.regex.Pattern;
+
+/** A text matcher.
+ *
A text matcher allows you to test whether a string matches a filter accordingly to some options as:
+ * - What condition means "matches":
+ * - String matches is equals to the filter.
+ * - String contains the filter.
+ * - String matches the filter (interpreted as a regular expression).
+ *
+ * - Case could be ignored ... or not.
+ * - Diacritical marks could be ignored ... or not.
+ *
+ * @see Kind#REGULAR
+ * @see Kind#EQUALS
+ * @see Kind#CONTAINS
+ */
+public class TextMatcher {
+ /** A kind of comparison a TextMatcher can perform. */
+ public enum Kind {
+ /** Kind of comparison: Does a string matches the filter (filter is interpreted as a regular expression) ? */
+ REGULAR,
+ /** Kind of comparison: Does a string is equal to the filter ? */
+ EQUALS,
+ /** Kind of comparison: Does a string contains the filter ? */
+ CONTAINS
+ }
+
+ private Kind kind;
+ private String filter;
+ private boolean caseSensitive;
+ private boolean diacriticalSensitive;
+ private Object internalFilter;
+
+ /** Constructor.
+ * @param kind The kind of matcher.
+ * @param filter The filter string
+ * @param caseSensitive sets the case sensitivity of the comparison (true if the comparison is case sensitive)
+ * @param diacriticalSensitive sets the diacritical sensitivity of the comparison (false to ignore diacritical marks).
+ * @see Kind#REGULAR
+ * @see Kind#EQUALS
+ * @see Kind#CONTAINS
+ */
+ public TextMatcher(Kind kind, String filter, boolean caseSensitive, boolean diacriticalSensitive) {
+ super();
+ if (kind==null) {
+ throw new IllegalArgumentException();
+ }
+ this.kind = kind;
+ this.filter = filter;
+ this.caseSensitive = caseSensitive;
+ this.diacriticalSensitive = diacriticalSensitive;
+ // If diacriticals have to be ignored, we need to remove the diacritical marks from the filter string
+ if (!diacriticalSensitive) {
+ filter = removeDiacriticals(filter);
+ }
+ if (kind==Kind.REGULAR) {
+ if (caseSensitive) {
+ internalFilter = Pattern.compile(filter);
+ } else {
+ internalFilter = Pattern.compile(filter, Pattern.UNICODE_CASE+Pattern.CASE_INSENSITIVE);
+ }
+ } else if ((kind==Kind.EQUALS) || ((kind==Kind.CONTAINS) && caseSensitive)) {
+ internalFilter = filter;
+ } else {
+ internalFilter = filter.toUpperCase();
+ }
+ }
+
+ /** Removes the diacritical marks from a string.
+ * @param string The string to process
+ * @return a new String with no diacritical marks
+ */
+ public static String removeDiacriticals(String string) {
+ return Normalizer.normalize(string, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
+ }
+
+ /** Gets the kind of comparison.
+ * @return a Kind of comparison.
+ * @see Kind#REGULAR
+ * @see Kind#EQUALS
+ * @see Kind#CONTAINS
+ */
+ public Kind getKind() {
+ return kind;
+ }
+
+ /** Gets the filter string.
+ * @return a String
+ */
+ public String getFilter() {
+ return filter;
+ }
+
+ /** Tests whether this matcher is case sensitive.
+ * @return true if the matcher is case sensitive.
+ */
+ public boolean isCaseSensitive() {
+ return caseSensitive;
+ }
+
+ /** Tests whether this matcher is diacritical sensitive.
+ * @return true if the matcher is diacritical sensitive.
+ */
+ public boolean isDiacriticalSensitive() {
+ return diacriticalSensitive;
+ }
+
+ /** Tests whether a string matches this matcher.
+ * @param text the string to test
+ * @return true if the string matches. If the string is null, this method always returns false
+ */
+ public boolean matches(String text) {
+ if (text==null) {
+ return false;
+ }
+ if (!diacriticalSensitive) {
+ text = removeDiacriticals(text);
+ }
+ if (kind==Kind.REGULAR) {
+ return ((Pattern)internalFilter).matcher(text).matches();
+ } else if (kind==Kind.EQUALS) {
+ return caseSensitive?text.equals(internalFilter):text.equalsIgnoreCase((String) internalFilter);
+ } else if (kind==Kind.CONTAINS) {
+ if (caseSensitive) {
+ return text.contains((CharSequence) internalFilter);
+ } else {
+ return text.toUpperCase().contains((CharSequence) internalFilter);
+ }
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return filter.hashCode();
+ }
+
+ /**
+ * Tests whether the argument object is equals to this.
+ *
Two TextMatcher are equals if their kind, filter, caseSensitive and diacriticalSensitive attributes are equals.
+ *
Note that two equivalent TextMatchers can not be equals; For instance one with "FILTER" as filter, the other with "filter"
+ * and the caseSensitive attribute set to false.
+ * @param obj a textMatcher to test.
+ * @see #TextMatcher(Kind, String, boolean, boolean)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof TextMatcher) {
+ TextMatcher other = (TextMatcher) obj;
+ return this.kind.equals(other.kind) && this.filter.equals(other.filter)
+ && (this.caseSensitive==other.caseSensitive) && (this.diacriticalSensitive==other.diacriticalSensitive);
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/utilities/WindowsShortcut.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/WindowsShortcut.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/utilities/WindowsShortcut.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/WindowsShortcut.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/utilities/package-info.java b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/package-info.java
similarity index 98%
rename from src/main/java/com/fathzer/soft/ajlib/utilities/package-info.java
rename to ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/package-info.java
index a5bd892..9dbcb08 100644
--- a/src/main/java/com/fathzer/soft/ajlib/utilities/package-info.java
+++ b/ajlib/src/main/java/com/fathzer/soft/ajlib/utilities/package-info.java
@@ -1,2 +1,2 @@
-/** General purpose utilities*/
+/** General purpose utilities*/
package com.fathzer.soft.ajlib.utilities;
\ No newline at end of file
diff --git a/src/main/resources/com/fathzer/soft/ajlib/Resources.properties b/ajlib/src/main/resources/com/fathzer/soft/ajlib/Resources.properties
similarity index 97%
rename from src/main/resources/com/fathzer/soft/ajlib/Resources.properties
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/Resources.properties
index ef8dfdf..7c5b46a 100644
--- a/src/main/resources/com/fathzer/soft/ajlib/Resources.properties
+++ b/ajlib/src/main/resources/com/fathzer/soft/ajlib/Resources.properties
@@ -1,65 +1,65 @@
-#Translation tips:
-#Some strings contain patterns like {0}. These patterns has to remain unchanged when you translate these string.
-#For those who are familiar with MessageFormat, be aware that AJLib uses another library that do not use
-#single quote as an escape char. So, you have not to double every single quote.
-
-#Menu localization
-MainMenu.file=File
-MainMenu.file.mnemonic=F
-MainMenu.quit=Quit
-MainMenu.quit.shortcut=Q
-MainMenu.quit.mnemonic=Q
-MainMenu.quit.tooltip=Quits the application
-
-#Generic wordings
-GenericButton.ignore=Ignore
-GenericButton.cancel=Cancel
-GenericButton.cancel.toolTip=Cancels the current input
-GenericButton.ok=Validate
-GenericButton.ok.toolTip=Validates the current input
-Generic.warning=Warning
-Generic.error=Error
-
-Browser.unsupported.message=Unable to open a web browser.
The URL ({0}) has been copied to the clipboard.
You can now paste it to your web browser.
-
-# This dialog is opened when the file to save the data is already existing
-# Dialog title
-saveDialog.FileExist.title=Warning
-# Dialog message
-saveDialog.FileExist.message=File already exists. Would you like to overwrite it?
-openDialog.fileDoesntExist=The selected file does not exist
-openDialog.targetDoesntExist=The target of the selected shortcut does not exist.
-
-# ExcelPane
-ExcelPane.error.message=Error while saving the file ({0})
-ExcelPane.save=Save
-ExcelPane.csv.wording=CSV Files
-
-#File selection panels
-FileSelectionPanel.file=File:
-FileSelectionPanel.change=Change
-URIChooserDialog.noFileSelected=This button is disabled because no file is selected
-URIChooserDialog.openButton.title=Open
-URIChooserDialog.saveButton.title=Save
-FileChooserPanel.title=Computer
-FileChooserPanel.tooltip.save=Select this tab to save data to your local storage
-FileChooserPanel.tooltip.open=Select this tab to read data from your local storage
-
-saveDialog.fileNotWritable=Sorry, this application can't write to this file.
Most commons causes are:
- The file is opened in another application.
- The file is located in a directory you are not allowed to write in.
- The file is write protected.
-openDialog.fileNotReadable=Sorry, this application can't read this file.
Most commons causes are:
- The file is opened in another application.
- The owner of this file does not give you the right to read.
-
-SearchPanel.find=Find:
-SearchPanel.ignoreMarks=Ignore accents
-SearchPanel.ingnoreCase=Ignore case
-
-FileSelector.new=New
-FileSelector.new.tooltip=Creates a new data file
-FileSelector.open=Open
-FileSelector.open.tooltip=Opens an existing data file
-FileSelector.save=Save
-FileSelector.save.tooltip=Saves data to disk
-FileSelector.saveAs=Save as...
-FileSelector.saveAs.tooltip=Saves data to a different location
-FileSelector.unsavedChanges=Unsaved changes
-FileSelector.unsavedChanges.question=There are unsaved changes. What do you want to do?
-
+#Translation tips:
+#Some strings contain patterns like {0}. These patterns has to remain unchanged when you translate these string.
+#For those who are familiar with MessageFormat, be aware that AJLib uses another library that do not use
+#single quote as an escape char. So, you have not to double every single quote.
+
+#Menu localization
+MainMenu.file=File
+MainMenu.file.mnemonic=F
+MainMenu.quit=Quit
+MainMenu.quit.shortcut=Q
+MainMenu.quit.mnemonic=Q
+MainMenu.quit.tooltip=Quits the application
+
+#Generic wordings
+GenericButton.ignore=Ignore
+GenericButton.cancel=Cancel
+GenericButton.cancel.toolTip=Cancels the current input
+GenericButton.ok=Validate
+GenericButton.ok.toolTip=Validates the current input
+Generic.warning=Warning
+Generic.error=Error
+
+Browser.unsupported.message=Unable to open a web browser.
The URL ({0}) has been copied to the clipboard.
You can now paste it to your web browser.
+
+# This dialog is opened when the file to save the data is already existing
+# Dialog title
+saveDialog.FileExist.title=Warning
+# Dialog message
+saveDialog.FileExist.message=File already exists. Would you like to overwrite it?
+openDialog.fileDoesntExist=The selected file does not exist
+openDialog.targetDoesntExist=The target of the selected shortcut does not exist.
+
+# ExcelPane
+ExcelPane.error.message=Error while saving the file ({0})
+ExcelPane.save=Save
+ExcelPane.csv.wording=CSV Files
+
+#File selection panels
+FileSelectionPanel.file=File:
+FileSelectionPanel.change=Change
+URIChooserDialog.noFileSelected=This button is disabled because no file is selected
+URIChooserDialog.openButton.title=Open
+URIChooserDialog.saveButton.title=Save
+FileChooserPanel.title=Computer
+FileChooserPanel.tooltip.save=Select this tab to save data to your local storage
+FileChooserPanel.tooltip.open=Select this tab to read data from your local storage
+
+saveDialog.fileNotWritable=Sorry, this application can't write to this file.
Most commons causes are:
- The file is opened in another application.
- The file is located in a directory you are not allowed to write in.
- The file is write protected.
+openDialog.fileNotReadable=Sorry, this application can't read this file.
Most commons causes are:
- The file is opened in another application.
- The owner of this file does not give you the right to read.
+
+SearchPanel.find=Find:
+SearchPanel.ignoreMarks=Ignore accents
+SearchPanel.ingnoreCase=Ignore case
+
+FileSelector.new=New
+FileSelector.new.tooltip=Creates a new data file
+FileSelector.open=Open
+FileSelector.open.tooltip=Opens an existing data file
+FileSelector.save=Save
+FileSelector.save.tooltip=Saves data to disk
+FileSelector.saveAs=Save as...
+FileSelector.saveAs.tooltip=Saves data to a different location
+FileSelector.unsavedChanges=Unsaved changes
+FileSelector.unsavedChanges.question=There are unsaved changes. What do you want to do?
+
diff --git a/src/main/resources/com/fathzer/soft/ajlib/Resources_fr.properties b/ajlib/src/main/resources/com/fathzer/soft/ajlib/Resources_fr.properties
similarity index 97%
rename from src/main/resources/com/fathzer/soft/ajlib/Resources_fr.properties
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/Resources_fr.properties
index c7f6315..ae870ce 100644
--- a/src/main/resources/com/fathzer/soft/ajlib/Resources_fr.properties
+++ b/ajlib/src/main/resources/com/fathzer/soft/ajlib/Resources_fr.properties
@@ -1,60 +1,60 @@
-#Menu localization
-MainMenu.file=Fichier
-MainMenu.file.mnemonic=F
-MainMenu.quit=Quitter
-MainMenu.quit.shortcut=Q
-MainMenu.quit.mnemonic=Q
-MainMenu.quit.tooltip=Quitte l'application
-
-#Generic wordings
-GenericButton.ignore=Ignorer
-GenericButton.cancel=Annuler
-GenericButton.cancel.toolTip=Annule la saisie en cours
-GenericButton.ok=Valider
-GenericButton.ok.toolTip=Valide la saisie en cours
-Generic.warning=Alerte
-Generic.error=Erreur
-
-Browser.unsupported.message=Impossible d'ouvrir un navigateur Web.
L'URL ({0}) a été copiée dans le presse-papiers.
Vous pouvez maintenant la coller dans votre navigateur Web.
-
-# This dialog is opened when the file to save the data is already existing
-# Dialog title
-saveDialog.FileExist.title=Attention
-# Dialog message
-saveDialog.FileExist.message=Le fichier existe déjà. Voulez-vous l'écraser ?
-openDialog.fileDoesntExist=Le fichier sélectionné n'existe pas
-openDialog.targetDoesntExist=La cible du raccourci sélectionné n'existe pas
-
-# ExcelPane
-ExcelPane.error.message=L'erreur {0} est survenue lors de la sauvegarde du fichier
-ExcelPane.save=Enregistrer
-ExcelPane.csv.wording=Fichier CSV
-
-#File selection panel
-FileSelectionPanel.file=Fichier :
-FileSelectionPanel.change=Changer
-URIChooserDialog.noFileSelected=Ce bouton est inactif car aucun fichier n'est sélectionné
-URIChooserDialog.openButton.title=Ouvrir
-URIChooserDialog.saveButton.title=Enregistrer
-FileChooserPanel.title=Ordinateur
-FileChooserPanel.tooltip.save=Selectionnez cet onglet pour sauver sur un support de stockage de votre ordinateur
-FileChooserPanel.tooltip.open=Selectionnez cet onglet pour lire à partir d'un support de stockage de votre ordinateur
-
-#To be translated
-saveDialog.fileNotWritable=Cette application ne peut pas écrire dans ce fichier.
Les causes courantes sont :
- Le fichier est ouvert dans une autre application.
- Le fichier est dans un dossier dans lequel vous n'êtes pas autorisé à écrire.
- Le fichier est protégé en écriture.
-openDialog.fileNotReadable=Cette application ne peut pas lire ce fichier.
Les causes courantes sont :
- Le fichier est ouvert dans une autre application.
- Le propriétaire de ce fichier ne vous a pas donné le droit de le lire.
-
-SearchPanel.find=Chercher :
-SearchPanel.ignoreMarks=Ignorer les accents
-SearchPanel.ingnoreCase=Ignorer la casse
-
-FileSelector.new=Nouveau
-FileSelector.new.tooltip=Crée un nouveau fichier de données
-FileSelector.open=Ouvrir
-FileSelector.open.tooltip=Ouvre un fichier de données
-FileSelector.save=Enregistrer
-FileSelector.save.tooltip=Enregistre les données sur disque
-FileSelector.saveAs=Enregistrer sous...
-FileSelector.saveAs.tooltip=Enregistre les données à un nouvel emplacement
-FileSelector.unsavedChanges=Des modifications n'ont pas été sauvegardées
-FileSelector.unsavedChanges.question=Des modifications n'ont pas été sauvegardées. Que fait-on ?
+#Menu localization
+MainMenu.file=Fichier
+MainMenu.file.mnemonic=F
+MainMenu.quit=Quitter
+MainMenu.quit.shortcut=Q
+MainMenu.quit.mnemonic=Q
+MainMenu.quit.tooltip=Quitte l'application
+
+#Generic wordings
+GenericButton.ignore=Ignorer
+GenericButton.cancel=Annuler
+GenericButton.cancel.toolTip=Annule la saisie en cours
+GenericButton.ok=Valider
+GenericButton.ok.toolTip=Valide la saisie en cours
+Generic.warning=Alerte
+Generic.error=Erreur
+
+Browser.unsupported.message=Impossible d'ouvrir un navigateur Web.
L'URL ({0}) a été copiée dans le presse-papiers.
Vous pouvez maintenant la coller dans votre navigateur Web.
+
+# This dialog is opened when the file to save the data is already existing
+# Dialog title
+saveDialog.FileExist.title=Attention
+# Dialog message
+saveDialog.FileExist.message=Le fichier existe déjà. Voulez-vous l'écraser ?
+openDialog.fileDoesntExist=Le fichier sélectionné n'existe pas
+openDialog.targetDoesntExist=La cible du raccourci sélectionné n'existe pas
+
+# ExcelPane
+ExcelPane.error.message=L'erreur {0} est survenue lors de la sauvegarde du fichier
+ExcelPane.save=Enregistrer
+ExcelPane.csv.wording=Fichier CSV
+
+#File selection panel
+FileSelectionPanel.file=Fichier :
+FileSelectionPanel.change=Changer
+URIChooserDialog.noFileSelected=Ce bouton est inactif car aucun fichier n'est sélectionné
+URIChooserDialog.openButton.title=Ouvrir
+URIChooserDialog.saveButton.title=Enregistrer
+FileChooserPanel.title=Ordinateur
+FileChooserPanel.tooltip.save=Selectionnez cet onglet pour sauver sur un support de stockage de votre ordinateur
+FileChooserPanel.tooltip.open=Selectionnez cet onglet pour lire à partir d'un support de stockage de votre ordinateur
+
+#To be translated
+saveDialog.fileNotWritable=Cette application ne peut pas écrire dans ce fichier.
Les causes courantes sont :
- Le fichier est ouvert dans une autre application.
- Le fichier est dans un dossier dans lequel vous n'êtes pas autorisé à écrire.
- Le fichier est protégé en écriture.
+openDialog.fileNotReadable=Cette application ne peut pas lire ce fichier.
Les causes courantes sont :
- Le fichier est ouvert dans une autre application.
- Le propriétaire de ce fichier ne vous a pas donné le droit de le lire.
+
+SearchPanel.find=Chercher :
+SearchPanel.ignoreMarks=Ignorer les accents
+SearchPanel.ingnoreCase=Ignorer la casse
+
+FileSelector.new=Nouveau
+FileSelector.new.tooltip=Crée un nouveau fichier de données
+FileSelector.open=Ouvrir
+FileSelector.open.tooltip=Ouvre un fichier de données
+FileSelector.save=Enregistrer
+FileSelector.save.tooltip=Enregistre les données sur disque
+FileSelector.saveAs=Enregistrer sous...
+FileSelector.saveAs.tooltip=Enregistre les données à un nouvel emplacement
+FileSelector.unsavedChanges=Des modifications n'ont pas été sauvegardées
+FileSelector.unsavedChanges.question=Des modifications n'ont pas été sauvegardées. Que fait-on ?
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/New.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/New.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/New.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/New.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/Open.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/Open.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/Open.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/Open.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/Save.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/Save.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/Save.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/Save.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/SaveAs.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/SaveAs.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/SaveAs.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/SaveAs.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/calendar.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/calendar.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/calendar.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/calendar.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/fast-forward.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/fast-forward.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/fast-forward.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/fast-forward.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/fast-rewind.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/fast-rewind.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/fast-rewind.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/fast-rewind.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/forward.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/forward.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/forward.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/forward.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/rewind.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/rewind.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/rewind.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/rewind.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/stop.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/stop.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/stop.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/date/stop.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/down.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/down.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/down.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/down.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/first.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/first.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/first.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/first.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/last.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/last.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/last.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/last.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/next.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/next.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/next.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/next.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/previous.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/previous.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/previous.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/previous.png
diff --git a/src/main/resources/com/fathzer/soft/ajlib/swing/widget/up.png b/ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/up.png
similarity index 100%
rename from src/main/resources/com/fathzer/soft/ajlib/swing/widget/up.png
rename to ajlib/src/main/resources/com/fathzer/soft/ajlib/swing/widget/up.png
diff --git a/src/test/java/com/fathzer/soft/ajlib/junit/CoolDateFormatterTest.java b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/CoolDateFormatterTest.java
similarity index 100%
rename from src/test/java/com/fathzer/soft/ajlib/junit/CoolDateFormatterTest.java
rename to ajlib/src/test/java/com/fathzer/soft/ajlib/junit/CoolDateFormatterTest.java
diff --git a/src/test/java/com/fathzer/soft/ajlib/junit/CurrencyWidgetTest.java b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/CurrencyWidgetTest.java
similarity index 96%
rename from src/test/java/com/fathzer/soft/ajlib/junit/CurrencyWidgetTest.java
rename to ajlib/src/test/java/com/fathzer/soft/ajlib/junit/CurrencyWidgetTest.java
index 68887cc..1a2b9a0 100644
--- a/src/test/java/com/fathzer/soft/ajlib/junit/CurrencyWidgetTest.java
+++ b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/CurrencyWidgetTest.java
@@ -1,46 +1,46 @@
-package com.fathzer.soft.ajlib.junit;
-
-import static org.junit.Assert.*;
-
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.util.Locale;
-
-import org.junit.Test;
-
-import com.fathzer.soft.ajlib.swing.widget.CurrencyWidget;
-import com.fathzer.soft.ajlib.swing.widget.NumberWidget;
-
-public class CurrencyWidgetTest {
- @Test
- public void test() {
- CurrencyWidget w = new CurrencyWidget(Locale.FRANCE);
- double value = 5000.0;
- w.setValue(value);
- assertEquals("5 000,00 €", w.getText());
- assertEquals(value, w.getValue(), 0.001);
-
- value = -5000.0;
- w.setValue(value);
- assertEquals("-5 000,00 €", w.getText());
- assertEquals(value, w.getValue(), 0.001);
- }
-
- private static class MyWidget extends NumberWidget {
- private static final long serialVersionUID = 1L;
-
- @Override
- public DecimalFormat patchJavaBug4510618(DecimalFormat format) {
- return super.patchJavaBug4510618(format);
- }
- }
-
- @Test
- public void fuckingJavaDecimalFormatTest() {
- DecimalFormat format = (DecimalFormat)NumberFormat.getCurrencyInstance(Locale.FRENCH);
- final String x = format.format(5000.0).replace((char)0x202F, ' ').replace((char)0x00A0, ' ');
-
- format = new MyWidget().patchJavaBug4510618(format);
- assertEquals(x, format.format(5000.0));
- }
-}
+package com.fathzer.soft.ajlib.junit;
+
+import static org.junit.Assert.*;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Locale;
+
+import org.junit.Test;
+
+import com.fathzer.soft.ajlib.swing.widget.CurrencyWidget;
+import com.fathzer.soft.ajlib.swing.widget.NumberWidget;
+
+public class CurrencyWidgetTest {
+ @Test
+ public void test() {
+ CurrencyWidget w = new CurrencyWidget(Locale.FRANCE);
+ double value = 5000.0;
+ w.setValue(value);
+ assertEquals("5 000,00 €", w.getText());
+ assertEquals(value, w.getValue(), 0.001);
+
+ value = -5000.0;
+ w.setValue(value);
+ assertEquals("-5 000,00 €", w.getText());
+ assertEquals(value, w.getValue(), 0.001);
+ }
+
+ private static class MyWidget extends NumberWidget {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public DecimalFormat patchJavaBug4510618(DecimalFormat format) {
+ return super.patchJavaBug4510618(format);
+ }
+ }
+
+ @Test
+ public void fuckingJavaDecimalFormatTest() {
+ DecimalFormat format = (DecimalFormat)NumberFormat.getCurrencyInstance(Locale.FRENCH);
+ final String x = format.format(5000.0).replace((char)0x202F, ' ').replace((char)0x00A0, ' ');
+
+ format = new MyWidget().patchJavaBug4510618(format);
+ assertEquals(x, format.format(5000.0));
+ }
+}
diff --git a/src/test/java/com/fathzer/soft/ajlib/junit/DateWidgetTest.java b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/DateWidgetTest.java
similarity index 96%
rename from src/test/java/com/fathzer/soft/ajlib/junit/DateWidgetTest.java
rename to ajlib/src/test/java/com/fathzer/soft/ajlib/junit/DateWidgetTest.java
index cf36053..d8c9d11 100644
--- a/src/test/java/com/fathzer/soft/ajlib/junit/DateWidgetTest.java
+++ b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/DateWidgetTest.java
@@ -1,75 +1,75 @@
-package com.fathzer.soft.ajlib.junit;
-
-import static org.junit.Assert.*;
-import static org.junit.Assume.assumeFalse;
-
-import java.awt.GraphicsEnvironment;
-import java.awt.event.KeyEvent;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-
-import javax.swing.JFrame;
-
-import org.junit.Test;
-
-import com.fathzer.soft.ajlib.junit.utils.AbstractSwingTest;
-import com.fathzer.soft.ajlib.swing.widget.date.DateField;
-import com.fathzer.soft.ajlib.swing.widget.date.DateWidget;
-
-public class DateWidgetTest extends AbstractSwingTest {
-
- @Test
- public void test() throws Throwable {
- assumeFalse(GraphicsEnvironment.isHeadless());
-
- final DateWidgetFrame test = new DateWidgetFrame();
- test.initTest();
- assertTrue(test.widget.isContentValid());
- assertTrue(test.widget.getDateField().isContentValid());
- MyListener widgetListener = new MyListener();
- test.widget.addPropertyChangeListener(DateWidget.CONTENT_VALID_PROPERTY, widgetListener);
- MyListener fieldListener = new MyListener();
- test.widget.getDateField().addPropertyChangeListener(DateField.CONTENT_VALID_PROPERTY, fieldListener);
- // Let some time to allow window to acquire the focus
- robot.delay(100);
- robot.keyPress(KeyEvent.VK_X);
- robot.keyRelease(KeyEvent.VK_X);
- robot.delay(50);
- assertEquals("x", test.widget.getDateField().getText());
- assertFalse(test.widget.isContentValid());
- assertFalse(test.widget.getDateField().isContentValid());
- widgetListener.reset();
- fieldListener.reset();
- robot.keyPress(KeyEvent.VK_BACK_SPACE);
- robot.keyRelease(KeyEvent.VK_BACK_SPACE);
- robot.delay(50);
- assertTrue(test.widget.getDateField().getText().isEmpty());
- assertTrue(test.widget.isContentValid());
- assertTrue(fieldListener.changed);
- assertTrue(widgetListener.changed);
- }
-
- private static final class MyListener implements PropertyChangeListener {
- private boolean changed;
-
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- changed=true;
- }
-
- public void reset() {
- changed = false;
- }
- }
-
- private static class DateWidgetFrame extends AbstractSwingWindow {
- private DateWidget widget;
-
- protected void populate(JFrame f) {
- widget = new DateWidget();
- widget.setDate(null);
- f.add(widget);
- f.pack();
- }
- }
+package com.fathzer.soft.ajlib.junit;
+
+import static org.junit.Assert.*;
+import static org.junit.Assume.assumeFalse;
+
+import java.awt.GraphicsEnvironment;
+import java.awt.event.KeyEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.JFrame;
+
+import org.junit.Test;
+
+import com.fathzer.soft.ajlib.junit.utils.AbstractSwingTest;
+import com.fathzer.soft.ajlib.swing.widget.date.DateField;
+import com.fathzer.soft.ajlib.swing.widget.date.DateWidget;
+
+public class DateWidgetTest extends AbstractSwingTest {
+
+ @Test
+ public void test() throws Throwable {
+ assumeFalse(GraphicsEnvironment.isHeadless());
+
+ final DateWidgetFrame test = new DateWidgetFrame();
+ test.initTest();
+ assertTrue(test.widget.isContentValid());
+ assertTrue(test.widget.getDateField().isContentValid());
+ MyListener widgetListener = new MyListener();
+ test.widget.addPropertyChangeListener(DateWidget.CONTENT_VALID_PROPERTY, widgetListener);
+ MyListener fieldListener = new MyListener();
+ test.widget.getDateField().addPropertyChangeListener(DateField.CONTENT_VALID_PROPERTY, fieldListener);
+ // Let some time to allow window to acquire the focus
+ robot.delay(100);
+ robot.keyPress(KeyEvent.VK_X);
+ robot.keyRelease(KeyEvent.VK_X);
+ robot.delay(50);
+ assertEquals("x", test.widget.getDateField().getText());
+ assertFalse(test.widget.isContentValid());
+ assertFalse(test.widget.getDateField().isContentValid());
+ widgetListener.reset();
+ fieldListener.reset();
+ robot.keyPress(KeyEvent.VK_BACK_SPACE);
+ robot.keyRelease(KeyEvent.VK_BACK_SPACE);
+ robot.delay(50);
+ assertTrue(test.widget.getDateField().getText().isEmpty());
+ assertTrue(test.widget.isContentValid());
+ assertTrue(fieldListener.changed);
+ assertTrue(widgetListener.changed);
+ }
+
+ private static final class MyListener implements PropertyChangeListener {
+ private boolean changed;
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ changed=true;
+ }
+
+ public void reset() {
+ changed = false;
+ }
+ }
+
+ private static class DateWidgetFrame extends AbstractSwingWindow {
+ private DateWidget widget;
+
+ protected void populate(JFrame f) {
+ widget = new DateWidget();
+ widget.setDate(null);
+ f.add(widget);
+ f.pack();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/test/java/com/fathzer/soft/ajlib/junit/FileUtilsTest.java b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/FileUtilsTest.java
similarity index 96%
rename from src/test/java/com/fathzer/soft/ajlib/junit/FileUtilsTest.java
rename to ajlib/src/test/java/com/fathzer/soft/ajlib/junit/FileUtilsTest.java
index 27f6f71..700a271 100644
--- a/src/test/java/com/fathzer/soft/ajlib/junit/FileUtilsTest.java
+++ b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/FileUtilsTest.java
@@ -1,26 +1,26 @@
-package com.fathzer.soft.ajlib.junit;
-
-import static org.junit.Assert.*;
-
-import java.io.File;
-
-import org.junit.Test;
-
-import com.fathzer.soft.ajlib.utilities.FileUtils;
-import com.fathzer.soft.ajlib.utilities.StringUtils;
-
-/** Tests for StringUtils class.
- * @see StringUtils
- */
-public class FileUtilsTest {
-
- @Test
- public void testExtension() {
- assertEquals(".xml", FileUtils.getExtension(new File("x.xml")));
- assertEquals(null, FileUtils.getExtension(new File("")));
- assertEquals(".", FileUtils.getExtension(new File(".")));
- assertEquals("x", FileUtils.getRootName(new File("x.xml")));
- assertEquals("", FileUtils.getRootName(new File("")));
- assertEquals("", FileUtils.getRootName(new File(".")));
- }
-}
+package com.fathzer.soft.ajlib.junit;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+
+import org.junit.Test;
+
+import com.fathzer.soft.ajlib.utilities.FileUtils;
+import com.fathzer.soft.ajlib.utilities.StringUtils;
+
+/** Tests for StringUtils class.
+ * @see StringUtils
+ */
+public class FileUtilsTest {
+
+ @Test
+ public void testExtension() {
+ assertEquals(".xml", FileUtils.getExtension(new File("x.xml")));
+ assertEquals(null, FileUtils.getExtension(new File("")));
+ assertEquals(".", FileUtils.getExtension(new File(".")));
+ assertEquals("x", FileUtils.getRootName(new File("x.xml")));
+ assertEquals("", FileUtils.getRootName(new File("")));
+ assertEquals("", FileUtils.getRootName(new File(".")));
+ }
+}
diff --git a/src/test/java/com/fathzer/soft/ajlib/junit/ListUtilsTest.java b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/ListUtilsTest.java
similarity index 96%
rename from src/test/java/com/fathzer/soft/ajlib/junit/ListUtilsTest.java
rename to ajlib/src/test/java/com/fathzer/soft/ajlib/junit/ListUtilsTest.java
index c535f7f..3b381ae 100644
--- a/src/test/java/com/fathzer/soft/ajlib/junit/ListUtilsTest.java
+++ b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/ListUtilsTest.java
@@ -1,63 +1,63 @@
-package com.fathzer.soft.ajlib.junit;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import com.fathzer.soft.ajlib.utilities.ListUtils;
-import com.fathzer.soft.ajlib.utilities.StringUtils;
-
-/** Tests for StringUtils class.
- * @see StringUtils
- */
-public class ListUtilsTest {
- private static Collection list;
-
- @BeforeClass
- public static void init() {
- list = new ArrayList();
- for (int i = 0; i < 10; i++) {
- list.add(i);
- }
- list = Collections.unmodifiableCollection(list);
- }
-
- @Test
- public void testOne() {
- List tested = new ArrayList(list);
- ListUtils.move(tested, 4, -2);
- assertIs(new int[]{0,1,4,2,3,5,6,7,8,9},tested);
- ListUtils.move(tested, 2, 2);
- assertIs(new int[]{0,1,2,3,4,5,6,7,8,9},tested);
- }
-
- @Test
- public void testMany() {
- List tested = new ArrayList(list);
- ListUtils.move(tested, new int[]{4,8,9}, -3);
- assertIs(new int[]{0,4,1,2,3,8,9,5,6,7},tested);
- ListUtils.move(tested, new int[]{1,5,6}, 3);
- assertIs(new int[]{0,1,2,3,4,5,6,7,8,9},tested);
- }
-
- private void assertIs(int[] expected, List actual) {
- if (expected.length!=actual.size()) {
- err(expected, actual, "(different lengths");
- }
- for (int i = 0; i < expected.length; i++) {
- if (expected[i] != actual.get(i)) {
- String message = "(expected["+i+"]="+expected[i]+" is not actual["+i+"]="+actual.get(i)+")";
- err(expected, actual, message);
- }
- }
- }
-
- private void err(int[] expected, List actual, String message) {
- throw new AssertionError("Expected <"+Arrays.toString(expected)+"> but was <"+actual+"> "+message);
- }
-}
+package com.fathzer.soft.ajlib.junit;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.fathzer.soft.ajlib.utilities.ListUtils;
+import com.fathzer.soft.ajlib.utilities.StringUtils;
+
+/** Tests for StringUtils class.
+ * @see StringUtils
+ */
+public class ListUtilsTest {
+ private static Collection list;
+
+ @BeforeClass
+ public static void init() {
+ list = new ArrayList();
+ for (int i = 0; i < 10; i++) {
+ list.add(i);
+ }
+ list = Collections.unmodifiableCollection(list);
+ }
+
+ @Test
+ public void testOne() {
+ List tested = new ArrayList(list);
+ ListUtils.move(tested, 4, -2);
+ assertIs(new int[]{0,1,4,2,3,5,6,7,8,9},tested);
+ ListUtils.move(tested, 2, 2);
+ assertIs(new int[]{0,1,2,3,4,5,6,7,8,9},tested);
+ }
+
+ @Test
+ public void testMany() {
+ List tested = new ArrayList(list);
+ ListUtils.move(tested, new int[]{4,8,9}, -3);
+ assertIs(new int[]{0,4,1,2,3,8,9,5,6,7},tested);
+ ListUtils.move(tested, new int[]{1,5,6}, 3);
+ assertIs(new int[]{0,1,2,3,4,5,6,7,8,9},tested);
+ }
+
+ private void assertIs(int[] expected, List actual) {
+ if (expected.length!=actual.size()) {
+ err(expected, actual, "(different lengths");
+ }
+ for (int i = 0; i < expected.length; i++) {
+ if (expected[i] != actual.get(i)) {
+ String message = "(expected["+i+"]="+expected[i]+" is not actual["+i+"]="+actual.get(i)+")";
+ err(expected, actual, message);
+ }
+ }
+ }
+
+ private void err(int[] expected, List actual, String message) {
+ throw new AssertionError("Expected <"+Arrays.toString(expected)+"> but was <"+actual+"> "+message);
+ }
+}
diff --git a/src/test/java/com/fathzer/soft/ajlib/junit/LocalizationDataTest.java b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/LocalizationDataTest.java
similarity index 96%
rename from src/test/java/com/fathzer/soft/ajlib/junit/LocalizationDataTest.java
rename to ajlib/src/test/java/com/fathzer/soft/ajlib/junit/LocalizationDataTest.java
index 4d7ff26..b04498b 100644
--- a/src/test/java/com/fathzer/soft/ajlib/junit/LocalizationDataTest.java
+++ b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/LocalizationDataTest.java
@@ -1,22 +1,22 @@
-package com.fathzer.soft.ajlib.junit;
-
-import static org.junit.Assert.*;
-
-import java.util.Locale;
-
-
-import org.junit.Test;
-
-import com.fathzer.soft.ajlib.utilities.LocalizationData;
-
-public class LocalizationDataTest {
- private static final String NAME = "name";
-
- @Test
- public void test() {
- LocalizationData loc = new LocalizationData("com.fathzer.soft.ajlib.junit.Resources");
- assertEquals (loc.getString(NAME, Locale.US), Locale.US.getLanguage());
- assertEquals (loc.getString(NAME, Locale.FRANCE), Locale.FRANCE.getLanguage());
- }
-
-}
+package com.fathzer.soft.ajlib.junit;
+
+import static org.junit.Assert.*;
+
+import java.util.Locale;
+
+
+import org.junit.Test;
+
+import com.fathzer.soft.ajlib.utilities.LocalizationData;
+
+public class LocalizationDataTest {
+ private static final String NAME = "name";
+
+ @Test
+ public void test() {
+ LocalizationData loc = new LocalizationData("com.fathzer.soft.ajlib.junit.Resources");
+ assertEquals (loc.getString(NAME, Locale.US), Locale.US.getLanguage());
+ assertEquals (loc.getString(NAME, Locale.FRANCE), Locale.FRANCE.getLanguage());
+ }
+
+}
diff --git a/src/test/java/com/fathzer/soft/ajlib/junit/StringUtilsTest.java b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/StringUtilsTest.java
similarity index 96%
rename from src/test/java/com/fathzer/soft/ajlib/junit/StringUtilsTest.java
rename to ajlib/src/test/java/com/fathzer/soft/ajlib/junit/StringUtilsTest.java
index 99bbd1f..24c1148 100644
--- a/src/test/java/com/fathzer/soft/ajlib/junit/StringUtilsTest.java
+++ b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/StringUtilsTest.java
@@ -1,28 +1,28 @@
-package com.fathzer.soft.ajlib.junit;
-
-import static org.junit.Assert.*;
-
-
-import org.junit.Test;
-
-import com.fathzer.soft.ajlib.utilities.StringUtils;
-
-/** Tests for StringUtils class.
- * @see StringUtils
- */
-public class StringUtilsTest {
-
- @Test
- public void testSplit() {
- // Tests empty imput string
- assertArrayEquals(new String[]{""}, StringUtils.split("", ','));
- // Tests string which not contains the delimiter
- assertArrayEquals(new String[]{"ABC"}, StringUtils.split("ABC", ','));
- // Tests standard use
- assertArrayEquals(new String[]{"A","B","C"}, StringUtils.split("A,B,C", ','));
- // Tests string beginning and ending by the delimiter
- assertArrayEquals(new String[]{"","A","","B","C",""}, StringUtils.split(",A,,B,C,", ','));
- // Test exotic delimiter
- assertArrayEquals(new String[]{"A","B","C"}, StringUtils.split("A\\B\\C", '\\'));
- }
-}
+package com.fathzer.soft.ajlib.junit;
+
+import static org.junit.Assert.*;
+
+
+import org.junit.Test;
+
+import com.fathzer.soft.ajlib.utilities.StringUtils;
+
+/** Tests for StringUtils class.
+ * @see StringUtils
+ */
+public class StringUtilsTest {
+
+ @Test
+ public void testSplit() {
+ // Tests empty imput string
+ assertArrayEquals(new String[]{""}, StringUtils.split("", ','));
+ // Tests string which not contains the delimiter
+ assertArrayEquals(new String[]{"ABC"}, StringUtils.split("ABC", ','));
+ // Tests standard use
+ assertArrayEquals(new String[]{"A","B","C"}, StringUtils.split("A,B,C", ','));
+ // Tests string beginning and ending by the delimiter
+ assertArrayEquals(new String[]{"","A","","B","C",""}, StringUtils.split(",A,,B,C,", ','));
+ // Test exotic delimiter
+ assertArrayEquals(new String[]{"A","B","C"}, StringUtils.split("A\\B\\C", '\\'));
+ }
+}
diff --git a/src/test/java/com/fathzer/soft/ajlib/junit/utils/AbstractSwingTest.java b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/utils/AbstractSwingTest.java
similarity index 95%
rename from src/test/java/com/fathzer/soft/ajlib/junit/utils/AbstractSwingTest.java
rename to ajlib/src/test/java/com/fathzer/soft/ajlib/junit/utils/AbstractSwingTest.java
index f64516b..08b5cdf 100644
--- a/src/test/java/com/fathzer/soft/ajlib/junit/utils/AbstractSwingTest.java
+++ b/ajlib/src/test/java/com/fathzer/soft/ajlib/junit/utils/AbstractSwingTest.java
@@ -1,62 +1,62 @@
-package com.fathzer.soft.ajlib.junit.utils;
-
-import java.awt.AWTException;
-import java.awt.EventQueue;
-import java.awt.FlowLayout;
-import java.awt.GraphicsEnvironment;
-import java.awt.Robot;
-
-import javax.swing.JFrame;
-
-import org.junit.BeforeClass;
-
-public abstract class AbstractSwingTest {
- protected static Robot robot;
-
- @BeforeClass
- public static void init() throws AWTException {
- if (!GraphicsEnvironment.isHeadless()) {
- robot = new Robot();
- }
- }
-
- protected static abstract class AbstractSwingWindow {
- private Throwable exception;
-
- public void initTest() throws InterruptedException, Throwable {
- EventQueue.invokeLater(new Runnable() {
- public void run() {
- build();
- }
- });
- synchronized (this) {
- wait();
- }
- if (exception!=null) {
- throw exception;
- }
- }
-
- private void build() {
- try {
- init();
- } catch (Throwable e) {
- exception = e;
- }
- synchronized (this) {
- notifyAll();
- }
- }
-
- private void init() {
- JFrame f = new JFrame();
- f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- f.setLocationRelativeTo(null);
- f.setLayout(new FlowLayout());
- populate(f);
- f.setVisible(true);
- }
-
- protected abstract void populate(JFrame f);
- }
+package com.fathzer.soft.ajlib.junit.utils;
+
+import java.awt.AWTException;
+import java.awt.EventQueue;
+import java.awt.FlowLayout;
+import java.awt.GraphicsEnvironment;
+import java.awt.Robot;
+
+import javax.swing.JFrame;
+
+import org.junit.BeforeClass;
+
+public abstract class AbstractSwingTest {
+ protected static Robot robot;
+
+ @BeforeClass
+ public static void init() throws AWTException {
+ if (!GraphicsEnvironment.isHeadless()) {
+ robot = new Robot();
+ }
+ }
+
+ protected static abstract class AbstractSwingWindow {
+ private Throwable exception;
+
+ public void initTest() throws InterruptedException, Throwable {
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ build();
+ }
+ });
+ synchronized (this) {
+ wait();
+ }
+ if (exception!=null) {
+ throw exception;
+ }
+ }
+
+ private void build() {
+ try {
+ init();
+ } catch (Throwable e) {
+ exception = e;
+ }
+ synchronized (this) {
+ notifyAll();
+ }
+ }
+
+ private void init() {
+ JFrame f = new JFrame();
+ f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ f.setLocationRelativeTo(null);
+ f.setLayout(new FlowLayout());
+ populate(f);
+ f.setVisible(true);
+ }
+
+ protected abstract void populate(JFrame f);
+ }
}
\ No newline at end of file
diff --git a/src/test/resources/com/fathzer/soft/ajlib/junit/Resources.properties b/ajlib/src/test/resources/com/fathzer/soft/ajlib/junit/Resources.properties
similarity index 100%
rename from src/test/resources/com/fathzer/soft/ajlib/junit/Resources.properties
rename to ajlib/src/test/resources/com/fathzer/soft/ajlib/junit/Resources.properties
diff --git a/src/test/resources/com/fathzer/soft/ajlib/junit/Resources_en.properties b/ajlib/src/test/resources/com/fathzer/soft/ajlib/junit/Resources_en.properties
similarity index 100%
rename from src/test/resources/com/fathzer/soft/ajlib/junit/Resources_en.properties
rename to ajlib/src/test/resources/com/fathzer/soft/ajlib/junit/Resources_en.properties
diff --git a/src/test/resources/com/fathzer/soft/ajlib/junit/Resources_fr.properties b/ajlib/src/test/resources/com/fathzer/soft/ajlib/junit/Resources_fr.properties
similarity index 100%
rename from src/test/resources/com/fathzer/soft/ajlib/junit/Resources_fr.properties
rename to ajlib/src/test/resources/com/fathzer/soft/ajlib/junit/Resources_fr.properties
diff --git a/demo/pom.xml b/demo/pom.xml
new file mode 100644
index 0000000..e4b7a3b
--- /dev/null
+++ b/demo/pom.xml
@@ -0,0 +1,50 @@
+
+ 4.0.0
+
+ com.fathzer
+ ajlib-parent-pom
+ 1.0.0
+
+ ajlib-demo
+ 0.3.16
+
+ jar
+
+ A-JLib-demo
+
+
+
+ com.fathzer
+ ajlib
+ 0.3.16
+
+
+
+
+
+
+ maven-shade-plugin
+ 3.4.1
+
+ true
+
+
+ com.fathzer.soft.ajlib.swing.demo.AJLibDemo
+
+
+
+
+
+ package
+
+ shade
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/demo/AJLibDemo.java b/demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/AJLibDemo.java
similarity index 95%
rename from src/main/java/com/fathzer/soft/ajlib/swing/demo/AJLibDemo.java
rename to demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/AJLibDemo.java
index 0a3089e..1d672e6 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/demo/AJLibDemo.java
+++ b/demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/AJLibDemo.java
@@ -1,39 +1,39 @@
-package com.fathzer.soft.ajlib.swing.demo;
-
-import javax.swing.JPanel;
-
-import com.fathzer.soft.ajlib.swing.framework.Application;
-
-/** This is a simple demonstration application. */
-public class AJLibDemo extends Application {
- public static final AJLibDemo DEMO = new AJLibDemo();
-
- private AJLibDemoPanel demoPanel;
-
- private AJLibDemo() {
- }
-
- @Override
- public String getName() {
- return "AJLibDemo";
- }
-
- @Override
- protected JPanel buildMainPanel() {
- if (demoPanel==null) {
- demoPanel = new AJLibDemoPanel();
- }
- return demoPanel;
- }
-
- /**
- * @param args Program arguments
- */
- public static void main(String[] args) {
- DEMO.launch();
- }
-
- public static void setMessage(String text) {
- DEMO.demoPanel.setMessage(text);
- }
-}
+package com.fathzer.soft.ajlib.swing.demo;
+
+import javax.swing.JPanel;
+
+import com.fathzer.soft.ajlib.swing.framework.Application;
+
+/** This is a simple demonstration application. */
+public class AJLibDemo extends Application {
+ public static final AJLibDemo DEMO = new AJLibDemo();
+
+ private AJLibDemoPanel demoPanel;
+
+ private AJLibDemo() {
+ }
+
+ @Override
+ public String getName() {
+ return "AJLibDemo";
+ }
+
+ @Override
+ protected JPanel buildMainPanel() {
+ if (demoPanel==null) {
+ demoPanel = new AJLibDemoPanel();
+ }
+ return demoPanel;
+ }
+
+ /**
+ * @param args Program arguments
+ */
+ public static void main(String[] args) {
+ DEMO.launch();
+ }
+
+ public static void setMessage(String text) {
+ DEMO.demoPanel.setMessage(text);
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/demo/AJLibDemoPanel.java b/demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/AJLibDemoPanel.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/demo/AJLibDemoPanel.java
rename to demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/AJLibDemoPanel.java
index 11d7046..b121340 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/demo/AJLibDemoPanel.java
+++ b/demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/AJLibDemoPanel.java
@@ -1,59 +1,59 @@
-package com.fathzer.soft.ajlib.swing.demo;
-
-import javax.swing.JPanel;
-import javax.swing.JLabel;
-import java.awt.GridBagLayout;
-import java.awt.GridBagConstraints;
-import java.awt.Insets;
-import javax.swing.JTabbedPane;
-
-@SuppressWarnings("serial")
-public class AJLibDemoPanel extends JPanel {
-
- private JLabel messageLabel;
-
- /**
- * Create the panel.
- */
- public AJLibDemoPanel() {
-
- initialize();
- }
- private void initialize() {
- GridBagLayout gridBagLayout = new GridBagLayout();
- setLayout(gridBagLayout);
-
- JTabbedPane panel = new JTabbedPane();
- GridBagConstraints gbcPanel = new GridBagConstraints();
- gbcPanel.weightx = 1.0;
- gbcPanel.weighty = 1.0;
- gbcPanel.fill = GridBagConstraints.BOTH;
- gbcPanel.gridx = 0;
- gbcPanel.gridy = 0;
- add(panel, gbcPanel);
-
- panel.add("widget", new WidgetsDemoPanel());
-
- panel.add("widget.date", new DateDemoPanel());
-
- panel.add("rotating label", new RotatingLabelPanel());
-
- panel.add("worker", new WorkerDemoPanel());
-
- panel.add("dialog", new DialogsPanel());
-
- messageLabel = new JLabel(" ");
- GridBagConstraints gbcMessageLabel = new GridBagConstraints();
- gbcMessageLabel.insets = new Insets(5, 5, 0, 5);
- gbcMessageLabel.weightx = 1.0;
- gbcMessageLabel.fill = GridBagConstraints.HORIZONTAL;
- gbcMessageLabel.anchor = GridBagConstraints.NORTHWEST;
- gbcMessageLabel.gridx = 0;
- gbcMessageLabel.gridy = 1;
- add(messageLabel, gbcMessageLabel);
- }
-
- public void setMessage(String text) {
- messageLabel.setText(text);
- }
-}
+package com.fathzer.soft.ajlib.swing.demo;
+
+import javax.swing.JPanel;
+import javax.swing.JLabel;
+import java.awt.GridBagLayout;
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+import javax.swing.JTabbedPane;
+
+@SuppressWarnings("serial")
+public class AJLibDemoPanel extends JPanel {
+
+ private JLabel messageLabel;
+
+ /**
+ * Create the panel.
+ */
+ public AJLibDemoPanel() {
+
+ initialize();
+ }
+ private void initialize() {
+ GridBagLayout gridBagLayout = new GridBagLayout();
+ setLayout(gridBagLayout);
+
+ JTabbedPane panel = new JTabbedPane();
+ GridBagConstraints gbcPanel = new GridBagConstraints();
+ gbcPanel.weightx = 1.0;
+ gbcPanel.weighty = 1.0;
+ gbcPanel.fill = GridBagConstraints.BOTH;
+ gbcPanel.gridx = 0;
+ gbcPanel.gridy = 0;
+ add(panel, gbcPanel);
+
+ panel.add("widget", new WidgetsDemoPanel());
+
+ panel.add("widget.date", new DateDemoPanel());
+
+ panel.add("rotating label", new RotatingLabelPanel());
+
+ panel.add("worker", new WorkerDemoPanel());
+
+ panel.add("dialog", new DialogsPanel());
+
+ messageLabel = new JLabel(" ");
+ GridBagConstraints gbcMessageLabel = new GridBagConstraints();
+ gbcMessageLabel.insets = new Insets(5, 5, 0, 5);
+ gbcMessageLabel.weightx = 1.0;
+ gbcMessageLabel.fill = GridBagConstraints.HORIZONTAL;
+ gbcMessageLabel.anchor = GridBagConstraints.NORTHWEST;
+ gbcMessageLabel.gridx = 0;
+ gbcMessageLabel.gridy = 1;
+ add(messageLabel, gbcMessageLabel);
+ }
+
+ public void setMessage(String text) {
+ messageLabel.setText(text);
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/demo/DateDemoPanel.java b/demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/DateDemoPanel.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/demo/DateDemoPanel.java
rename to demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/DateDemoPanel.java
index 5332f9b..cd4e302 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/demo/DateDemoPanel.java
+++ b/demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/DateDemoPanel.java
@@ -1,101 +1,101 @@
-package com.fathzer.soft.ajlib.swing.demo;
-
-import javax.swing.JPanel;
-import java.awt.GridBagLayout;
-import javax.swing.JLabel;
-import java.awt.GridBagConstraints;
-import java.awt.Insets;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.text.DateFormat;
-import java.util.Date;
-
-import javax.swing.border.TitledBorder;
-
-import com.fathzer.soft.ajlib.swing.widget.date.CalendarWidget;
-import com.fathzer.soft.ajlib.swing.widget.date.DateField;
-import com.fathzer.soft.ajlib.swing.widget.date.DateWidget;
-
-@SuppressWarnings("serial")
-public class DateDemoPanel extends JPanel {
- private DateField textField;
-
- /**
- * Create the panel.
- */
- public DateDemoPanel() {
- GridBagLayout gridBagLayout = new GridBagLayout();
- setLayout(gridBagLayout);
-
- PropertyChangeListener listener = new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- Date old = (Date) evt.getOldValue();
- Date date = (Date) evt.getNewValue();
- DateFormat format = DateFormat.getDateInstance(DateFormat.MEDIUM);
- String oldString = old == null ? "?" : format.format(old);
- String dateString = date == null ? "?" : format.format(date);
- AJLibDemo.setMessage("Date changed from "+oldString+" to "+dateString);
- }
- };
-
- JLabel lblNewLabel = new JLabel("DateWidget:");
- GridBagConstraints gbcLblNewLabel = new GridBagConstraints();
- gbcLblNewLabel.insets = new Insets(0, 5, 5, 5);
- gbcLblNewLabel.anchor = GridBagConstraints.WEST;
- gbcLblNewLabel.gridx = 0;
- gbcLblNewLabel.gridy = 0;
- add(lblNewLabel, gbcLblNewLabel);
-
- DateWidget panel = new DateWidget();
- panel.addPropertyChangeListener(DateWidget.DATE_PROPERTY, listener);
- GridBagConstraints gbcPanel = new GridBagConstraints();
- gbcPanel.insets = new Insets(0, 0, 5, 0);
- gbcPanel.anchor = GridBagConstraints.NORTHWEST;
- gbcPanel.gridx = 1;
- gbcPanel.gridy = 0;
- add(panel, gbcPanel);
-
- JLabel lblDatefield = new JLabel("DateField:");
- GridBagConstraints gbcLblDatefield = new GridBagConstraints();
- gbcLblDatefield.anchor = GridBagConstraints.WEST;
- gbcLblDatefield.insets = new Insets(0, 5, 5, 5);
- gbcLblDatefield.gridx = 0;
- gbcLblDatefield.gridy = 1;
- add(lblDatefield, gbcLblDatefield);
-
- textField = new DateField();
- textField.addPropertyChangeListener(DateField.DATE_PROPERTY, listener);
- GridBagConstraints gbcTextField = new GridBagConstraints();
- gbcTextField.insets = new Insets(0, 0, 5, 0);
- gbcTextField.anchor = GridBagConstraints.WEST;
- gbcTextField.gridx = 1;
- gbcTextField.gridy = 1;
- add(textField, gbcTextField);
- textField.setColumns(10);
-
- JPanel panel1 = new JPanel();
- panel1.setBorder(new TitledBorder(null, "CalendarWidget", TitledBorder.LEADING, TitledBorder.TOP, null, null));
- GridBagConstraints gbcPanel1 = new GridBagConstraints();
- gbcPanel1.anchor = GridBagConstraints.NORTHWEST;
- gbcPanel1.weighty = 1.0;
- gbcPanel1.weightx = 1.0;
- gbcPanel1.gridwidth = 2;
- gbcPanel1.insets = new Insets(0, 0, 0, 5);
- gbcPanel1.gridx = 0;
- gbcPanel1.gridy = 2;
- add(panel1, gbcPanel1);
- GridBagLayout gblPanel1 = new GridBagLayout();
- panel1.setLayout(gblPanel1);
-
- CalendarWidget calendarWidget = new CalendarWidget();
- calendarWidget.addPropertyChangeListener(CalendarWidget.DATE_PROPERTY, listener);
- GridBagConstraints gbcCalendarWidget = new GridBagConstraints();
- gbcCalendarWidget.anchor = GridBagConstraints.WEST;
- gbcCalendarWidget.insets = new Insets(0, 0, 5, 0);
- gbcCalendarWidget.gridwidth = 2;
- gbcCalendarWidget.gridx = 0;
- gbcCalendarWidget.gridy = 0;
- panel1.add(calendarWidget, gbcCalendarWidget);
- }
-}
+package com.fathzer.soft.ajlib.swing.demo;
+
+import javax.swing.JPanel;
+import java.awt.GridBagLayout;
+import javax.swing.JLabel;
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.text.DateFormat;
+import java.util.Date;
+
+import javax.swing.border.TitledBorder;
+
+import com.fathzer.soft.ajlib.swing.widget.date.CalendarWidget;
+import com.fathzer.soft.ajlib.swing.widget.date.DateField;
+import com.fathzer.soft.ajlib.swing.widget.date.DateWidget;
+
+@SuppressWarnings("serial")
+public class DateDemoPanel extends JPanel {
+ private DateField textField;
+
+ /**
+ * Create the panel.
+ */
+ public DateDemoPanel() {
+ GridBagLayout gridBagLayout = new GridBagLayout();
+ setLayout(gridBagLayout);
+
+ PropertyChangeListener listener = new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ Date old = (Date) evt.getOldValue();
+ Date date = (Date) evt.getNewValue();
+ DateFormat format = DateFormat.getDateInstance(DateFormat.MEDIUM);
+ String oldString = old == null ? "?" : format.format(old);
+ String dateString = date == null ? "?" : format.format(date);
+ AJLibDemo.setMessage("Date changed from "+oldString+" to "+dateString);
+ }
+ };
+
+ JLabel lblNewLabel = new JLabel("DateWidget:");
+ GridBagConstraints gbcLblNewLabel = new GridBagConstraints();
+ gbcLblNewLabel.insets = new Insets(0, 5, 5, 5);
+ gbcLblNewLabel.anchor = GridBagConstraints.WEST;
+ gbcLblNewLabel.gridx = 0;
+ gbcLblNewLabel.gridy = 0;
+ add(lblNewLabel, gbcLblNewLabel);
+
+ DateWidget panel = new DateWidget();
+ panel.addPropertyChangeListener(DateWidget.DATE_PROPERTY, listener);
+ GridBagConstraints gbcPanel = new GridBagConstraints();
+ gbcPanel.insets = new Insets(0, 0, 5, 0);
+ gbcPanel.anchor = GridBagConstraints.NORTHWEST;
+ gbcPanel.gridx = 1;
+ gbcPanel.gridy = 0;
+ add(panel, gbcPanel);
+
+ JLabel lblDatefield = new JLabel("DateField:");
+ GridBagConstraints gbcLblDatefield = new GridBagConstraints();
+ gbcLblDatefield.anchor = GridBagConstraints.WEST;
+ gbcLblDatefield.insets = new Insets(0, 5, 5, 5);
+ gbcLblDatefield.gridx = 0;
+ gbcLblDatefield.gridy = 1;
+ add(lblDatefield, gbcLblDatefield);
+
+ textField = new DateField();
+ textField.addPropertyChangeListener(DateField.DATE_PROPERTY, listener);
+ GridBagConstraints gbcTextField = new GridBagConstraints();
+ gbcTextField.insets = new Insets(0, 0, 5, 0);
+ gbcTextField.anchor = GridBagConstraints.WEST;
+ gbcTextField.gridx = 1;
+ gbcTextField.gridy = 1;
+ add(textField, gbcTextField);
+ textField.setColumns(10);
+
+ JPanel panel1 = new JPanel();
+ panel1.setBorder(new TitledBorder(null, "CalendarWidget", TitledBorder.LEADING, TitledBorder.TOP, null, null));
+ GridBagConstraints gbcPanel1 = new GridBagConstraints();
+ gbcPanel1.anchor = GridBagConstraints.NORTHWEST;
+ gbcPanel1.weighty = 1.0;
+ gbcPanel1.weightx = 1.0;
+ gbcPanel1.gridwidth = 2;
+ gbcPanel1.insets = new Insets(0, 0, 0, 5);
+ gbcPanel1.gridx = 0;
+ gbcPanel1.gridy = 2;
+ add(panel1, gbcPanel1);
+ GridBagLayout gblPanel1 = new GridBagLayout();
+ panel1.setLayout(gblPanel1);
+
+ CalendarWidget calendarWidget = new CalendarWidget();
+ calendarWidget.addPropertyChangeListener(CalendarWidget.DATE_PROPERTY, listener);
+ GridBagConstraints gbcCalendarWidget = new GridBagConstraints();
+ gbcCalendarWidget.anchor = GridBagConstraints.WEST;
+ gbcCalendarWidget.insets = new Insets(0, 0, 5, 0);
+ gbcCalendarWidget.gridwidth = 2;
+ gbcCalendarWidget.gridx = 0;
+ gbcCalendarWidget.gridy = 0;
+ panel1.add(calendarWidget, gbcCalendarWidget);
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/demo/DialogsPanel.java b/demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/DialogsPanel.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/demo/DialogsPanel.java
rename to demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/DialogsPanel.java
index d15f378..c99796b 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/demo/DialogsPanel.java
+++ b/demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/DialogsPanel.java
@@ -1,80 +1,80 @@
-package com.fathzer.soft.ajlib.swing.demo;
-
-import javax.swing.JPanel;
-import javax.swing.JButton;
-import javax.swing.JFileChooser;
-import javax.swing.JOptionPane;
-
-import com.fathzer.soft.ajlib.swing.Utils;
-import com.fathzer.soft.ajlib.swing.dialog.AbstractDialog;
-import com.fathzer.soft.ajlib.swing.dialog.FileChooser;
-import com.fathzer.soft.ajlib.swing.widget.HTMLPane;
-
-
-import java.awt.event.ActionListener;
-import java.io.File;
-import java.awt.event.ActionEvent;
-
-@SuppressWarnings("serial")
-public class DialogsPanel extends JPanel {
- private JButton btnOpenDialog;
- private JButton btnOpenDirectoryChooser;
-
- /**
- * Create the panel.
- */
- public DialogsPanel() {
- add(getBtnOpenDialog());
- add(getBtnOpenDirectoryChooser());
- }
-
- private JButton getBtnOpenDialog() {
- if (btnOpenDialog == null) {
- btnOpenDialog = new JButton("Open dialog");
- btnOpenDialog.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- AbstractDialog dialog = new AbstractDialog(Utils.getOwnerWindow(btnOpenDialog),"a very simple panel",null) {
- @Override
- protected JPanel createCenterPane() {
- JPanel panel = new JPanel();
- HTMLPane htmlPane = new HTMLPane("This is a very simple dialog, displaying a link." +
- "
You should override createCentePane and buildResult methods to create more complex dialogs.");
- panel.add(htmlPane);
- return panel;
- }
-
- @Override
- protected Boolean buildResult() {
- return Boolean.TRUE;
- }
- };
- dialog.setVisible(true);
- if (dialog.getResult()!=null) {
- AJLibDemo.setMessage("The dialog was validated");
- } else {
- AJLibDemo.setMessage("The dialog was cancelled");
- }
- }
- });
- }
- return btnOpenDialog;
- }
- private String path;
- private JButton getBtnOpenDirectoryChooser() {
- if (btnOpenDirectoryChooser == null) {
- btnOpenDirectoryChooser = new JButton("Open directory chooser");
- btnOpenDirectoryChooser.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- JFileChooser chooser = new FileChooser(path);
- chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- File file = chooser.showOpenDialog(DialogsPanel.this)==JFileChooser.APPROVE_OPTION ? chooser.getSelectedFile() : null;
- if (file!=null) {
- path = file.getPath();
- JOptionPane.showMessageDialog(DialogsPanel.this, "You selected "+path);
- }
- }
- });
- }
- return btnOpenDirectoryChooser;
- }
-}
+package com.fathzer.soft.ajlib.swing.demo;
+
+import javax.swing.JPanel;
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+
+import com.fathzer.soft.ajlib.swing.Utils;
+import com.fathzer.soft.ajlib.swing.dialog.AbstractDialog;
+import com.fathzer.soft.ajlib.swing.dialog.FileChooser;
+import com.fathzer.soft.ajlib.swing.widget.HTMLPane;
+
+
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.awt.event.ActionEvent;
+
+@SuppressWarnings("serial")
+public class DialogsPanel extends JPanel {
+ private JButton btnOpenDialog;
+ private JButton btnOpenDirectoryChooser;
+
+ /**
+ * Create the panel.
+ */
+ public DialogsPanel() {
+ add(getBtnOpenDialog());
+ add(getBtnOpenDirectoryChooser());
+ }
+
+ private JButton getBtnOpenDialog() {
+ if (btnOpenDialog == null) {
+ btnOpenDialog = new JButton("Open dialog");
+ btnOpenDialog.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ AbstractDialog dialog = new AbstractDialog(Utils.getOwnerWindow(btnOpenDialog),"a very simple panel",null) {
+ @Override
+ protected JPanel createCenterPane() {
+ JPanel panel = new JPanel();
+ HTMLPane htmlPane = new HTMLPane("This is a very simple dialog, displaying a link." +
+ "
You should override createCentePane and buildResult methods to create more complex dialogs.");
+ panel.add(htmlPane);
+ return panel;
+ }
+
+ @Override
+ protected Boolean buildResult() {
+ return Boolean.TRUE;
+ }
+ };
+ dialog.setVisible(true);
+ if (dialog.getResult()!=null) {
+ AJLibDemo.setMessage("The dialog was validated");
+ } else {
+ AJLibDemo.setMessage("The dialog was cancelled");
+ }
+ }
+ });
+ }
+ return btnOpenDialog;
+ }
+ private String path;
+ private JButton getBtnOpenDirectoryChooser() {
+ if (btnOpenDirectoryChooser == null) {
+ btnOpenDirectoryChooser = new JButton("Open directory chooser");
+ btnOpenDirectoryChooser.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ JFileChooser chooser = new FileChooser(path);
+ chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ File file = chooser.showOpenDialog(DialogsPanel.this)==JFileChooser.APPROVE_OPTION ? chooser.getSelectedFile() : null;
+ if (file!=null) {
+ path = file.getPath();
+ JOptionPane.showMessageDialog(DialogsPanel.this, "You selected "+path);
+ }
+ }
+ });
+ }
+ return btnOpenDirectoryChooser;
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/demo/RotatingLabelPanel.java b/demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/RotatingLabelPanel.java
similarity index 100%
rename from src/main/java/com/fathzer/soft/ajlib/swing/demo/RotatingLabelPanel.java
rename to demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/RotatingLabelPanel.java
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/demo/WidgetsDemoPanel.java b/demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/WidgetsDemoPanel.java
similarity index 97%
rename from src/main/java/com/fathzer/soft/ajlib/swing/demo/WidgetsDemoPanel.java
rename to demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/WidgetsDemoPanel.java
index 1d12688..8a35956 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/demo/WidgetsDemoPanel.java
+++ b/demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/WidgetsDemoPanel.java
@@ -1,190 +1,190 @@
-package com.fathzer.soft.ajlib.swing.demo;
-
-import javax.swing.JPanel;
-import javax.swing.JLabel;
-
-import com.fathzer.soft.ajlib.swing.widget.CurrencyWidget;
-import com.fathzer.soft.ajlib.swing.widget.NumberWidget;
-import com.fathzer.soft.ajlib.swing.widget.TextWidget;
-
-import java.awt.Color;
-import java.awt.GridBagLayout;
-import java.awt.GridBagConstraints;
-import java.awt.Insets;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.text.MessageFormat;
-import com.fathzer.soft.ajlib.swing.widget.PageSelector;
-
-
-public class WidgetsDemoPanel extends JPanel {
- private static final class DefaultPropertyChangeListener implements PropertyChangeListener {
- private String what;
- private DefaultPropertyChangeListener(String what) {
- this.what = what;
- }
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- String message;
- if (evt.getOldValue()==null) {
- message = MessageFormat.format("{0} is set to {1}", what, evt.getNewValue());
- } else if (evt.getNewValue()==null) {
- message = MessageFormat.format("{0} is wrong", what);
- } else {
- message = MessageFormat.format("{0} changed from {1} to {2}", what, evt.getOldValue(), evt.getNewValue());
- }
- AJLibDemo.setMessage(message);
- }
- }
- private static final long serialVersionUID = 1L;
- private JLabel lblTextwidget;
- private TextWidget textWidget;
- private JLabel lblNumberWidget;
- private NumberWidget numberWidget;
- private JLabel lblNewLabel;
- private CurrencyWidget currencyWidget;
- private PageSelector pageSelector;
- private JLabel lblNewLabel1;
-
- /**
- * Create the panel.
- */
- public WidgetsDemoPanel() {
-
- initialize();
- }
- private void initialize() {
- GridBagLayout gridBagLayout = new GridBagLayout();
- setLayout(gridBagLayout);
- GridBagConstraints gbcLblTextwidget = new GridBagConstraints();
- gbcLblTextwidget.fill = GridBagConstraints.BOTH;
- gbcLblTextwidget.insets = new Insets(0, 0, 5, 5);
- gbcLblTextwidget.gridx = 0;
- gbcLblTextwidget.gridy = 0;
- add(getLblTextwidget(), gbcLblTextwidget);
- GridBagConstraints gbcTextWidget = new GridBagConstraints();
- gbcTextWidget.fill = GridBagConstraints.HORIZONTAL;
- gbcTextWidget.insets = new Insets(0, 0, 5, 0);
- gbcTextWidget.gridx = 1;
- gbcTextWidget.gridy = 0;
- add(getTextWidget(), gbcTextWidget);
- GridBagConstraints gbcLblNumberWidget = new GridBagConstraints();
- gbcLblNumberWidget.anchor = GridBagConstraints.WEST;
- gbcLblNumberWidget.insets = new Insets(0, 0, 5, 5);
- gbcLblNumberWidget.gridx = 0;
- gbcLblNumberWidget.gridy = 1;
- add(getLblNumberWidget(), gbcLblNumberWidget);
- GridBagConstraints gbcNumberWidget = new GridBagConstraints();
- gbcNumberWidget.insets = new Insets(0, 0, 5, 0);
- gbcNumberWidget.weightx = 1.0;
- gbcNumberWidget.fill = GridBagConstraints.HORIZONTAL;
- gbcNumberWidget.gridx = 1;
- gbcNumberWidget.gridy = 1;
- add(getNumberWidget(), gbcNumberWidget);
- GridBagConstraints gbcLblNewLabel = new GridBagConstraints();
- gbcLblNewLabel.anchor = GridBagConstraints.WEST;
- gbcLblNewLabel.insets = new Insets(0, 0, 5, 5);
- gbcLblNewLabel.gridx = 0;
- gbcLblNewLabel.gridy = 2;
- add(getLblNewLabel(), gbcLblNewLabel);
- GridBagConstraints gbcCurrencyWidget = new GridBagConstraints();
- gbcCurrencyWidget.insets = new Insets(0, 0, 5, 0);
- gbcCurrencyWidget.fill = GridBagConstraints.HORIZONTAL;
- gbcCurrencyWidget.gridx = 1;
- gbcCurrencyWidget.gridy = 2;
- add(getCurrencyWidget(), gbcCurrencyWidget);
- GridBagConstraints gbcLblNewLabel1 = new GridBagConstraints();
- gbcLblNewLabel1.anchor = GridBagConstraints.WEST;
- gbcLblNewLabel1.insets = new Insets(0, 0, 0, 5);
- gbcLblNewLabel1.gridx = 0;
- gbcLblNewLabel1.gridy = 3;
- add(getLblNewLabel1(), gbcLblNewLabel1);
- GridBagConstraints gbcPageSelector = new GridBagConstraints();
- gbcPageSelector.anchor = GridBagConstraints.WEST;
- gbcPageSelector.gridx = 1;
- gbcPageSelector.gridy = 3;
- add(getPageSelector(), gbcPageSelector);
- }
-
- private JLabel getLblTextwidget() {
- if (lblTextwidget == null) {
- lblTextwidget = new JLabel("TextWidget:");
- }
- return lblTextwidget;
- }
- private TextWidget getTextWidget() {
- if (textWidget == null) {
- textWidget = new TextWidget(10);
- textWidget.setPredefined(new String[]{"dummy", "this string", "another one", "next one", "last one", "One more"}, 2);
- textWidget.addPropertyChangeListener(TextWidget.TEXT_PROPERTY, new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- AJLibDemo.setMessage("Text changed from "+evt.getOldValue()+" to "+evt.getNewValue());
- }
- });
- }
- return textWidget;
- }
- private JLabel getLblNumberWidget() {
- if (lblNumberWidget == null) {
- lblNumberWidget = new JLabel("Number widget:");
- }
- return lblNumberWidget;
- }
- private NumberWidget getNumberWidget() {
- if (numberWidget == null) {
- numberWidget = new NumberWidget();
- numberWidget.setToolTipText("This widget allows you to enter a double.");
- numberWidget.setColumns(10);
- numberWidget.addPropertyChangeListener(NumberWidget.VALUE_PROPERTY, new DefaultPropertyChangeListener("Number"));
- numberWidget.addPropertyChangeListener(NumberWidget.CONTENT_VALID_PROPERTY, new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- Color color = (Boolean) evt.getNewValue()?Color.WHITE:Color.RED;
- numberWidget.setBackground(color);
- }
- });
- }
- return numberWidget;
- }
- private JLabel getLblNewLabel() {
- if (lblNewLabel == null) {
- lblNewLabel = new JLabel("Currency Widget:");
- }
- return lblNewLabel;
- }
- private CurrencyWidget getCurrencyWidget() {
- if (currencyWidget == null) {
- currencyWidget = new CurrencyWidget();
- currencyWidget.setColumns(10);
- currencyWidget.addPropertyChangeListener(NumberWidget.VALUE_PROPERTY, new DefaultPropertyChangeListener("Amount"));
- currencyWidget.addPropertyChangeListener(NumberWidget.CONTENT_VALID_PROPERTY, new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- Color color = (Boolean) evt.getNewValue()?Color.WHITE:Color.RED;
- currencyWidget.setBackground(color);
- }
- });
- }
- return currencyWidget;
- }
- private PageSelector getPageSelector() {
- if (pageSelector == null) {
- pageSelector = new PageSelector();
- pageSelector.setPageCount(5);
- pageSelector.addPropertyChangeListener(PageSelector.PAGE_SELECTED_PROPERTY_NAME, new PropertyChangeListener() {
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- AJLibDemo.setMessage("Page set to "+evt.getNewValue());
- }
- });
- }
- return pageSelector;
- }
- private JLabel getLblNewLabel1() {
- if (lblNewLabel1 == null) {
- lblNewLabel1 = new JLabel("Page selector:");
- }
- return lblNewLabel1;
- }
-}
+package com.fathzer.soft.ajlib.swing.demo;
+
+import javax.swing.JPanel;
+import javax.swing.JLabel;
+
+import com.fathzer.soft.ajlib.swing.widget.CurrencyWidget;
+import com.fathzer.soft.ajlib.swing.widget.NumberWidget;
+import com.fathzer.soft.ajlib.swing.widget.TextWidget;
+
+import java.awt.Color;
+import java.awt.GridBagLayout;
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.text.MessageFormat;
+import com.fathzer.soft.ajlib.swing.widget.PageSelector;
+
+
+public class WidgetsDemoPanel extends JPanel {
+ private static final class DefaultPropertyChangeListener implements PropertyChangeListener {
+ private String what;
+ private DefaultPropertyChangeListener(String what) {
+ this.what = what;
+ }
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ String message;
+ if (evt.getOldValue()==null) {
+ message = MessageFormat.format("{0} is set to {1}", what, evt.getNewValue());
+ } else if (evt.getNewValue()==null) {
+ message = MessageFormat.format("{0} is wrong", what);
+ } else {
+ message = MessageFormat.format("{0} changed from {1} to {2}", what, evt.getOldValue(), evt.getNewValue());
+ }
+ AJLibDemo.setMessage(message);
+ }
+ }
+ private static final long serialVersionUID = 1L;
+ private JLabel lblTextwidget;
+ private TextWidget textWidget;
+ private JLabel lblNumberWidget;
+ private NumberWidget numberWidget;
+ private JLabel lblNewLabel;
+ private CurrencyWidget currencyWidget;
+ private PageSelector pageSelector;
+ private JLabel lblNewLabel1;
+
+ /**
+ * Create the panel.
+ */
+ public WidgetsDemoPanel() {
+
+ initialize();
+ }
+ private void initialize() {
+ GridBagLayout gridBagLayout = new GridBagLayout();
+ setLayout(gridBagLayout);
+ GridBagConstraints gbcLblTextwidget = new GridBagConstraints();
+ gbcLblTextwidget.fill = GridBagConstraints.BOTH;
+ gbcLblTextwidget.insets = new Insets(0, 0, 5, 5);
+ gbcLblTextwidget.gridx = 0;
+ gbcLblTextwidget.gridy = 0;
+ add(getLblTextwidget(), gbcLblTextwidget);
+ GridBagConstraints gbcTextWidget = new GridBagConstraints();
+ gbcTextWidget.fill = GridBagConstraints.HORIZONTAL;
+ gbcTextWidget.insets = new Insets(0, 0, 5, 0);
+ gbcTextWidget.gridx = 1;
+ gbcTextWidget.gridy = 0;
+ add(getTextWidget(), gbcTextWidget);
+ GridBagConstraints gbcLblNumberWidget = new GridBagConstraints();
+ gbcLblNumberWidget.anchor = GridBagConstraints.WEST;
+ gbcLblNumberWidget.insets = new Insets(0, 0, 5, 5);
+ gbcLblNumberWidget.gridx = 0;
+ gbcLblNumberWidget.gridy = 1;
+ add(getLblNumberWidget(), gbcLblNumberWidget);
+ GridBagConstraints gbcNumberWidget = new GridBagConstraints();
+ gbcNumberWidget.insets = new Insets(0, 0, 5, 0);
+ gbcNumberWidget.weightx = 1.0;
+ gbcNumberWidget.fill = GridBagConstraints.HORIZONTAL;
+ gbcNumberWidget.gridx = 1;
+ gbcNumberWidget.gridy = 1;
+ add(getNumberWidget(), gbcNumberWidget);
+ GridBagConstraints gbcLblNewLabel = new GridBagConstraints();
+ gbcLblNewLabel.anchor = GridBagConstraints.WEST;
+ gbcLblNewLabel.insets = new Insets(0, 0, 5, 5);
+ gbcLblNewLabel.gridx = 0;
+ gbcLblNewLabel.gridy = 2;
+ add(getLblNewLabel(), gbcLblNewLabel);
+ GridBagConstraints gbcCurrencyWidget = new GridBagConstraints();
+ gbcCurrencyWidget.insets = new Insets(0, 0, 5, 0);
+ gbcCurrencyWidget.fill = GridBagConstraints.HORIZONTAL;
+ gbcCurrencyWidget.gridx = 1;
+ gbcCurrencyWidget.gridy = 2;
+ add(getCurrencyWidget(), gbcCurrencyWidget);
+ GridBagConstraints gbcLblNewLabel1 = new GridBagConstraints();
+ gbcLblNewLabel1.anchor = GridBagConstraints.WEST;
+ gbcLblNewLabel1.insets = new Insets(0, 0, 0, 5);
+ gbcLblNewLabel1.gridx = 0;
+ gbcLblNewLabel1.gridy = 3;
+ add(getLblNewLabel1(), gbcLblNewLabel1);
+ GridBagConstraints gbcPageSelector = new GridBagConstraints();
+ gbcPageSelector.anchor = GridBagConstraints.WEST;
+ gbcPageSelector.gridx = 1;
+ gbcPageSelector.gridy = 3;
+ add(getPageSelector(), gbcPageSelector);
+ }
+
+ private JLabel getLblTextwidget() {
+ if (lblTextwidget == null) {
+ lblTextwidget = new JLabel("TextWidget:");
+ }
+ return lblTextwidget;
+ }
+ private TextWidget getTextWidget() {
+ if (textWidget == null) {
+ textWidget = new TextWidget(10);
+ textWidget.setPredefined(new String[]{"dummy", "this string", "another one", "next one", "last one", "One more"}, 2);
+ textWidget.addPropertyChangeListener(TextWidget.TEXT_PROPERTY, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ AJLibDemo.setMessage("Text changed from "+evt.getOldValue()+" to "+evt.getNewValue());
+ }
+ });
+ }
+ return textWidget;
+ }
+ private JLabel getLblNumberWidget() {
+ if (lblNumberWidget == null) {
+ lblNumberWidget = new JLabel("Number widget:");
+ }
+ return lblNumberWidget;
+ }
+ private NumberWidget getNumberWidget() {
+ if (numberWidget == null) {
+ numberWidget = new NumberWidget();
+ numberWidget.setToolTipText("This widget allows you to enter a double.");
+ numberWidget.setColumns(10);
+ numberWidget.addPropertyChangeListener(NumberWidget.VALUE_PROPERTY, new DefaultPropertyChangeListener("Number"));
+ numberWidget.addPropertyChangeListener(NumberWidget.CONTENT_VALID_PROPERTY, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ Color color = (Boolean) evt.getNewValue()?Color.WHITE:Color.RED;
+ numberWidget.setBackground(color);
+ }
+ });
+ }
+ return numberWidget;
+ }
+ private JLabel getLblNewLabel() {
+ if (lblNewLabel == null) {
+ lblNewLabel = new JLabel("Currency Widget:");
+ }
+ return lblNewLabel;
+ }
+ private CurrencyWidget getCurrencyWidget() {
+ if (currencyWidget == null) {
+ currencyWidget = new CurrencyWidget();
+ currencyWidget.setColumns(10);
+ currencyWidget.addPropertyChangeListener(NumberWidget.VALUE_PROPERTY, new DefaultPropertyChangeListener("Amount"));
+ currencyWidget.addPropertyChangeListener(NumberWidget.CONTENT_VALID_PROPERTY, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ Color color = (Boolean) evt.getNewValue()?Color.WHITE:Color.RED;
+ currencyWidget.setBackground(color);
+ }
+ });
+ }
+ return currencyWidget;
+ }
+ private PageSelector getPageSelector() {
+ if (pageSelector == null) {
+ pageSelector = new PageSelector();
+ pageSelector.setPageCount(5);
+ pageSelector.addPropertyChangeListener(PageSelector.PAGE_SELECTED_PROPERTY_NAME, new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ AJLibDemo.setMessage("Page set to "+evt.getNewValue());
+ }
+ });
+ }
+ return pageSelector;
+ }
+ private JLabel getLblNewLabel1() {
+ if (lblNewLabel1 == null) {
+ lblNewLabel1 = new JLabel("Page selector:");
+ }
+ return lblNewLabel1;
+ }
+}
diff --git a/src/main/java/com/fathzer/soft/ajlib/swing/demo/WorkerDemoPanel.java b/demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/WorkerDemoPanel.java
similarity index 96%
rename from src/main/java/com/fathzer/soft/ajlib/swing/demo/WorkerDemoPanel.java
rename to demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/WorkerDemoPanel.java
index 1c191d1..ee25fdf 100644
--- a/src/main/java/com/fathzer/soft/ajlib/swing/demo/WorkerDemoPanel.java
+++ b/demo/src/main/java/com/fathzer/soft/ajlib/swing/demo/WorkerDemoPanel.java
@@ -1,115 +1,115 @@
-package com.fathzer.soft.ajlib.swing.demo;
-
-import java.awt.Dialog.ModalityType;
-import java.awt.GridBagLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.JButton;
-import javax.swing.JPanel;
-
-import com.fathzer.soft.ajlib.swing.Utils;
-import com.fathzer.soft.ajlib.swing.worker.WorkInProgressFrame;
-import com.fathzer.soft.ajlib.swing.worker.Worker;
-
-import java.awt.GridBagConstraints;
-
-@SuppressWarnings("serial")
-public class WorkerDemoPanel extends JPanel {
- private JButton btnStartANew1;
-
- /**
- * Create the panel.
- */
- public WorkerDemoPanel() {
- initialize();
- }
-
- private void initialize() {
- setLayout(new GridBagLayout());
- JButton btnStartANew = getBtnStartANew();
- GridBagConstraints gbcBtnStartANew = new GridBagConstraints();
- gbcBtnStartANew.gridy = 0;
- gbcBtnStartANew.gridx = 0;
- add(btnStartANew, gbcBtnStartANew);
- GridBagConstraints gbcBtnStartANew1 = new GridBagConstraints();
- gbcBtnStartANew1.gridy = 1;
- gbcBtnStartANew1.gridx = 0;
- add(getBtnStartANew1(), gbcBtnStartANew1);
- }
-
- private static class WorkerSample extends Worker {
- private static int globalTaskNumber;
- private int taskNumber;
-
- WorkerSample() {
- this.taskNumber = ++globalTaskNumber;
- }
-
- @Override
- protected Void doProcessing() throws Exception {
- setPhase("A task may define phases", -1);
- for (int i=0;i<40;i++) {
- Thread.sleep(50);
- if (isCancelled()) {
- return null;
- }
- }
- setPhase("Some may not have a fixed length", -1);
- for (int i=0;i<30;i++) {
- Thread.sleep(50);
- if (isCancelled()) {
- return null;
- }
- }
- int nb = 30;
- setPhase("Other may have a defined length", nb);
- for (int i=0;i {
+ private static int globalTaskNumber;
+ private int taskNumber;
+
+ WorkerSample() {
+ this.taskNumber = ++globalTaskNumber;
+ }
+
+ @Override
+ protected Void doProcessing() throws Exception {
+ setPhase("A task may define phases", -1);
+ for (int i=0;i<40;i++) {
+ Thread.sleep(50);
+ if (isCancelled()) {
+ return null;
+ }
+ }
+ setPhase("Some may not have a fixed length", -1);
+ for (int i=0;i<30;i++) {
+ Thread.sleep(50);
+ if (isCancelled()) {
+ return null;
+ }
+ }
+ int nb = 30;
+ setPhase("Other may have a defined length", nb);
+ for (int i=0;iparent-pom
1.0.8
- ajlib
- 0.3.16
+ ajlib-parent-pom
+ 1.0.0
+ pom
- jar
-
- A-JLib
- A-Jlib is a simple java library with Swing widgets, utilities
- and other stuff
+ ajlib-parent
+ The parent pom used by ajlib.
https://github.com/fathzer/ajlib
https://github.com/fathzer/ajlib
- scm:git:git@github.com:fathzer/ajlib
+ https://github.com/fathzer/ajlib
UTF-8
- 1.23
java17
1.7
+ 1.23
-
+
release
@@ -42,23 +40,14 @@
sonar
- fathzer
+ fathzer
https://sonarcloud.io
-
+
+
-
- com.fathzer
- jlocal
- 1.0.0
-
-
- org.codehaus.mojo
- animal-sniffer-annotations
- ${animal-sniffer-version}
-
junit
junit
@@ -67,56 +56,17 @@
+
+ ajlib
+ demo
+
+
org.codehaus.mojo
animal-sniffer-maven-plugin
-
- maven-javadoc-plugin
- 2.10.3
-
- com.fathzer.soft.ajlib.swing.demo
-
-
-
- maven-jar-plugin
- 2.4
-
-
-
- true
- com.fathzer.soft.ajlib.swing.demo.AJLibDemo
-
-
-
- **/package.html
-
-
-
-
-
- maven-antrun-plugin
- 1.7
-
-
- install
-
-
-
-
-
-
-
-
-
- run
-
-
-
-