[Schmitzm-commits] r2205 - in trunk/schmitzm-core/src/main: java java/de/schmitzm/lang java/de/schmitzm/swing java/de/schmitzm/swing/menu java/javax java/javax/swing resources/de/schmitzm/swing/resource/locales
scm-commit at wald.intevation.org
scm-commit at wald.intevation.org
Thu Jan 31 13:27:01 CET 2013
Author: mojays
Date: 2013-01-31 13:27:01 +0100 (Thu, 31 Jan 2013)
New Revision: 2205
Added:
trunk/schmitzm-core/src/main/java/de/schmitzm/swing/ListMaintainanceDialog.java
trunk/schmitzm-core/src/main/java/de/schmitzm/swing/ListMaintainancePanel.java
trunk/schmitzm-core/src/main/java/de/schmitzm/swing/menu/FavoritesMenu.java
trunk/schmitzm-core/src/main/java/javax/
trunk/schmitzm-core/src/main/java/javax/swing/
trunk/schmitzm-core/src/main/java/javax/swing/ReferencedListModel.java
Modified:
trunk/schmitzm-core/src/main/java/de/schmitzm/lang/ApplicationProps.java
trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle.properties
trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties
Log:
ApplicationProps: encryption/decryption swap to methods, new method setStringList(.)
new ListMaintainancePanel/Dialog: abstract components to edit/order a List<?>
new FavoritesMenu: generic JMenu to show varying number of favorite items
new ReferencedListModel: ListModel which data directly refers to an origin list
Modified: trunk/schmitzm-core/src/main/java/de/schmitzm/lang/ApplicationProps.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/lang/ApplicationProps.java 2013-01-31 08:18:32 UTC (rev 2204)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/lang/ApplicationProps.java 2013-01-31 12:27:01 UTC (rev 2205)
@@ -286,6 +286,19 @@
}
/**
+ * Decrypts a string value.
+ */
+ public String decrypt(String encryptedValue) {
+ if ( encryptCipher == null || decryptCipher == null )
+ throw new UnsupportedOperationException("getStringDecrypted(.) can not be used before a cipher is set.");
+ if ( encryptedValue == null )
+ return null;
+ byte[] encryptedBytes = CryptUtil.convertWritableStringToEncryptedBytes(encryptedValue);
+ String decryptedValue = CryptUtil.decryptString(encryptedBytes, getDecrytionCipher());
+ return decryptedValue;
+ }
+
+ /**
* Returns a property value which was stored encrypted in the map.
* @param key properties key
* @param defaultValueDecrypted default value (already decrypted!)
@@ -299,9 +312,7 @@
if ( encryptedValue == null )
return defaultValueDecrypted.length > 0 ? defaultValueDecrypted[0] : null;
try {
- byte[] encryptedBytes = CryptUtil.convertWritableStringToEncryptedBytes(encryptedValue);
- String decryptedValue = CryptUtil.decryptString(encryptedBytes, getDecrytionCipher());
- return decryptedValue;
+ return decrypt(encryptedValue);
} catch (Exception err) {
LOGGER.error("Error decrypting value '"+encryptedValue+"' for key '"+key+"' (NULL value returned): "+err.getMessage());
LOGGER.debug(err.getMessage(),err);
@@ -329,6 +340,24 @@
}
/**
+ * Encodes a list as semicolon-separated list
+ * and stores it in map
+ */
+ public <T> void setStringList(KEYS key, List<T> list) {
+ String listStr = "";
+
+ if ( list != null ) {
+ for (T v : list) {
+ String valueStr = v != null ? v.toString() : "";
+ if (!StringUtils.isBlank(listStr))
+ listStr += ";";
+ listStr += valueStr.trim();
+ }
+ }
+ set(key, listStr);
+ }
+
+ /**
* Encodes a map as semicolon-separated list of "key:value" pairs
* and stores it in map
*/
@@ -348,22 +377,12 @@
set(key, mapStr);
}
- /**
- * Set a value in the underlying {@link Properties}. The value
- * is encrypted by the encryption {@link Cipher}.
- * @see #setCipher(Cipher, Cipher)
- * @see #setCipher(byte[])
- * @see #setCipher(String)
- */
- public void setEncrypted(KEYS key, Object clearValue) {
+ public String encrypt(Object clearValue) {
if ( encryptCipher == null || decryptCipher == null )
throw new UnsupportedOperationException("setEncrypted(.) can not be used before a cipher is set.");
- // NULL can not be encrypted
- if ( clearValue == null ) {
- LOGGER.warn("NULL value for key '"+key+"' is stored not-encrypt!");
- set(key,clearValue);
- return;
- }
+ if ( clearValue == null )
+ return null;
+
// convert Byte[] to byte[]
if ( clearValue instanceof Byte[] ) {
Byte[] b = (Byte[])clearValue;
@@ -383,9 +402,29 @@
// properties.put(key.toString(), encryptBytes) forces
// a crash on store() because cast to String fails!
// Solution: store bytes concatenated
- set(key, CryptUtil.convertEncryptedBytesToWritableString(encryptBytes));
+ return CryptUtil.convertEncryptedBytesToWritableString(encryptBytes);
+
}
+ /**
+ * Set a value in the underlying {@link Properties}. The value
+ * is encrypted by the encryption {@link Cipher}.
+ * @see #setCipher(Cipher, Cipher)
+ * @see #setCipher(byte[])
+ * @see #setCipher(String)
+ */
+ public void setEncrypted(KEYS key, Object clearValue) {
+// if ( encryptCipher == null || decryptCipher == null )
+// throw new UnsupportedOperationException("setEncrypted(.) can not be used before a cipher is set.");
+ // NULL can not be encrypted
+ if ( clearValue == null ) {
+ LOGGER.warn("NULL value for key '"+key+"' is stored not-encrypt!");
+ set(key,clearValue);
+ return;
+ }
+ set(key, encrypt(clearValue));
+ }
+
/////////////////////////////////////////////////////
/////////////// Property storage //////////////////
/////////////////////////////////////////////////////
Added: trunk/schmitzm-core/src/main/java/de/schmitzm/swing/ListMaintainanceDialog.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/swing/ListMaintainanceDialog.java (rev 0)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/swing/ListMaintainanceDialog.java 2013-01-31 12:27:01 UTC (rev 2205)
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ *
+ * This file is part of the SCHMITZM library - a collection of utility
+ * classes based on Java 1.6, focusing (not only) on Java Swing
+ * and the Geotools library.
+ *
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ *
+ * This program 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.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Martin O. J. Schmitz - initial API and implementation
+ * Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Dialog;
+import java.awt.event.ActionEvent;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+
+/**
+ * Dialog to maintain list data.
+ * @author Martin O.J. Schmitz
+ *
+ */
+public abstract class ListMaintainanceDialog<T> extends OkCancelDialog {
+
+ protected ListMaintainancePanel<T> listPanel;
+ protected boolean orderable;
+
+ /**
+ * Creates a new dialog.
+ * @param owner parent frame
+ * @param title dialog title
+ * @param orderable indicates whether the element order should be maintained by
+ * the panel
+ */
+ public ListMaintainanceDialog(JFrame owner, String title, boolean orderable) {
+ super(owner, title, true, false);
+ this.orderable = orderable;
+ init();
+ }
+
+ /**
+ * Creates a new dialog.
+ * @param owner parent frame
+ * @param title dialog title
+ * @param orderable indicates whether the element order should be maintained by
+ * the panel
+ */
+ public ListMaintainanceDialog(Dialog owner, String title, boolean orderable) {
+ super(owner, title, true, false);
+ this.orderable = orderable;
+ init();
+ }
+
+ @Override
+ protected void init() {
+ super.init();
+
+ this.listPanel = new ListMaintainancePanel<T>(orderable) {
+ @Override
+ protected T createNewElement() {
+ return ListMaintainanceDialog.this.createNewElement();
+ }
+
+ @Override
+ protected T editElement(T element) {
+ return ListMaintainanceDialog.this.editElement(element);
+ }
+ };
+
+ getContentPane().add( listPanel, BorderLayout.CENTER );
+ pack();
+ SwingUtil.setRelativeFramePosition(this, getOwner(), 0.5, 0.5);
+ }
+
+ /**
+ * Creates a new element. Called by {@link ListMaintainancePanel#actionPerformed(ActionEvent)}.
+ */
+ protected abstract T createNewElement();
+
+ /**
+ * Edits an element. Called by {@link ListMaintainancePanel#actionPerformed(ActionEvent)}.
+ */
+ protected abstract T editElement(T element);
+
+ /**
+ * Returns the list panel. E.g. to edit the data from scratch.
+ */
+ public ListMaintainancePanel<T> getListPanel() {
+ return listPanel;
+ }
+
+}
Added: trunk/schmitzm-core/src/main/java/de/schmitzm/swing/ListMaintainancePanel.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/swing/ListMaintainancePanel.java (rev 0)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/swing/ListMaintainancePanel.java 2013-01-31 12:27:01 UTC (rev 2205)
@@ -0,0 +1,379 @@
+package de.schmitzm.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.swing.Action;
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JList;
+import javax.swing.JScrollPane;
+import javax.swing.ReferencedListModel;
+import javax.swing.event.ListDataListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import net.miginfocom.swing.MigLayout;
+
+/**
+ * Panel showing a {@link JList} which allows to modify the list.
+ * @author Martin O.J. Schmitz
+ */
+public abstract class ListMaintainancePanel<T> extends JPanel implements ActionListener, ListSelectionListener {
+ protected JList<T> list;
+
+ protected Action addAction;
+ protected Action removeAction;
+ protected Action editAction;
+ protected Action moveUpAction;
+ protected Action moveDownAction;
+
+ /**
+ * Creates a new list with actions to add, edit and remove elements.
+ * @param data initial data
+ * @param orderable indicates whether the element order should be maintained by
+ * the panel
+ */
+ public ListMaintainancePanel(boolean orderable) {
+ this(true, true, true, orderable, null);
+ }
+
+ /**
+ * Creates a new list.
+ * @param data initial data
+ * @param addAction indicates whether the elements can be added
+ * @param removeAction indicates whether the elements can be removed
+ * @param editAction indicates whether the elements can be edited/changed
+ * @param orderable indicates whether the element order should be maintained by
+ * the panel
+ */
+ public ListMaintainancePanel(boolean addAction, boolean removeAction, boolean editAction, boolean orderable) {
+ this(addAction, removeAction, editAction, orderable,null);
+ }
+
+ /**
+ * Creates a new list.
+ * @param data list data (if {@code null} an new empty {@link ArrayList} is created)
+ * @param orderable indicates whether the element order should be maintained by
+ * the panel
+ */
+ public ListMaintainancePanel(final boolean addAction, final boolean removeAction, final boolean editAction, final boolean orderable, List<T> data) {
+ super( new BorderLayout() );
+
+ list = new JList<T>( new ListModel<T>() );
+ list.addListSelectionListener(this);
+ list.addMouseListener( new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if ( e == null || !editAction )
+ return;
+ if ( e.getButton() == MouseEvent.BUTTON1 &&
+ e.getClickCount() == 2 )
+ performEditAction();
+ }
+ });
+
+ // Order actions
+ JPanel orderActionsPanel = new JPanel(new MigLayout("wrap 1","[]","[top][bottom]"));
+ if ( orderable ) {
+ this.moveUpAction = SwingUtil.createAction(SwingUtil.R("ListMaintainancePanel.action.moveUp"), this, "MOVE_UP", SwingUtil.R("ListMaintainancePanel.action.moveUp.desc"), SwingUtil.createImageIconFromResourcePath(SwingUtil.class, "resource/icons/small/arrow_up.png", null));
+ this.moveDownAction = SwingUtil.createAction(SwingUtil.R("ListMaintainancePanel.action.moveDown"), this, "MOVE_DOWN", SwingUtil.R("ListMaintainancePanel.action.moveDown.desc"), SwingUtil.createImageIconFromResourcePath(SwingUtil.class, "resource/icons/small/arrow_down.png", null));
+ orderActionsPanel.add(new JButton(this.moveUpAction));
+ orderActionsPanel.add(new JButton(this.moveDownAction));
+ }
+ // Edit actions
+ JPanel editActionsPanel = new JPanel(new MigLayout("wrap 1","[]","[top]"));
+ if ( addAction ) {
+ this.addAction = SwingUtil.createAction(SwingUtil.R("ListMaintainancePanel.action.add"), this, "ADD", SwingUtil.R("ListMaintainancePanel.action.add.desc"), SwingUtil.createImageIconFromResourcePath(SwingUtil.class, "resource/icons/small/add.png", null));
+ editActionsPanel.add(new JButton(this.addAction));
+ }
+ if ( editAction ) {
+ this.editAction = SwingUtil.createAction(SwingUtil.R("ListMaintainancePanel.action.edit"), this, "EDIT", SwingUtil.R("ListMaintainancePanel.action.edit.desc"), SwingUtil.createImageIconFromResourcePath(SwingUtil.class, "resource/icons/small/properties.png", null));
+ editActionsPanel.add(new JButton(this.editAction));
+ }
+ if ( removeAction ) {
+ this.removeAction = SwingUtil.createAction(SwingUtil.R("ListMaintainancePanel.action.remove"), this, "REMOVE", SwingUtil.R("ListMaintainancePanel.action.remove.desc"), SwingUtil.createImageIconFromResourcePath(SwingUtil.class, "resource/icons/small/cancel2.png", null));
+ editActionsPanel.add(new JButton(this.removeAction));
+ }
+ add(new JScrollPane(list), BorderLayout.CENTER);
+ if ( orderActionsPanel.getComponentCount() > 0 )
+ add(orderActionsPanel, BorderLayout.WEST);
+ if ( editActionsPanel.getComponentCount() > 0 )
+ add(editActionsPanel, BorderLayout.EAST);
+
+ for (Component c : orderActionsPanel.getComponents())
+ if ( c instanceof JButton ) {
+ ((JButton)c).setHideActionText(true);
+ SwingUtil.setMaximumWidth(c,20);
+ }
+ for (Component c : editActionsPanel.getComponents())
+ if ( c instanceof JButton ) {
+ ((JButton)c).setHideActionText(true);
+ SwingUtil.setMaximumWidth(c,30);
+ }
+
+ setData(data);
+ }
+
+ /**
+ * Returns the {@link JList}.
+ */
+ public JList<T> getList() {
+ return list;
+ }
+
+ /**
+ * Returns the data. Always returns a new {@link List} instance. Changes
+ * on this object does not effect the GUI!
+ */
+ public List<T> getData() {
+ return ((ListModel<T>)list.getModel()).getDataSource();
+ }
+
+ /**
+ * Sets the data of the list.
+ */
+ public void setData(List<T> data) {
+ ((ListModel<T>)list.getModel()).setDataSource(data);
+ }
+
+
+ /**
+ * Reacts on selection changes in lists with call of {@link #updateActions()}.
+ */
+ @Override
+ public void valueChanged(ListSelectionEvent e) {
+ updateActions();
+ }
+
+ /**
+ * Updates the enabled state of actions according to list selections.
+ */
+ protected void updateActions() {
+ boolean listSelected = list.getSelectedIndices().length > 0;
+ if ( editAction != null )
+ editAction.setEnabled( listSelected );
+ if ( removeAction != null )
+ removeAction.setEnabled( listSelected );
+ if ( moveUpAction != null )
+ moveUpAction.setEnabled( listSelected );
+ if ( moveDownAction != null )
+ moveDownAction.setEnabled( listSelected );
+ }
+
+ /**
+ * Adds a {@link ListDataListener} to the {@linkplain #list list}
+ * which is informed on each list change.
+ */
+ public void addListDataListener(ListDataListener l) {
+ list.getModel().addListDataListener(l);
+ }
+
+ /**
+ * Removes a {@link ListDataListener} from the {@linkplain #listlist}.
+ */
+ public void removeListDataListener(ListDataListener l) {
+ list.getModel().removeListDataListener(l);
+ }
+
+ /**
+ * Removes all list entries from list.
+ */
+ public void clearList() {
+ // remove all entries from field sequence
+ ((ListModel<T>)list.getModel()).removeAllElements();
+ }
+
+ /**
+ * Adds an element to the list.
+ */
+ public void addElement(int idx, T element) {
+ if ( idx >= 0 )
+ ((ListModel<T>)list.getModel()).insertElementAt(element,idx);
+ else
+ ((ListModel<T>)list.getModel()).addElement(element);
+ }
+
+ /**
+ * Adds an element to the end of the list.
+ */
+ public void addElement(T element) {
+ addElement(-1,element);
+ }
+
+ /**
+ * Removes an element from the list.
+ */
+ public void removeElement(T element) {
+ ((ListModel<T>)list.getModel()).removeElement(element);
+ }
+
+ /**
+ * Creates a new element. Called by {@link #actionPerformed(ActionEvent)}.
+ */
+ protected abstract T createNewElement();
+
+ /**
+ * Edits an element. Called by {@link #actionPerformed(ActionEvent)}.
+ */
+ protected abstract T editElement(T element);
+
+ /**
+ * Performs the button actions.
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String actionID = e.getActionCommand();
+
+ if ( "ADD".equals(actionID) ) {
+ T elem = createNewElement();
+ if ( elem != null )
+ addElement(elem);
+ }
+ if ( "EDIT".equals(actionID) ) {
+ performEditAction();
+ }
+ if ( "REMOVE".equals(actionID) ) {
+ for ( T elem : list.getSelectedValuesList() )
+ removeElement(elem);
+ }
+ if ( "MOVE_UP".equals(actionID) ) {
+ List<T> selectedValues = list.getSelectedValuesList();
+ int[] selectedIdx = list.getSelectedIndices();
+ int firstIdx = selectedIdx[0];
+ int lastIdx = selectedIdx[selectedIdx.length-1];
+ if ( firstIdx > 0 ) {
+ ((ListModel<T>)list.getModel()).removeRange(firstIdx, lastIdx);
+ ((ListModel<T>)list.getModel()).addElements(firstIdx-1, selectedValues);
+ list.addSelectionInterval(firstIdx-1, lastIdx-1);
+ }
+ }
+ if ( "MOVE_DOWN".equals(actionID) ) {
+ List<T> selectedValues = list.getSelectedValuesList();
+ int[] selectedIdx = list.getSelectedIndices();
+ int firstIdx = selectedIdx[0];
+ int lastIdx = selectedIdx[selectedIdx.length-1];
+ if ( lastIdx < ((ListModel<T>)list.getModel()).getSize()-1 ) {
+ ((ListModel<T>)list.getModel()).removeRange(firstIdx, lastIdx);
+ ((ListModel<T>)list.getModel()).addElements(firstIdx+1, selectedValues);
+ list.addSelectionInterval(firstIdx+1, lastIdx+1);
+ }
+ }
+
+ }
+
+ /**
+ * Invokes the edit action for the selected list item. Does nothing if
+ * edit action is not enabled or no list item is selected.
+ */
+ protected void performEditAction() {
+ if ( editAction == null )
+ return;
+ T elem = list.getSelectedValue();
+ if ( elem == null )
+ return;
+ // Edit action:
+ int elemIdx = list.getSelectedIndex();
+ elem = editElement(elem);
+ // set element
+ // --> not really necessary, but method fires update event!
+ if ( elem != null )
+ ((ListModel<T>)getList().getModel()).setElementAt(elem, elemIdx);
+ }
+
+ /**
+ * Data model for the {@link ListMaintainancePanel}.
+ * @author Martin O.J. Schmitz
+ */
+ protected class ListModel<T> extends ReferencedListModel<T> {
+ /**
+ * Creates empty list model.
+ */
+ public ListModel() {
+ this(null);
+ }
+
+
+ /**
+ * Creates list model and initializes the values.
+ */
+ public ListModel(List<T> list) {
+ super(list);
+ }
+
+
+ /**
+ * Removes elements from list.
+ */
+ public void removeElements(T[] elements) {
+ for (T f : elements)
+ removeElement(f);
+ }
+
+ /**
+ * Removes elements from list.
+ */
+ public void removeElements(Collection<T> elements) {
+ for (T f : elements)
+ removeElement(f);
+ }
+
+ /**
+ * Adds elements to bottom of the list.
+ */
+ public void addElements(T[] elements) {
+ addElements(getSize(), elements);
+ }
+
+ /**
+ * Inserts elements to bottom at specific list position.
+ */
+ public void addElements(int idx, T[] elements) {
+ if ( elements == null )
+ return;
+ for (T f : elements)
+ insertElementAt(f, idx++);
+ }
+
+ /**
+ * Adds elements to bottom of the list.
+ */
+ public void addElements(Collection<T> elements) {
+ addElements(0, elements);
+ }
+
+ /**
+ * Inserts elements to bottom at specific list position.
+ */
+ public void addElements(int idx, Collection<T> elements) {
+ if ( elements == null )
+ return;
+ for (T f : elements)
+ insertElementAt(f, idx++);
+ }
+
+ /**
+ * Initializes the list elements from given list.
+ */
+ public void setElements(T[] fields) {
+ removeAllElements();
+ addElements(fields);
+ }
+
+ /**
+ * Initializes the list elements from given list.
+ */
+ public void setElements(Collection<T> fields) {
+ removeAllElements();
+ addElements(fields);
+ }
+ }
+}
\ No newline at end of file
Added: trunk/schmitzm-core/src/main/java/de/schmitzm/swing/menu/FavoritesMenu.java
===================================================================
--- trunk/schmitzm-core/src/main/java/de/schmitzm/swing/menu/FavoritesMenu.java (rev 0)
+++ trunk/schmitzm-core/src/main/java/de/schmitzm/swing/menu/FavoritesMenu.java 2013-01-31 12:27:01 UTC (rev 2205)
@@ -0,0 +1,214 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ *
+ * This file is part of the SCHMITZM library - a collection of utility
+ * classes based on Java 1.6, focusing (not only) on Java Swing
+ * and the Geotools library.
+ *
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ *
+ * This program 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.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Martin O. J. Schmitz - initial API and implementation
+ * Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.swing.menu;
+
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+
+import de.schmitzm.swing.ButtonGroup;
+import de.schmitzm.swing.SwingUtil;
+
+/**
+ * {@link JMenu} to show a varying number of "Favorite" items. Additionally the
+ * menu contains an
+ * @author Martin O.J. Schmitz
+ *
+ */
+public class FavoritesMenu<F> extends JMenu {
+ /** {@link Action} command for "Maintain favorites" action (if no explicit
+ * action is specified in constructor) */
+ public static final String ACTION_CMD_MAINTAIN = "FAVORITES_MAINTAIN";
+ /** {@link Action} command for "Add favorite" action (if no explicit
+ * action is specified in constructor) */
+ public static final String ACTION_CMD_ADD = "FAVORITES_ADD";
+ /** {@link Action} command for "Remove favorite" action (this constant only
+ * defines a prefix. In {@link ActionEvent} the prefix will be followed by
+ * the favorite ID) */
+ public static final String ACTION_CMD_PREFIX_REMOVE = "FAVORITES_REMOVE_";
+ /** {@link Action} command for "Apply favorite" action (this constant only
+ * defines a prefix. In {@link ActionEvent} the prefix will be followed by
+ * the favorite ID) */
+ public static final String ACTION_CMD_PREFIX_APPLY = "FAVORITES_APPLY_";
+
+ /** Map key which is used to store the favorite object in the {@link Action} */
+ public static final String ACTION_KEY_FAVORITE = "FAVORITE";
+
+ private static final JMenuItem NO_FAVS_MENU_ITEM = new JMenuItem(SwingUtil.R("FavoritesMenu.empty"));
+ static {
+ NO_FAVS_MENU_ITEM.setEnabled(false);
+ NO_FAVS_MENU_ITEM.setFont( NO_FAVS_MENU_ITEM.getFont().deriveFont(Font.ITALIC) );
+ }
+
+ protected ActionListener actionListener = null;
+ protected Action addFavoriteAction = null;
+ protected Action maintainFavoritesAction = null;
+
+ protected Map<? extends Object, F> favorites = null;
+ protected Map<Object, Action> favoriteActionsByFavId = new HashMap<Object, Action>();
+ protected Map<F, Action> favoriteActionsByFav = new HashMap<F, Action>();
+
+ private ButtonGroup favsButtonGroup;
+
+ /**
+ * Creates a new menu.
+ * @param name menu title
+ * @param favorites map which contains the favorites (if this map's content changes
+ * {@link #initMenu(Map)} should be called to update the menu structure!)
+ * @param actionListener listener which is called for menu actions
+ */
+ public FavoritesMenu(String name, Map<Object,F> favorites, ActionListener actionListener) {
+ this(name,favorites,actionListener,null,null);
+ }
+
+
+ /**
+ * Creates a new menu.
+ * @param name menu title
+ * @param favorites map which contains the favorites (if this map's content changes
+ * {@link #initMenu(Map)} should be called to update the menu structure!)
+ * @param actionListener listener which is called for menu actions
+ * @param addFavoriteAction action used for "Add favorite" (if {@code null} a default action
+ * will be created, which also invokes the {@code actionListener})
+ * @param maintainFavoritesAction action used for "Maintain favorites" (if {@code null} a default action
+ * will be created, which also invokes the {@code actionListener})
+ */
+ public FavoritesMenu(String name, Map<?,F> favorites, ActionListener actionListener, Action addFavoriteAction, Action maintainFavoritesAction) {
+ super(name);
+ if ( addFavoriteAction == null )
+ addFavoriteAction = SwingUtil.createAction(SwingUtil.R("FavoritesMenu.add"), actionListener, ACTION_CMD_ADD, SwingUtil.R("FavoritesMenu.add.desc"), null);
+ if ( maintainFavoritesAction == null )
+ addFavoriteAction = SwingUtil.createAction(SwingUtil.R("FavoritesMenu.maintain"), actionListener, ACTION_CMD_MAINTAIN, SwingUtil.R("FavoritesMenu.maintain.desc"), null);
+
+ this.actionListener = actionListener;
+ this.addFavoriteAction = addFavoriteAction;
+ this.maintainFavoritesAction = maintainFavoritesAction;
+
+ initMenu(favorites);
+ }
+
+ /**
+ * Initializes the menu structure according to the current favorites map.
+ */
+ public void initMenu() {
+ initMenu( favorites );
+ }
+
+ /**
+ * Initializes the menu structure.
+ * @param favorites favorites to show in menu
+ */
+ public void initMenu(Map<? extends Object,F> favorites) {
+ if ( favorites == null )
+ favorites = new HashMap<Object,F>();
+
+ // remember selected favorite before clearing the maps and lists
+ F selectedFav = getSelectedFavorite();
+
+ removeAll();
+ this.favorites = favorites;
+ this.favoriteActionsByFav.clear();
+ this.favoriteActionsByFavId.clear();
+
+ add(addFavoriteAction);
+ addSeparator();
+ if ( favorites.size() > 0 ) {
+ favsButtonGroup = new ButtonGroup();
+ for (Object favID : favorites.keySet() ) {
+ F fav = favorites.get(favID);
+ // Create action to apply favorite
+ Action favApplyAction = SwingUtil.createAction(favID.toString(),
+ actionListener,
+ ACTION_CMD_PREFIX_APPLY+favID,
+ SwingUtil.R("FavoritesMenu.apply.desc"),
+ null);
+ favApplyAction.putValue(ACTION_KEY_FAVORITE, fav);
+ favoriteActionsByFavId.put(favID, favApplyAction);
+ favoriteActionsByFav.put(fav, favApplyAction);
+// // Create actions to remove favorite
+// Action favRemoveAction = SwingUtil.createAction("Remove favorite",
+// actionListener,
+// ACTION_CMD_PREFIX_REMOVE+favID,
+// "Remove favorites from list.",
+// null);
+ // Create menu item for favorite
+ JMenuItem favMenuItem = SwingUtil.createRadioMenuItem(favApplyAction, favsButtonGroup, fav == selectedFav);
+ add( favMenuItem );
+ }
+ } else {
+ add(NO_FAVS_MENU_ITEM);
+ }
+ addSeparator();
+ add(maintainFavoritesAction);
+ }
+
+ /**
+ * Returns the favorite object currently selected in the menu.
+ */
+ public F getSelectedFavorite() {
+ if ( favsButtonGroup == null ||
+ favsButtonGroup.getSelectedButton() == null ||
+ favsButtonGroup.getSelectedButton().getAction() == null )
+ return null;
+ Action favAction = favsButtonGroup.getSelectedButton().getAction();
+ return (F)favAction.getValue(ACTION_KEY_FAVORITE);
+// for (F fav : favorites.values()) {
+// Action favAction = favoriteActionsByFav.get(fav);
+// if ( Boolean.TRUE.equals(favAction.getValue(AbstractAction.SELECTED_KEY)) )
+// return fav;
+// }
+// return null;
+ }
+
+ /**
+ * Sets the favorite to be selected/applied in the menu.
+ */
+ public void setSelectedFavorite(F fav) {
+ Action favAction = favoriteActionsByFav.get(fav);
+ if ( favAction != null )
+ favAction.putValue(AbstractAction.SELECTED_KEY, true);
+ }
+
+ /**
+ * Sets the favorite to be selected/applied in the menu.
+ */
+ public void setSelectedFavoriteByID(Object favId) {
+ Action favAction = favoriteActionsByFavId.get(favId);
+ if ( favAction != null )
+ favAction.putValue(AbstractAction.SELECTED_KEY, true);
+ }
+}
Added: trunk/schmitzm-core/src/main/java/javax/swing/ReferencedListModel.java
===================================================================
--- trunk/schmitzm-core/src/main/java/javax/swing/ReferencedListModel.java (rev 0)
+++ trunk/schmitzm-core/src/main/java/javax/swing/ReferencedListModel.java 2013-01-31 12:27:01 UTC (rev 2205)
@@ -0,0 +1,386 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ *
+ * This file is part of the SCHMITZM library - a collection of utility
+ * classes based on Java 1.6, focusing (not only) on Java Swing
+ * and the Geotools library.
+ *
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ *
+ * This program 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.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ *
+ * Contributors:
+ * Martin O. J. Schmitz - initial API and implementation
+ * Stefan A. Tzeggai - additional utility classes
+ */
+package javax.swing;
+
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * This {@link ListModel} is a reduced version of {@link javax.swing.DefaultListModel}
+ * which uses a {@link List} as that the {@link #delegate} field (which contains the data).
+ * Furthermore the field is {@code protected} so that sub-classes can override the implementation.<br>
+ * <br>
+ * In contrast to {@link javax.swing.DefaultListModel} this model does not hold a copy
+ * of the list data, but changes an underlying {@link List} directly (to avoid unnecessary copy
+ * processes). However "external" inserts and deletes on the list data should be avoided because
+ * no corresponding events are fired!
+ * @author Martin O.J. Schmitz
+ *
+ */
+public class ReferencedListModel<E> extends AbstractListModel<E>
+{
+ /** Hold the list data. */
+ protected List<E> delegate;
+
+
+ /**
+ * Creates a new model with a new empty {@link Vector} as data source.
+ */
+ public ReferencedListModel() {
+ this(null);
+ }
+
+ /**
+ * Creates a new model.
+ */
+ public ReferencedListModel(List<E> data) {
+ super();
+ if ( data == null )
+ data = new Vector<E>();
+ this.delegate = data;
+ }
+
+ /**
+ * Resets the data source.
+ */
+ public void setDataSource(List<E> data) {
+ // first remove all elements (and fire event)
+ removeAllElements();
+ // redefine the data
+ if ( data == null )
+ data = new Vector<E>();
+ this.delegate = data;
+
+ int index = delegate.size()-1;
+ if (index >= 0) {
+ fireIntervalAdded(this, 0, index);
+ }
+ }
+
+ /**
+ * Returns the data source. Modifications of this list will be effect the
+ * model data, but not immediately the GUI because no events are fired!
+ */
+ public List<E> getDataSource() {
+ return delegate;
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // The following methods are copied from javax.swing.DefaultListModel //
+ // and only lightly modified to respect the List type of delegate ( //
+ // instead of Vector) //
+ ////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Returns the number of components in this list.
+ * <p>
+ * This method is identical to <code>size</code>, which implements the
+ * <code>List</code> interface defined in the 1.2 Collections framework.
+ * This method exists in conjunction with <code>setSize</code> so that
+ * <code>size</code> is identifiable as a JavaBean property.
+ *
+ * @return the number of components in this list
+ * @see #size()
+ */
+ public int getSize() {
+ return delegate.size();
+ }
+
+ /**
+ * Returns the component at the specified index.
+ * <blockquote>
+ * <b>Note:</b> Although this method is not deprecated, the preferred
+ * method to use is <code>get(int)</code>, which implements the
+ * <code>List</code> interface defined in the 1.2 Collections framework.
+ * </blockquote>
+ * @param index an index into this list
+ * @return the component at the specified index
+ * @exception ArrayIndexOutOfBoundsException if the <code>index</code>
+ * is negative or greater than the current size of this
+ * list
+ * @see #get(int)
+ */
+ public E getElementAt(int index) {
+ return delegate.get(index);
+ }
+
+ /**
+ * Returns the number of components in this list.
+ *
+ * @return the number of components in this list
+ * @see Vector#size()
+ */
+ public int size() {
+ return delegate.size();
+ }
+
+ /**
+ * Tests whether this list has any components.
+ *
+ * @return <code>true</code> if and only if this list has
+ * no components, that is, its size is zero;
+ * <code>false</code> otherwise
+ * @see Vector#isEmpty()
+ */
+ public boolean isEmpty() {
+ return delegate.isEmpty();
+ }
+
+ /**
+ * Tests whether the specified object is a component in this list.
+ *
+ * @param elem an object
+ * @return <code>true</code> if the specified object
+ * is the same as a component in this list
+ * @see Vector#contains(Object)
+ */
+ public boolean contains(Object elem) {
+ return delegate.contains(elem);
+ }
+
+ /**
+ * Searches for the first occurrence of <code>elem</code>.
+ *
+ * @param elem an object
+ * @return the index of the first occurrence of the argument in this
+ * list; returns <code>-1</code> if the object is not found
+ * @see Vector#indexOf(Object)
+ */
+ public int indexOf(Object elem) {
+ return delegate.indexOf(elem);
+ }
+
+ /**
+ * Returns the index of the last occurrence of <code>elem</code>.
+ *
+ * @param elem the desired component
+ * @return the index of the last occurrence of <code>elem</code>
+ * in the list; returns <code>-1</code> if the object is not found
+ * @see Vector#lastIndexOf(Object)
+ */
+ public int lastIndexOf(Object elem) {
+ return delegate.lastIndexOf(elem);
+ }
+
+ /**
+ * Returns the component at the specified index.
+ * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index
+ * is negative or not less than the size of the list.
+ * <blockquote>
+ * <b>Note:</b> Although this method is not deprecated, the preferred
+ * method to use is <code>get(int)</code>, which implements the
+ * <code>List</code> interface defined in the 1.2 Collections framework.
+ * </blockquote>
+ *
+ * @param index an index into this list
+ * @return the component at the specified index
+ * @see #get(int)
+ * @see Vector#elementAt(int)
+ */
+ public E elementAt(int index) {
+ return delegate.get(index);
+ }
+
+ /**
+ * Returns the first component of this list.
+ * Throws a <code>NoSuchElementException</code> if this
+ * vector has no components.
+ * @return the first component of this list
+ * @see Vector#firstElement()
+ */
+ public E firstElement() {
+ return delegate.get(0);
+ }
+
+ /**
+ * Returns the last component of the list.
+ * Throws a <code>NoSuchElementException</code> if this vector
+ * has no components.
+ *
+ * @return the last component of the list
+ * @see Vector#lastElement()
+ */
+ public E lastElement() {
+ return delegate.get( getSize()-1 );
+ }
+
+ /**
+ * Sets the component at the specified <code>index</code> of this
+ * list to be the specified element. The previous component at that
+ * position is discarded.
+ * <p>
+ * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index
+ * is invalid.
+ * <blockquote>
+ * <b>Note:</b> Although this method is not deprecated, the preferred
+ * method to use is <code>set(int,Object)</code>, which implements the
+ * <code>List</code> interface defined in the 1.2 Collections framework.
+ * </blockquote>
+ *
+ * @param element what the component is to be set to
+ * @param index the specified index
+ * @see #set(int,Object)
+ * @see Vector#setElementAt(Object,int)
+ */
+ public void setElementAt(E element, int index) {
+ delegate.set(index,element);
+ fireContentsChanged(this, index, index);
+ }
+
+ /**
+ * Deletes the component at the specified index.
+ * <p>
+ * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index
+ * is invalid.
+ * <blockquote>
+ * <b>Note:</b> Although this method is not deprecated, the preferred
+ * method to use is <code>remove(int)</code>, which implements the
+ * <code>List</code> interface defined in the 1.2 Collections framework.
+ * </blockquote>
+ *
+ * @param index the index of the object to remove
+ * @see #remove(int)
+ * @see Vector#removeElementAt(int)
+ */
+ public void removeElementAt(int index) {
+ delegate.remove(index);
+ fireIntervalRemoved(this, index, index);
+ }
+
+ /**
+ * Inserts the specified element as a component in this list at the
+ * specified <code>index</code>.
+ * <p>
+ * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index
+ * is invalid.
+ * <blockquote>
+ * <b>Note:</b> Although this method is not deprecated, the preferred
+ * method to use is <code>add(int,Object)</code>, which implements the
+ * <code>List</code> interface defined in the 1.2 Collections framework.
+ * </blockquote>
+ *
+ * @param element the component to insert
+ * @param index where to insert the new component
+ * @exception ArrayIndexOutOfBoundsException if the index was invalid
+ * @see #add(int,Object)
+ * @see Vector#insertElementAt(Object,int)
+ */
+ public void insertElementAt(E element, int index) {
+ delegate.add(index,element);
+ fireIntervalAdded(this, index, index);
+ }
+
+ /**
+ * Adds the specified component to the end of this list.
+ *
+ * @param element the component to be added
+ * @see Vector#addElement(Object)
+ */
+ public void addElement(E element) {
+ int index = delegate.size();
+ delegate.add(element);
+ fireIntervalAdded(this, index, index);
+ }
+
+ /**
+ * Removes the first (lowest-indexed) occurrence of the argument
+ * from this list.
+ *
+ * @param obj the component to be removed
+ * @return <code>true</code> if the argument was a component of this
+ * list; <code>false</code> otherwise
+ * @see Vector#removeElement(Object)
+ */
+ public boolean removeElement(Object obj) {
+ int index = indexOf(obj);
+ boolean rv = delegate.remove(obj);
+ if (index >= 0) {
+ fireIntervalRemoved(this, index, index);
+ }
+ return rv;
+ }
+
+
+ /**
+ * Removes all components from this list and sets its size to zero.
+ * <blockquote>
+ * <b>Note:</b> Although this method is not deprecated, the preferred
+ * method to use is <code>clear</code>, which implements the
+ * <code>List</code> interface defined in the 1.2 Collections framework.
+ * </blockquote>
+ *
+ * @see #clear()
+ * @see Vector#removeAllElements()
+ */
+ public void removeAllElements() {
+ int index1 = delegate.size()-1;
+ delegate.clear();
+ if (index1 >= 0) {
+ fireIntervalRemoved(this, 0, index1);
+ }
+ }
+
+
+ /**
+ * Deletes the components at the specified range of indexes.
+ * The removal is inclusive, so specifying a range of (1,5)
+ * removes the component at index 1 and the component at index 5,
+ * as well as all components in between.
+ * <p>
+ * Throws an <code>ArrayIndexOutOfBoundsException</code>
+ * if the index was invalid.
+ * Throws an <code>IllegalArgumentException</code> if
+ * <code>fromIndex > toIndex</code>.
+ *
+ * @param fromIndex the index of the lower end of the range
+ * @param toIndex the index of the upper end of the range
+ * @see #remove(int)
+ */
+ public void removeRange(int fromIndex, int toIndex) {
+ if (fromIndex > toIndex) {
+ throw new IllegalArgumentException("fromIndex must be <= toIndex");
+ }
+ for(int i = toIndex; i >= fromIndex; i--) {
+ delegate.remove(i);
+ }
+ fireIntervalRemoved(this, fromIndex, toIndex);
+ }
+
+ /**
+ * Returns a string that displays and identifies this
+ * object's properties.
+ *
+ * @return a String representation of this object
+ */
+ public String toString() {
+ return delegate.toString();
+ }
+}
+
Modified: trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle.properties
===================================================================
--- trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle.properties 2013-01-31 08:18:32 UTC (rev 2204)
+++ trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle.properties 2013-01-31 12:27:01 UTC (rev 2205)
@@ -319,4 +319,22 @@
POP3Settings.auth.pw=Password
DirectoryChooser.title=Choose directory
-DirectoryChooser.DirectoryRoot=Computer
\ No newline at end of file
+DirectoryChooser.DirectoryRoot=Computer
+
+FavoritesMenu.add=Add favorite
+FavoritesMenu.add.desc=Add a favorite to the favorites list
+FavoritesMenu.maintain=Maintain favorites
+FavoritesMenu.maintain.desc=Maintain the list of favorites
+FavoritesMenu.empty=No favorites defined yet
+FavoritesMenu.apply.desc=Apply favorite
+
+ListMaintainancePanel.action.add=<<<
+ListMaintainancePanel.action.add.desc=Add new list element
+ListMaintainancePanel.action.remove=>>>
+ListMaintainancePanel.action.remove.desc=Remove selected list elements
+ListMaintainancePanel.action.edit=Edit
+ListMaintainancePanel.action.edit.desc=Edit selected list element
+ListMaintainancePanel.action.moveUp=Up
+ListMaintainancePanel.action.moveUp.desc=Move selected elements up in list
+ListMaintainancePanel.action.moveDown=Dn
+ListMaintainancePanel.action.moveDown.desc=Move selected elements down in list
Modified: trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties
===================================================================
--- trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties 2013-01-31 08:18:32 UTC (rev 2204)
+++ trunk/schmitzm-core/src/main/resources/de/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties 2013-01-31 12:27:01 UTC (rev 2205)
@@ -292,4 +292,22 @@
POP3Settings.auth.pw=Passwort
DirectoryChooser.title=Choose directory
-DirectoryChooser.DirectoryRoot=Computer
\ No newline at end of file
+DirectoryChooser.DirectoryRoot=Computer
+
+FavoritesMenu.add=Favorit hinzufügen
+FavoritesMenu.add.desc=Fügt einen Favorit der Liste hinzu
+FavoritesMenu.maintain=Favoriten verwalten
+FavoritesMenu.maintain.desc=Verwalten der Favoriten-Liste
+FavoritesMenu.empty=Keine Favoriten definiert
+FavoritesMenu.apply.desc=Favorit anwenden
+
+ListMaintainancePanel.action.add=<<<
+ListMaintainancePanel.action.add.desc=Neues Listen-Element hinzufügen
+ListMaintainancePanel.action.remove=>>>
+ListMaintainancePanel.action.remove.desc=Ausgewählte Listen-Elemente entfernen
+ListMaintainancePanel.action.edit=Bearb.
+ListMaintainancePanel.action.edit.desc=Ausgwähltes Listen-Element bearbeiten
+ListMaintainancePanel.action.moveUp=Hoch
+ListMaintainancePanel.action.moveUp.desc=Ausgewählte Elemente in der Liste nach oben/vorne verschieben
+ListMaintainancePanel.action.moveDown=Runter
+ListMaintainancePanel.action.moveDown.desc=Ausgewählte Elemente in der Liste nach unten/hinten verschieben
More information about the Schmitzm-commits
mailing list