package org.marketcetera.photon.views;
import java.io.InputStream;
import java.util.EnumSet;
import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.validation.MultiValidator;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.dialogs.PopupDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.marketcetera.client.OrderValidationException;
import org.marketcetera.client.instruments.OptionValidationHandler;
import org.marketcetera.core.ClassVersion;
import org.marketcetera.photon.PhotonPlugin;
import org.marketcetera.photon.commons.ui.databinding.DataBindingUtils;
import org.marketcetera.trade.OptionType;
/* $License$ */
/**
* This class implements the view that provides the end user the ability to type
* in--and graphically interact with--stock option orders.
*
* Additionally this class manages the stock and option market data that can be
* displayed along with the order ticket itself.
*
* @author gmiller
* @version $Id: OptionOrderTicketView.java 16154 2012-07-14 16:34:05Z colin $
* @since 1.0.0
*
*/
@ClassVersion("$Id: OptionOrderTicketView.java 16154 2012-07-14 16:34:05Z colin $")
public class OptionOrderTicketView extends
OrderTicketView<OptionOrderTicketModel, IOptionOrderTicket> {
public static final String ID = "org.marketcetera.photon.views.OptionOrderTicketView"; //$NON-NLS-1$
private ComboViewer mOptionTypeComboViewer;
private ComboViewer mOrderCapacityComboViewer;
private ComboViewer mOpenCloseComboViewer;
/**
* Constructor.
*/
public OptionOrderTicketView() {
super(IOptionOrderTicket.class, PhotonPlugin.getDefault()
.getOptionOrderTicketModel());
}
@Override
protected InputStream getXSWTResourceStream() {
return getClass().getResourceAsStream("/option_order_ticket.xswt"); //$NON-NLS-1$
}
@Override
protected String getNewOrderString() {
return Messages.OPTION_ORDER_TICKET_VIEW_NEW__HEADING.getText();
}
@Override
protected String getReplaceOrderString() {
return Messages.OPTION_ORDER_TICKET_VIEW_REPLACE__HEADING.getText();
}
@Override
protected void initViewers(IOptionOrderTicket ticket) {
super.initViewers(ticket);
/*
* Put or Call combo based on OptionType enum.
*/
mOptionTypeComboViewer = new ComboViewer(ticket.getPutOrCallCombo());
mOptionTypeComboViewer.setContentProvider(new ArrayContentProvider());
mOptionTypeComboViewer.setInput(EnumSet.complementOf(
EnumSet.of(OptionType.Unknown)).toArray());
/*
* Order capacity combo based on OrderCapacity enum.
*
* An extra blank entry is added since the field is optional.
*/
mOrderCapacityComboViewer = new ComboViewer(ticket
.getOrderCapacityCombo());
mOrderCapacityComboViewer
.setContentProvider(new ArrayContentProvider());
mOrderCapacityComboViewer.setInput(getModel()
.getValidOrderCapacityValues());
/*
* Open close combo based on PositionEffect enum.
*
* An extra blank entry is added since the field is optional.
*/
mOpenCloseComboViewer = new ComboViewer(ticket.getOpenCloseCombo());
mOpenCloseComboViewer.setContentProvider(new ArrayContentProvider());
mOpenCloseComboViewer.setInput(getModel()
.getValidPositionEffectValues());
}
@Override
protected void customizeWidgets(final IOptionOrderTicket ticket) {
super.customizeWidgets(ticket);
/*
* Update size of text fields since default will be small.
*/
updateSize(ticket.getOptionExpiryText(), 10);
updateSize(ticket.getStrikePriceText(), 10);
/*
* Customize text fields to auto select the text on focus to make it
* easy to change the value.
*/
selectOnFocus(ticket.getOptionExpiryText());
selectOnFocus(ticket.getStrikePriceText());
/*
* If the ticket has no errors, enter on these fields will trigger a
* send.
*/
addSendOrderListener(ticket.getOptionExpiryText());
addSendOrderListener(ticket.getStrikePriceText());
addSendOrderListener(ticket.getPutOrCallCombo());
addSendOrderListener(ticket.getOrderCapacityCombo());
addSendOrderListener(ticket.getOpenCloseCombo());
ticket.getSelectExpiryButton().addSelectionListener(
new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
PopupDialog d = new CalendarPopup(getSite().getShell());
d.open();
};
});
}
/**
* Gets the "default" OptionOrderTicketView, that is the first one returned
* by {@link IWorkbenchPage#findView(String)}
*
* @return the default OptionOrderTicketView
*/
public static OptionOrderTicketView getDefault() {
OptionOrderTicketView orderTicket = (OptionOrderTicketView) PlatformUI
.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.findView(OptionOrderTicketView.ID);
return orderTicket;
}
@Override
protected void bindMessage() {
super.bindMessage();
final DataBindingContext dbc = getDataBindingContext();
final OptionOrderTicketModel model = getModel();
final IOptionOrderTicket ticket = getXSWTView();
/*
* Expiry
*/
final IObservableValue target = SWTObservables.observeText(ticket
.getOptionExpiryText(), SWT.Modify);
Binding binding = dbc.bindValue(target, model.getOptionExpiry());
setRequired(binding, Messages.OPTION_ORDER_TICKET_VIEW_EXPIRY__LABEL
.getText());
MultiValidator expiryValidator = new MultiValidator() {
@Override
protected IStatus validate() {
String expiry = (String) target.getValue();
if (expiry == null || expiry.isEmpty()) {
/*
* Let required field support kick in.
*/
return ValidationStatus.ok();
}
try {
OptionValidationHandler.validateExpiryDate(expiry);
return ValidationStatus.ok();
} catch (OrderValidationException e) {
return ValidationStatus.error(e.getLocalizedMessage(), e);
}
}
};
DataBindingUtils.initControlDecorationSupportFor(expiryValidator,
SWT.BOTTOM | SWT.LEFT);
dbc.addValidationStatusProvider(expiryValidator);
enableForNewOrderOnly(ticket.getOptionExpiryText());
enableForNewOrderOnly(ticket.getSelectExpiryButton());
/*
* Strike
*/
bindRequiredDecimal(ticket.getStrikePriceText(),
model.getStrikePrice(),
Messages.OPTION_ORDER_TICKET_VIEW_STRIKE_PRICE__LABEL.getText());
enableForNewOrderOnly(ticket.getStrikePriceText());
/*
* Option type
*/
bindRequiredCombo(mOptionTypeComboViewer, model.getOptionType(),
Messages.OPTION_ORDER_TICKET_VIEW_OPTION_TYPE__LABEL.getText());
enableForNewOrderOnly(ticket.getPutOrCallCombo());
/*
* Order Capacity
*/
bindCombo(mOrderCapacityComboViewer, model.getOrderCapacity());
/*
* Open Close
*/
bindCombo(mOpenCloseComboViewer, model.getPositionEffect());
}
private class CalendarPopup extends PopupDialog {
private static final String DATE_FORMAT = "%04d%02d%02d"; //$NON-NLS-1$
public CalendarPopup(Shell shell) {
super(shell, SWT.ON_TOP, true, false, false, false, false, null,
null);
}
@Override
protected Point getDefaultLocation(Point initialSize) {
Button button = getXSWTView().getSelectExpiryButton();
Point location = getShell().getDisplay().map(button.getParent(),
null, button.getLocation());
Point size = button.getSize();
return new Point(location.x + size.x, location.y + size.y);
}
@Override
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
final DateTime calendar = new DateTime(composite, SWT.CALENDAR);
calendar.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
getXSWTView().getOptionExpiryText()
.setText(
String.format(DATE_FORMAT, calendar
.getYear(),
calendar.getMonth() + 1, calendar
.getDay()));
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
close();
}
});
return composite;
}
}
}