/*
* Copyright 2009 Peter Karich.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* under the License.
*/
package de.timefinder.core.ui.form;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.swing.TextComponentMatcherEditor;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import de.timefinder.data.DBInterface;
import de.timefinder.data.Event;
import de.timefinder.data.Feature;
import de.timefinder.data.Location;
import de.timefinder.data.Person;
import de.timefinder.data.access.Dao;
import de.timefinder.core.springrc.MyAbstractTableMasterForm;
import de.timefinder.data.util.Helper;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.table.TableModel;
import org.springframework.binding.form.HierarchicalFormModel;
import org.springframework.binding.value.ValueModel;
import org.springframework.binding.value.support.ObservableList;
import org.springframework.richclient.command.AbstractCommand;
import org.springframework.richclient.command.ActionCommand;
import org.springframework.richclient.command.CommandGroup;
import org.springframework.richclient.dialog.ConfirmationDialog;
import org.springframework.richclient.form.AbstractDetailForm;
import org.springframework.richclient.form.FormModelHelper;
import org.springframework.richclient.table.support.GlazedTableModel;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* @author Peter Karich
*/
public class CollectionMasterDetailForm<T extends DBInterface>
extends MyAbstractTableMasterForm {
protected Dao<T> dao;
private String[] columns;
private JPanel filterPanel;
protected CommandGroup commandGroup;
public CollectionMasterDetailForm(Dao<T> dao, String[] columns) {
// connect the table to the getAll method of Dao<T>
super(FormModelHelper.createFormModel(dao), "all",
dao.getType().getSimpleName().toLowerCase(), dao.getType());
this.columns = columns;
this.dao = dao;
}
@Override
protected AbstractDetailForm createDetailForm(HierarchicalFormModel parentFormModel,
ValueModel valueHolder, ObservableList masterList) {
// now the details form:
Class clazz = dao.getType();
String str = clazz.getSimpleName().toLowerCase() + "Detail";
AbstractDaoForm objForm;
if (Person.class.equals(clazz)) {
throw new UnsupportedOperationException("will be handled in : " + PersonMasterDetailView.class);
} else if (Event.class.equals(clazz)) {
throw new UnsupportedOperationException("will be handled in : " + EventMasterDetailView.class);
} else if (Feature.class.equals(clazz)) {
objForm = new FeatureForm(parentFormModel, str, valueHolder, masterList);
} else if (Location.class.equals(clazz)) {
throw new UnsupportedOperationException("will be handled in : " + LocationMasterDetailView.class);
} else {
throw new UnsupportedOperationException("no Form was found for class: " + clazz);
}
objForm.setDao(dao);
return objForm;
}
@Override
protected void deleteSelectedItems() {
ListSelectionModel sm = getSelectionModel();
if (sm.isSelectionEmpty()) {
return;
}
int min = sm.getMinSelectionIndex();
int max = sm.getMaxSelectionIndex();
// Loop backwards and delete each selected item in the interval
for (int index = max; index >= min; index--) {
if (sm.isSelectedIndex(index)) {
// do not remove from list => propertyChange listener will do this
Object o = getMasterEventList().get(index);
dao.detach((T) o);
}
}
// do we need to hack? http://forum.springframework.org/showthread.php?t=68899
}
protected void cloneSelectedItems() {
ListSelectionModel sm = getSelectionModel();
if (sm.isSelectionEmpty()) {
return;
}
int min = sm.getMinSelectionIndex();
int max = sm.getMaxSelectionIndex();
// Loop backwards and delete each selected item in the interval
for (int index = max; index >= min; index--) {
if (sm.isSelectedIndex(index)) {
// do not remove from list => propertyChange listener will do this
Object o = getMasterEventList().get(index);
T obj = dao.create();
Helper.copyProperties(o, obj);
obj.setId(null);
dao.attach(obj);
}
}
// do we need to hack? http://forum.springframework.org/showthread.php?t=68899
}
@Override
protected void configure() {
super.configure();
final JTextField filterField = getComponentFactory().createTextField();
filterField.setToolTipText(getMessage("filter.label"));
JButton resetButton = new JButton(getIconSource().getIcon("resetButton")) {
@Override
public Insets getInsets() {
return new Insets(0, 0, 0, 0);
}
};
resetButton.setToolTipText(getMessage("resetButton.label"));
resetButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
filterField.setText("");
}
});
// http://www.jgoodies.com/articles/forms.pdf
FormLayout formLayout = new FormLayout(
"left:pref, pref, pref:grow, right:pref", // 3 columns
"pref"); // 1 row
CellConstraints cc = new CellConstraints();
filterPanel = getComponentFactory().createPanel(formLayout);
filterPanel.add(getComponentFactory().createLabel("filter.label"), cc.xy(1, 1));
filterPanel.add(resetButton, cc.xy(2, 1));
filterPanel.add(filterField, cc.xy(3, 1));
filterPanel.add(super.createButtonBar(), cc.xy(4, 1));
filterPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
setMatcherEditor(new TextComponentMatcherEditor<Object>(filterField,
GlazedLists.textFilterator(new String[]{"name"})));
}
@Override
public JComponent createNorthPanel() {
return filterPanel;
}
/**
* Create the table model for the master table.
* @return table model to install
*/
@Override
protected TableModel createTableModel() {
// if dao triggers additions then update eventList
dao.addListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
eventList.getReadWriteLock().writeLock().lock();
if (Dao.ATTACH.equals(evt.getPropertyName())) {
eventList.add(evt.getNewValue());
} else if (Dao.ATTACH_ALL.equals(evt.getPropertyName())) {
if (evt.getNewValue() instanceof Collection)
eventList.addAll((Collection) evt.getNewValue());
else
logger.fatal("evt.getNewValue() should be Collection but was:" + evt.getNewValue());
} else if (Dao.DETACH.equals(evt.getPropertyName())) {
eventList.remove(evt.getOldValue());
} else if (Dao.DETACH_ALL.equals(evt.getPropertyName())) {
eventList.clear();
if (evt.getNewValue() instanceof Collection)
eventList.addAll((Collection) evt.getNewValue());
else
logger.fatal("evt.getNewValue() should be Collection but was:" + evt.getNewValue());
}
eventList.getReadWriteLock().writeLock().unlock();
}
});
return new GlazedTableModel(eventList, getColumnPropertyNames(), getId()) {
@Override
protected boolean isEditable(Object row, int column) {
return false;
}
};
}
@Override
protected String[] getColumnPropertyNames() {
return columns;
}
public AbstractCommand getCloneFormObjectCommand() {
String commandId = getCloneFormObjectCommandId();
if (!StringUtils.hasText(commandId)) {
return null;
}
ActionCommand newDetailObjectCommand = new ActionCommand(commandId) {
protected void doExecuteCommand() {
maybeCloneObject(); // Avoid losing user edits
}
};
String scid = constructSecurityControllerId(commandId);
newDetailObjectCommand.setSecurityControllerId(scid);
return (ActionCommand) getCommandConfigurer().configure(newDetailObjectCommand);
}
private String getCloneFormObjectCommandId() {
return "clone" + StringUtils.capitalize(ClassUtils.getShortName(getDetailType() + "Command"));
}
private String getPrintFormObjectCommandId() {
return "print" + StringUtils.capitalize(ClassUtils.getShortName(getDetailType() + "Command"));
}
protected void maybeCloneObject() {
// nearly copied from maybeCreateNewObject();
if (getDetailForm().isEditingNewFormObject()) {
return; // Already creating a new object, just bail
}
if (getDetailForm().isDirty()) {
String title = getMessage(new String[]{getId() + ".dirtyNew.title", "masterForm.dirtyNew.title"});
String message = getMessage(new String[]{getId() + ".dirtyNew.message", "masterForm.dirtyNew.message"});
ConfirmationDialog dlg = new ConfirmationDialog(title, message) {
@Override
protected void onConfirm() {
cloneSelectedItems();
}
};
dlg.showDialog();
} else {
cloneSelectedItems();
}
}
public ActionCommand getPrintFormObjectCommand() {
String commandId = getPrintFormObjectCommandId();
if (!StringUtils.hasText(commandId)) {
return null;
}
ActionCommand printObjectCommand = new ActionCommand(commandId) {
@Override
protected void doExecuteCommand() {
Iterator<T> iter = new Iterator<T>() {
private ListSelectionModel sm = getSelectionModel();
private int max = sm.getMaxSelectionIndex();
private int index = sm.getMinSelectionIndex();
@Override
public boolean hasNext() {
if (sm.isSelectionEmpty())
return false;
for (; index <= max; index++) {
if (sm.isSelectedIndex(index))
return true;
}
return false;
}
@Override
public T next() {
if (hasNext())
return (T) getMasterEventList().get(index++);
throw new NoSuchElementException("No further elements were selected! Check this via hasNext before!");
}
@Override
public void remove() {
throw new UnsupportedOperationException("Not supported yet.");
}
};
printAction(iter);
}
};
String scid = constructSecurityControllerId(commandId);
printObjectCommand.setSecurityControllerId(scid);
return (ActionCommand) getCommandConfigurer().configure(printObjectCommand);
}
protected void printAction(Iterator<T> iter) {
}
@Override
protected CommandGroup getCommandGroup() {
if (commandGroup == null) {
// now include duplicate as well
commandGroup = CommandGroup.createCommandGroup(null, new AbstractCommand[]{
getPrintFormObjectCommand(), getDeleteCommand(),
getCloneFormObjectCommand(), getNewFormObjectCommand()});
}
return commandGroup;
}
}