package org.nightlabs.jfire.reporting.ui.layout;
import java.util.Collection;
import javax.jdo.FetchPlan;
import javax.jdo.JDOHelper;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.nightlabs.base.ui.composite.XComposite;
import org.nightlabs.base.ui.job.Job;
import org.nightlabs.jfire.reporting.dao.ReportRegistryItemDAO;
import org.nightlabs.jfire.reporting.layout.ReportLayout;
import org.nightlabs.jfire.reporting.layout.ReportRegistryItem;
import org.nightlabs.jfire.reporting.layout.id.ReportRegistryItemID;
import org.nightlabs.jfire.reporting.ui.layout.ReportRegistryItemDialog.ISelectionVerifier;
import org.nightlabs.progress.ProgressMonitor;
import org.nightlabs.util.Util;
/**
* Composite that displays the name of a ReportLayout set by
* {@link #internalSetReportLayoutID(ReportRegistryItemID)} and lets the user choose another one
* from a dialog.
* <p>
* The Composite is capable of displaying a given Text above the widgets it uses to display the
* selected layout and bring up the selection dialog.
* </p>
* <p>
* The Composite implements {@link ISelectionProvider} and therefore is able to notify
* {@link ISelectionChangedListener}s of a change in the users choice of ReportLayout.
* </p>
*
* @author Alexander Bieber <!-- alex [AT] nightlabs [DOT] de -->
*
*/
public class ReportLayoutSelectionComposite extends XComposite implements ISelectionProvider {
private String caption;
private Text layoutNameText;
private ReportRegistryItemID reportLayoutID;
private ListenerList selectionChangedListeners = new ListenerList();
private boolean setReportLayoutIDFromOutside = false;
/**
* Creates a new {@link ReportLayoutSelectionComposite} with a default {@link LayoutDataMode} of
* {@link LayoutDataMode#GRID_DATA_HORIZONTAL}.
*
* @param parent The parent of the new Composite.
* @param style The style of the new Composite.
* @param caption The caption that should be displayed above the widgets of this Composite. If
* this is <code>null</code> or empty, no caption will be displayed.
*/
public ReportLayoutSelectionComposite(Composite parent, int style, String caption) {
super(parent, style, LayoutMode.TIGHT_WRAPPER, LayoutDataMode.GRID_DATA_HORIZONTAL);
this.caption = caption;
createContents();
}
/**
* Creates a new {@link ReportLayoutSelectionComposite}.
*
* @param parent The parent of the new Composite.
* @param style The style of the new Composite.
* @param layoutDataMode The {@link LayoutDataMode} of the new Composite.
* @param caption The caption that should be displayed above the widgets of this Composite. If
* this is <code>null</code> or empty, no caption will be displayed.
*/
public ReportLayoutSelectionComposite(Composite parent, int style, LayoutDataMode layoutDataMode, String caption) {
super(parent, style, LayoutMode.TIGHT_WRAPPER, layoutDataMode);
this.caption = caption;
createContents();
}
/**
* Creates the contents of this Composite (Text to show the layout name and the a button to bring up the selection-dialog).
*/
protected void createContents() {
getGridLayout().makeColumnsEqualWidth = false;
getGridLayout().numColumns = 2;
if (caption != null && !caption.isEmpty()) {
Label captionLabel = new Label(this, SWT.WRAP);
captionLabel.setText(caption);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = 2;
captionLabel.setLayoutData(gd);
}
layoutNameText = new Text(this, getBorderStyle());
layoutNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
layoutNameText.setEditable(false);
Button selectLayoutButton = new Button(this, SWT.PUSH);
selectLayoutButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Collection<ReportRegistryItemID> selectedItems = ReportRegistryItemDialog.openDialog(layoutNameText.getShell(),
new ISelectionVerifier() {
@Override
public boolean isSelectionValid(Collection<ReportRegistryItem> reportRegistryItems) {
if (reportRegistryItems.size() != 1)
return false;
ReportRegistryItem item = reportRegistryItems.iterator().next();
return (item instanceof ReportLayout) && !Util.equals(reportLayoutID, JDOHelper.getObjectId(item));
}
});
if (selectedItems != null && selectedItems.size() == 1) {
internalSetReportLayoutID(selectedItems.iterator().next());
}
}
});
selectLayoutButton.setText("...");
selectLayoutButton.setLayoutData(new GridData());
}
/**
* Set the ID of the ReportLayout this Composite displays. The id will be set immediately and a
* Job will be started that loads the name of the ReportLayout.
*
* @param reportLayoutID The ID of the ReportLayout to display.
*/
public void setReportLayoutID(final ReportRegistryItemID reportLayoutID) {
setReportLayoutIDFromOutside = true;
try {
internalSetReportLayoutID(reportLayoutID);
} finally {
setReportLayoutIDFromOutside = false;
}
}
/**
* Internal method to set the reportLayoutID. Does what
* {@link #setReportLayoutID(ReportRegistryItemID)} says.
*
* @param reportLayoutID The reportLaoyutID to set.
*/
protected void internalSetReportLayoutID(final ReportRegistryItemID reportLayoutID) {
layoutNameText.getDisplay().syncExec(new Runnable() {
public void run() {
layoutNameText.setText("Loading report layout name ...");
}
});
this.reportLayoutID = reportLayoutID;
Job loadNameJob = new Job("Loading ReportLayout name") {
@Override
protected IStatus run(ProgressMonitor monitor) throws Exception {
final ReportRegistryItem[] reportLayout = new ReportRegistryItem[1];
if (reportLayoutID != null) {
reportLayout[0] = ReportRegistryItemDAO.sharedInstance().getReportRegistryItem(reportLayoutID,
new String[] { FetchPlan.DEFAULT, ReportRegistryItem.FETCH_GROUP_NAME }, monitor);
}
layoutNameText.getDisplay().asyncExec(new Runnable() {
public void run() {
if (ReportLayoutSelectionComposite.this.reportLayoutID == reportLayoutID) {
if (reportLayout[0] != null)
layoutNameText.setText(reportLayout[0].getName().getText());
else
layoutNameText.setText("No report layout selected");
}
}
});
return Status.OK_STATUS;
}
};
loadNameJob.schedule();
if (!setReportLayoutIDFromOutside)
notifySelectionChangedListeners();
}
/**
* @return The currently displayed ReportLayout. This was either set by
* {@link #internalSetReportLayoutID(ReportRegistryItemID)} or selected by the user from the
* selection-dialog.
*/
public ReportRegistryItemID getReportLayoutID() {
return reportLayoutID;
}
/**
* {@inheritDoc}
*/
public void addSelectionChangedListener(ISelectionChangedListener listener) {
selectionChangedListeners.add(listener);
}
/**
* {@inheritDoc}
*/
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
selectionChangedListeners.remove(listener);
}
/**
* Notifies the {@link ISelectionChangedListener}s.
*/
private void notifySelectionChangedListeners() {
Object[] listeners = selectionChangedListeners.getListeners();
SelectionChangedEvent selectionChangedEvent = new SelectionChangedEvent(this, getSelection());
for (Object listener : listeners) {
if (listener instanceof ISelectionChangedListener) {
((ISelectionChangedListener) listener).selectionChanged(selectionChangedEvent);
}
}
}
/**
* {@inheritDoc}
* @return The selected ReportLayout-ID.
*/
@Override
public ISelection getSelection() {
if (reportLayoutID != null)
return new StructuredSelection(reportLayoutID);
else
return new StructuredSelection();
}
/**
* {@inheritDoc}
*/
@Override
public void setSelection(ISelection selection) {
if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
Object firstElement = ((IStructuredSelection) selection).getFirstElement();
if (firstElement instanceof ReportRegistryItemID)
setReportLayoutID((ReportRegistryItemID) firstElement);
else
setReportLayoutID(null);
} else {
setReportLayoutID(null);
}
}
}