package org.nightlabs.jfire.trade.ui.detail; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.InflaterInputStream; import org.apache.log4j.Logger; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.ui.IMemento; import org.eclipse.ui.forms.widgets.Form; import org.eclipse.ui.forms.widgets.FormToolkit; import org.nightlabs.base.ui.composite.ReadOnlyLabeledText; import org.nightlabs.base.ui.composite.XComposite; import org.nightlabs.base.ui.job.Job; import org.nightlabs.jfire.store.ProductType; import org.nightlabs.jfire.store.id.ProductTypeID; import org.nightlabs.jfire.trade.ui.resource.Messages; import org.nightlabs.progress.ProgressMonitor; /** * This is the Composite which is used by the {@link SimpleProductTypeDetailView} * * @author Alexander Bieber <!-- alex [AT] nightlabs [DOT] de --> * */ public abstract class AbstractProductTypeDetailViewComposite extends XComposite { private static final String ATTR_NAME_WEIGHT_2 = "weight_2"; //$NON-NLS-1$ private static final String ATTR_NAME_WEIGHT_1 = "weight_1"; //$NON-NLS-1$ private static final String ATTR_NAME_SASH_ORIENTATION = "sashOrientation"; //$NON-NLS-1$ private static final int defaultImageHeight = 200; private static final int defaultImageWidth = 200; private Logger logger = Logger.getLogger(AbstractProductTypeDetailViewComposite.class); private Composite textWrapper; private ReadOnlyLabeledText productTypeName; private ReadOnlyLabeledText productTypeDescription; private XComposite imageWrapper; private Label imageLabel; private ImageData currImageData; public AbstractProductTypeDetailViewComposite(Composite parent, int style, LayoutMode layoutMode, LayoutDataMode layoutDataMode) { super(parent, style, layoutMode, layoutDataMode); createComposite(this); } public AbstractProductTypeDetailViewComposite(Composite parent, int style) { super(parent, style); createComposite(this); } public static final String[] FETCH_GROUP_PRODUCT_TYPE_DETAIL = new String[] { ProductType.FETCH_GROUP_NAME, ProductType.FETCH_GROUP_OWNER, ProductType.FETCH_GROUP_VENDOR, ProductType.FETCH_GROUP_PRODUCT_TYPE_GROUPS}; protected abstract ProductType fetchProductType(final ProductTypeID productTypeID, final ProgressMonitor monitor); protected abstract String fetchProductTypeName(final ProductType productType, final ProgressMonitor monitor); protected abstract String fetchProductTypeDescription(final ProductType productType, final ProgressMonitor monitor); protected abstract byte[] fetchProductTypeImage(final ProductType productType, final ProgressMonitor monitor); private volatile Job setProductTypeIDJob = null; public void setProductTypeID(final ProductTypeID productTypeID) { Job loadJob = new Job(Messages.getString("org.nightlabs.jfire.trade.ui.detail.AbstractProductTypeDetailViewComposite.loadProductTypeJob.name")) { //$NON-NLS-1$ @Override protected IStatus run(ProgressMonitor monitor) throws Exception { final ProductType productType = fetchProductType(productTypeID, monitor); final String name = fetchProductTypeName(productType, monitor); final String description = fetchProductTypeDescription(productType, monitor); final byte[] img = fetchProductTypeImage(productType, monitor); final Job thisJob = this; Display.getDefault().asyncExec(new Runnable() { public void run() { if (thisJob != setProductTypeIDJob) return; if (isDisposed()) return; productTypeName.setText(name); currImageData = null; if (img != null) { InputStream in = new InflaterInputStream(new ByteArrayInputStream(img)); try { currImageData = new ImageData(in); } finally { if (in != null) try { in.close(); } catch (IOException e) { logger.error("", e); //$NON-NLS-1$ } } } displayImage(); productTypeDescription.setText(description == null ? "" : description); //$NON-NLS-1$ } }); return Status.OK_STATUS; } }; setProductTypeIDJob = loadJob; loadJob.schedule(); } private SashForm sashForm; protected void createComposite(XComposite parent) { parent.getGridLayout().numColumns = 2; parent.getGridLayout().makeColumnsEqualWidth = false; FormToolkit toolkit = new FormToolkit(parent.getDisplay()); parent.setBackground(toolkit.getColors().getBackground()); Form form = toolkit.createForm(parent); // form.setText("Details"); // toolkit.decorateFormHeading(form); form.setLayoutData(new GridData(GridData.FILL_BOTH)); form.setLayout(new GridLayout()); Composite comp = form.getBody(); comp.setLayout(new GridLayout()); // sashForm = new SashForm(parent, SWT.HORIZONTAL); sashForm = new SashForm(comp, SWT.HORIZONTAL); sashForm.setLayout(new FillLayout()); sashForm.setLayoutData(new GridData(GridData.FILL_BOTH)); sashForm.setForeground(sashForm.getParent().getBackground()); sashForm.setBackground(sashForm.getParent().getBackground()); toolkit.adapt(sashForm); // textWrapper = new XComposite(sashForm, SWT.NONE, LayoutMode.TIGHT_WRAPPER); textWrapper = toolkit.createComposite(sashForm); textWrapper.setLayout(new GridLayout()); textWrapper.setLayoutData(new GridData(GridData.FILL_BOTH)); productTypeName = new ReadOnlyLabeledText(textWrapper, Messages.getString("org.nightlabs.jfire.trade.ui.detail.AbstractProductTypeDetailViewComposite.productTypeName.caption"), SWT.BORDER); // | SWT.READ_ONLY); //$NON-NLS-1$ productTypeDescription = new ReadOnlyLabeledText(textWrapper, Messages.getString("org.nightlabs.jfire.trade.ui.detail.AbstractProductTypeDetailViewComposite.productTypeDescription.caption"), SWT.BORDER); // | SWT.MULTI | SWT.READ_ONLY); //$NON-NLS-1$ productTypeDescription.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); productTypeDescription.getTextControl().setLayoutData(new GridData(GridData.FILL_BOTH)); imageWrapper = new XComposite(sashForm, SWT.NONE, LayoutMode.TIGHT_WRAPPER) { @Override public void layout(boolean arg0, boolean arg1) { layoutingImageWrapper = true; try { super.layout(arg0, arg1); displayImage(); } finally { layoutingImageWrapper = false; } } }; imageWrapper.adaptToToolkit(); imageWrapper.getGridData().grabExcessHorizontalSpace = false; imageWrapper.getGridData().heightHint = defaultImageHeight; imageWrapper.getGridData().widthHint = defaultImageWidth; imageLabel = new Label(imageWrapper, SWT.NONE); imageLabel.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { if (imageLabel.getImage() != null) imageLabel.getImage().dispose(); } }); imageWrapper.addControlListener(new ControlListener() { public void controlMoved(ControlEvent e) { } public void controlResized(ControlEvent e) { displayImage(); int orientation = (restoredOrientation != null && restoredWeights != null) ? restoredOrientation : sashForm.getOrientation(); if (getSize().x < 350 && orientation != SWT.VERTICAL) { setOrientation(SWT.VERTICAL); } if (getSize().x > 400 && orientation != SWT.HORIZONTAL) { setOrientation(SWT.HORIZONTAL); } } }); GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_CENTER | GridData.VERTICAL_ALIGN_CENTER); gd.grabExcessHorizontalSpace = true; gd.grabExcessVerticalSpace = true; imageLabel.setLayoutData(gd); sashForm.setWeights(new int[] {10, 10}); Display.getDefault().asyncExec(sash_setWeights_runnable); } private int sash_setWeights_counter = 0; private Runnable sash_setWeights_runnable = new Runnable() { public void run() { if (restoredOrientation != null && restoredWeights != null) { sashForm.setOrientation(restoredOrientation); sashForm.setWeights(restoredWeights); restoredOrientation = null; restoredWeights = null; return; } ++sash_setWeights_counter; int leftWeight = (100 * (getSize().x - defaultImageWidth) / getSize().x); // first multiply, then divide!!! otherwise the integer-divisions are most of the time 0 int rightWeight = (100 * defaultImageWidth / getSize().x); if (leftWeight > 0 && rightWeight > 0) { int[] weights = new int[] {leftWeight, rightWeight}; logger.info("Setting weights to " + weights[0] + ", " + weights[1]); //$NON-NLS-1$ //$NON-NLS-2$ sashForm.setWeights(weights); } else { logger.warn("Weights are out of range! leftWeight=" + leftWeight + " rightWeight=" + rightWeight); //$NON-NLS-1$ //$NON-NLS-2$ if (sash_setWeights_counter < 10) Display.getDefault().asyncExec(sash_setWeights_runnable); } } }; private boolean layoutingImageWrapper = false; private void displayImage() { if (imageLabel.getImage() != null) { imageLabel.getImage().dispose(); imageLabel.setImage(null); } if (currImageData == null) { if (!layoutingImageWrapper) imageWrapper.layout(true, true); return; } int width = currImageData.width; int height = currImageData.height; double factor = 1.0; int imgMaxWidth = defaultImageWidth - 5; int maxThumbnailHeight = imageWrapper.getSize().y; int maxThumbnailWidth = Math.min(Math.max(imageWrapper.getSize().x / 2, imgMaxWidth), imgMaxWidth); if (maxThumbnailWidth > imageWrapper.getSize().x) maxThumbnailWidth = imageWrapper.getSize().x; if (width > maxThumbnailWidth || height > maxThumbnailHeight) factor = Math.min( height > maxThumbnailHeight ? 1.0*maxThumbnailHeight/height : 1.0, width > maxThumbnailWidth ? 1.0*maxThumbnailWidth/width : 1.0 ); ImageData scaledData = currImageData.scaledTo((int) (factor*width), (int) (factor*height)); Image image = new Image(Display.getDefault(), scaledData); imageLabel.setImage(image); if (!layoutingImageWrapper) { imageLabel.getParent().layout(true, true); imageLabel.getParent().getParent().layout(true, true); } } public void setOrientation(int orientation) { sashForm.setOrientation(orientation); getDisplay().asyncExec(sash_setWeights_runnable); } public void saveState(IMemento memento) { int[] weights = sashForm.getWeights(); if (weights.length != 2) return; IMemento element = memento.createChild(this.getClass().getSimpleName()); element.putInteger(ATTR_NAME_SASH_ORIENTATION, sashForm.getOrientation()); logger.info("Storing weights to " + weights[0] + ", " + weights[1]); //$NON-NLS-1$ //$NON-NLS-2$ element.putInteger(ATTR_NAME_WEIGHT_1, weights[0]); element.putInteger(ATTR_NAME_WEIGHT_2, weights[1]); } private Integer restoredOrientation = null; private int[] restoredWeights = null; public void restoreState(IMemento memento) { IMemento element = memento.getChild(this.getClass().getSimpleName()); restoredOrientation = element.getInteger(ATTR_NAME_SASH_ORIENTATION); if (restoredOrientation != null) { Integer weight_1 = element.getInteger(ATTR_NAME_WEIGHT_1); Integer weight_2 = element.getInteger(ATTR_NAME_WEIGHT_2); if (weight_1 != null && weight_2 != null) { restoredWeights = new int[2]; restoredWeights[0] = weight_1; restoredWeights[1] = weight_2; } else { restoredOrientation = null; } } } }