/**
* Copyright (C) 2015 Valkyrie RCP
*
* 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.
*/
package org.valkyriercp.form.binding.swing;
import com.google.common.collect.Lists;
import org.valkyriercp.binding.form.FormModel;
import org.valkyriercp.command.support.AbstractCommand;
import org.valkyriercp.command.support.ActionCommand;
import org.valkyriercp.component.ComponentUtils;
import org.valkyriercp.component.Focussable;
import org.valkyriercp.dialog.ApplicationDialog;
import org.valkyriercp.dialog.TitledApplicationDialog;
import org.valkyriercp.form.AbstractForm;
import org.valkyriercp.form.binding.support.AbstractCRUDBinding;
import org.valkyriercp.util.CloneUtils;
import org.valkyriercp.widget.AbstractFocussableWidgetForm;
import org.valkyriercp.widget.table.TableDescription;
import org.valkyriercp.widget.table.TableWidget;
import org.valkyriercp.widget.table.glazedlists.GlazedListTableWidget;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
public abstract class AbstractGlazedListsBinding extends AbstractCRUDBinding
{
/**
* List on screen, has to be a cloned one to be able to detect differences.
*/
protected Object viewControllerObject;
/**
* Add mode: form is used to add an object.
*/
private static final int ADD_MODE = 1;
/**
* Edit mode: form is used to display and edit an object.
*/
private static final int EDIT_MODE = 2;
/**
* Edit mode: form is used to display and edit an object.
*/
private static final int DETAIL_MODE = 3;
/**
* Current mode of the form/dialog.
*/
protected int currentMode = ADD_MODE;
/**
* Table used to show the list.
*/
protected GlazedListTableWidget table;
/**
* Dialog used to add/create rowObjects.
*/
protected ApplicationDialog formDialog;
/**
* Form used to add/create rowObjects.
*/
protected AbstractForm form;
/**
* Id to configure the dialog.
*/
protected String dialogId;
/**
* Use the original sort order of the provided data
*/
protected boolean useOriginalSortOrder;
/**
* Form used to show rowObjects.
*/
private AbstractForm detailForm;
/**
* Dialog used to show rowObjects.
*/
private ApplicationDialog detailFormDialog;
/**
* Constructor.
*
* @param formModel formModel met de property.
* @param formPropertyPath pad naar de property.
*/
public AbstractGlazedListsBinding(FormModel formModel, String formPropertyPath)
{
this(formModel, formPropertyPath, false);
}
/**
* Constructor.
*
* @param formModel formModel met de property.
* @param formPropertyPath pad naar de property.
* @param useOriginalSortOrder gebruik de originele sorteervolgorde van de lijst
*/
public AbstractGlazedListsBinding(FormModel formModel, String formPropertyPath,
boolean useOriginalSortOrder)
{
super(formModel, formPropertyPath, null);
this.useOriginalSortOrder = useOriginalSortOrder;
}
@Override
protected final void valueModelChanged(Object newValue)
{
this.viewControllerObject = CloneUtils.getClone(newValue);
this.table.setRows(getList(this.viewControllerObject));
onValueModelChanged();
readOnlyChanged();
}
protected void onValueModelChanged()
{
}
protected final void listChanged()
{
controlValueChanged(CloneUtils.getClone(this.viewControllerObject));
this.table.setRows(getList(this.viewControllerObject));
}
@Override
protected JComponent doBindControl()
{
getTable();
JPanel editor = new JPanel(new BorderLayout())
{
private static final long serialVersionUID = 853322345395517384L;
@Override
public void setEnabled(boolean enable)
{
table.getTable().setEnabled(enable);
for (AbstractCommand command : getCommands())
{
command.setEnabled(false);
}
}
};
JTable tableComponent = table.getTable();
if (isEditSupported() && getEditCommand().isAuthorized())
{
tableComponent.addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() > 1 && SwingUtilities.isLeftMouseButton(e))
{
edit(table.getSelectedRows());
}
}
});
}
else if (isShowDetailSupported() && getDetailCommand().isAuthorized())
{
tableComponent.addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() > 1 && SwingUtilities.isLeftMouseButton(e))
{
showDetail(table.getSelectedRows());
}
}
});
}
editor.add(table.getComponent(), BorderLayout.CENTER);
java.util.List<AbstractCommand> commands = getCommands();
if ((commands != null) && (commands.size() > 0))
{
JPanel buttons = ComponentUtils.createIconButtonPanel(commands);
editor.add(buttons, BorderLayout.SOUTH);
}
valueModelChanged(getValue());
return editor;
}
protected TableWidget getTable()
{
if (table == null)
{
if (useOriginalSortOrder) {
this.table = new GlazedListTableWidget(null, getTableDescription(), null, isFilteringSupported());
}
else
this.table = new GlazedListTableWidget(null, getTableDescription(), isFilteringSupported());
}
return this.table;
}
public Object[] getSelection()
{
return this.table.getSelectedRows();
}
/**
* Enable/disable the commands on readOnly change or valueModelChange
*/
@Override
protected void readOnlyChanged()
{
for (AbstractCommand abstractCommand : getCommands())
{
if (isShowDetailSupported() && abstractCommand == getDetailCommand())
(abstractCommand).setEnabled(isEnabled());
else
(abstractCommand).setEnabled(isEnabled() && !isReadOnly());
}
}
@Override
protected void enabledChanged()
{
this.table.getTable().setEnabled(isEnabled());
readOnlyChanged();
}
@Override
protected AbstractCommand createAddCommand()
{
AbstractCommand addRow = new ActionCommand("addrow")
{
@Override
protected void doExecuteCommand()
{
add(viewControllerObject);
}
};
addRow.setSecurityControllerId(getAddCommandSecurityControllerId());
getApplicationConfig().commandConfigurer().configure(addRow);
return addRow;
}
/**
* Returns the securityControllerId for the add command. Default returns <code>null</code>, provide
* your own id to enable security.
*/
protected String getAddCommandSecurityControllerId()
{
return null;
}
@Override
protected AbstractCommand createRemoveCommand()
{
AbstractCommand removeRow = new ActionCommand("removerow")
{
@Override
protected void doExecuteCommand()
{
remove(viewControllerObject, table.getSelectedRows());
}
};
removeRow.setSecurityControllerId(getRemoveCommandSecurityControllerId());
getApplicationConfig().commandConfigurer().configure(removeRow);
return removeRow;
}
/**
* Returns the securityControllerId for the remove command. Default returns <code>null</code>, provide
* your own id to enable security.
*/
protected String getRemoveCommandSecurityControllerId()
{
return null;
}
@Override
protected AbstractCommand createDetailCommand()
{
AbstractCommand detail = new ActionCommand("detailrow")
{
@Override
protected void doExecuteCommand()
{
Object[] selection = table.getSelectedRows();
if (selection.length > 0)
showDetail(selection);
}
};
getApplicationConfig().commandConfigurer().configure(detail);
return detail;
}
@Override
protected AbstractCommand createEditCommand()
{
ActionCommand editRow = new ActionCommand("editrow")
{
@Override
protected void doExecuteCommand()
{
edit(table.getSelectedRows());
}
};
editRow.setSecurityControllerId(getEditCommandSecurityControllerId());
getApplicationConfig().commandConfigurer().configure(editRow);
return editRow;
}
/**
* Returns the securityControllerId for the remove command. Default returns <code>null</code>, provide
* your own id to enable security.
*/
protected String getEditCommandSecurityControllerId()
{
return null;
}
public void edit(Object[] rows)
{
if (rows != null)
{
currentMode = EDIT_MODE;
getOrCreateAddEditForm();
for (Object row : rows)
{
form.setFormObject(row);
getOrCreateFormDialog().showDialog();
}
}
}
protected void add(Object list)
{
this.currentMode = ADD_MODE;
getOrCreateAddEditForm().setFormObject(getNewFormObject());
getOrCreateFormDialog().showDialog();
}
protected void remove(Object list, Object[] selection)
{
if (list instanceof Collection)
{
if (selection.length > 0)
{
((Collection) list).removeAll(Arrays.asList(selection));
listChanged();
}
}
else
throw new UnsupportedOperationException();
}
public void showDetail(Object[] rows)
{
if (rows != null)
{
getOrCreateDetailForm();
for (Object row : rows)
{
detailForm.setFormObject(row);
getOrCreateDetailFormDialog().showDialog();
}
}
}
protected AbstractForm getOrCreateAddEditForm()
{
if (this.form == null)
this.form = createAddEditForm();
return this.form;
}
protected AbstractForm getOrCreateDetailForm()
{
if (this.detailForm == null)
this.detailForm = createDetailForm();
return this.form;
}
protected AbstractForm createDetailForm()
{
throw new UnsupportedOperationException("Need a Form for adding/editing");
}
protected AbstractForm createAddEditForm()
{
throw new UnsupportedOperationException("Need a Form for adding/editing");
}
protected abstract TableDescription getTableDescription();
protected Collection getList(Object value)
{
if (value instanceof Collection)
{
return (Collection) value;
}
else if (value == null)
{
return Collections.emptyList();
}
else
{
throw new IllegalArgumentException("getList 's argument is not a Collection: " + value.getClass());
}
}
protected Object getNewFormObject()
{
return null;
}
public void setDialogId(String dialogId)
{
this.dialogId = dialogId;
}
public String getDialogId()
{
if (dialogId == null)
return "listBindingDialog";
return dialogId;
}
private ApplicationDialog getOrCreateFormDialog()
{
if (this.formDialog == null)
{
this.formDialog = createFormDialog();
this.formDialog.setParentComponent(table.getComponent());
getApplicationConfig().applicationObjectConfigurer().configure(this.formDialog, getDialogId());
}
return this.formDialog;
}
private ApplicationDialog getOrCreateDetailFormDialog()
{
if (this.detailFormDialog == null)
{
this.detailFormDialog = createDetailFormDialog();
this.detailFormDialog.setParentComponent(table.getComponent());
getApplicationConfig().applicationObjectConfigurer().configure(this.detailFormDialog, getDialogId());
}
return this.detailFormDialog;
}
private ApplicationDialog createDetailFormDialog()
{
return new TitledApplicationDialog()
{
protected ArrayList<AbstractCommand> getCommandGroupMembers()
{
return Lists.<AbstractCommand>newArrayList(getFinishCommand());
}
@Override
protected JComponent createTitledDialogContentPane()
{
return detailForm.getControl();
}
@Override
public void setTitle(String title)
{
super.setTitle(title);
setTitlePaneTitle(title);
}
protected boolean onFinish()
{
return true;
}
};
}
private ApplicationDialog createFormDialog()
{
return new TitledApplicationDialog()
{
@Override
protected JComponent createTitledDialogContentPane()
{
form.newSingleLineResultsReporter(this);
form.addGuarded(this);
return form.getControl();
}
@Override
public void setTitle(String title)
{
super.setTitle(title);
setTitlePaneTitle(title);
}
@Override
protected void onAboutToShow()
{
form.getFormModel().validate();
if (form instanceof Focussable)
((AbstractFocussableWidgetForm) form).grabFocus();
}
@Override
protected boolean onFinish()
{
if (form.hasErrors())
return false;
form.commit();
final Object formObject;
if (currentMode == ADD_MODE)
formObject = onFinishAdd(viewControllerObject, form.getFormObject());
else
formObject = onFinishEdit(viewControllerObject, form.getFormObject());
if (formObject != null)
{
listChanged();
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
getTable().selectRowObject(formObject, null);
}
});
}
return formObject != null;
}
};
}
protected Object onFinishAdd(Object list, Object newItem)
{
if (list instanceof Collection)
{
((Collection) list).add(newItem);
return newItem;
}
throw new UnsupportedOperationException(
"onFinishAdd received a non Collection object, needs alternate implementation");
}
protected Object onFinishEdit(Object list, Object newItem)
{
return newItem;
}
}