package org.nightlabs.jfire.pbx.ui; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; 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.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Table; import org.eclipse.ui.forms.editor.FormPage; import org.eclipse.ui.forms.widgets.ExpandableComposite; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import org.nightlabs.base.ui.composite.XComposite; import org.nightlabs.base.ui.editor.ToolBarSectionPart; import org.nightlabs.base.ui.job.Job; import org.nightlabs.base.ui.layout.WeightedTableLayout; import org.nightlabs.base.ui.table.AbstractTableComposite; import org.nightlabs.jfire.organisation.Organisation; import org.nightlabs.jfire.pbx.PhoneSystem; import org.nightlabs.jfire.pbx.ui.resource.Messages; import org.nightlabs.jfire.person.Person; import org.nightlabs.jfire.prop.Struct; import org.nightlabs.jfire.prop.StructBlock; import org.nightlabs.jfire.prop.StructField; import org.nightlabs.jfire.prop.StructLocal; import org.nightlabs.jfire.prop.dao.StructLocalDAO; import org.nightlabs.jfire.prop.id.StructLocalID; import org.nightlabs.jfire.prop.structfield.PhoneNumberStructField; import org.nightlabs.progress.ProgressMonitor; /** * @author Chairat Kongarayawetchakun <!-- chairat [AT] nightlabs [DOT] de --> */ public class PhoneSystemCallableFieldSection extends ToolBarSectionPart { private Button addButton; private Button removeButton; private Button addAllButton; private Button removeAllButton; private StructFieldTable availableStructFieldTable; private StructFieldTable callableStructFieldTable; public PhoneSystemCallableFieldSection(FormPage page, Composite parent) { super( page, parent, ExpandableComposite.EXPANDED | ExpandableComposite.TITLE_BAR | ExpandableComposite.TWISTIE | ExpandableComposite.TITLE_BAR, Messages.getString("org.nightlabs.jfire.pbx.ui.PhoneSystemCallableFieldSection.title")); //$NON-NLS-1$ createClient(getSection(), page.getEditor().getToolkit()); } private void createClient(Section section, FormToolkit toolkit) { section.setLayoutData(new GridData(GridData.FILL_BOTH)); section.setText(Messages.getString("org.nightlabs.jfire.pbx.ui.PhoneSystemCallableFieldSection.sectionText")); //$NON-NLS-1$ Composite container = getContainer();//EntityEditorUtil.createCompositeClient(toolkit, section, 1); GridLayout gridLayout = new GridLayout(3, false); container.setLayout(gridLayout); availableStructFieldTable = new StructFieldTable(container, SWT.NONE); availableStructFieldTable.setLayoutData(new GridData(GridData.FILL_BOTH)); availableStructFieldTable.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent e) { updateButtonStates(); } }); XComposite buttonComposite = new XComposite(container, SWT.NONE); buttonComposite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING)); addButton = new Button(buttonComposite, SWT.NONE); addButton.setText(Messages.getString("org.nightlabs.jfire.pbx.ui.PhoneSystemCallableFieldSection.addText")); //$NON-NLS-1$ GridData gridData = new GridData(GridData.FILL_HORIZONTAL); addButton.setLayoutData(gridData); addButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { addCallableField(false); updateButtonStates(); markDirty(); } }); removeButton = new Button(buttonComposite, SWT.NONE); removeButton.setText(Messages.getString("org.nightlabs.jfire.pbx.ui.PhoneSystemCallableFieldSection.removeText")); //$NON-NLS-1$ gridData = new GridData(GridData.FILL_HORIZONTAL); removeButton.setLayoutData(gridData); removeButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { removeCallableField(false); updateButtonStates(); markDirty(); } }); addAllButton = new Button(buttonComposite, SWT.NONE); addAllButton.setText(Messages.getString("org.nightlabs.jfire.pbx.ui.PhoneSystemCallableFieldSection.addAllText")); //$NON-NLS-1$ gridData = new GridData(GridData.FILL_HORIZONTAL); addAllButton.setLayoutData(gridData); addAllButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { addCallableField(true); updateButtonStates(); markDirty(); } }); removeAllButton = new Button(buttonComposite, SWT.NONE); removeAllButton.setText(Messages.getString("org.nightlabs.jfire.pbx.ui.PhoneSystemCallableFieldSection.removeAllText")); //$NON-NLS-1$ gridData = new GridData(GridData.FILL_HORIZONTAL); removeAllButton.setLayoutData(gridData); removeAllButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { removeCallableField(true); updateButtonStates(); markDirty(); } }); callableStructFieldTable = new StructFieldTable(container, SWT.NONE); callableStructFieldTable.setLayoutData(new GridData(GridData.FILL_BOTH)); callableStructFieldTable.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent e) { updateButtonStates(); } }); } @Override public boolean setFormInput(Object input) { if (Display.getCurrent() == null) throw new IllegalStateException("Thread mismatch! This method must always be called on the SWT UI thread!!!"); this.phoneSystem = (PhoneSystem) input; // createInput(phoneSystem); // WRONG here - must be in refresh! return super.setFormInput(input); } // private void createInput(final PhoneSystem phoneSystem) { // /*****Load data*****/ // StructLocalID personStructID = // StructLocalID.create(Organisation.DEV_ORGANISATION_ID, Person.class, Struct.DEFAULT_SCOPE, StructLocal.DEFAULT_SCOPE); // final StructLocal personStruct = // StructLocalDAO.sharedInstance().getStructLocal(personStructID, new NullProgressMonitor()); // TODO this should be done on a Job thread!!! It is blocking the UI!!!!! // // Display.getDefault().asyncExec(new Runnable() { // @Override // public void run() { // // @Chairat: This is nonsense. The whole point of the configuration is the not use any constant and thus be able to use *every* // // PhoneNumberDataField - not only the predefined ones. // // List<StructField<? extends DataField>> availableFields = personStruct.getStructBlock(PersonStruct.PHONE).getStructFields(); // List<PhoneNumberStructField> availableFields = new ArrayList<PhoneNumberStructField>(); // for (StructBlock structBlock : personStruct.getStructBlocks()) { // for (StructField<?> structField : structBlock.getStructFields()) { // if (structField instanceof PhoneNumberStructField) // availableFields.add((PhoneNumberStructField) structField); // } // } // // availableFields.removeAll(phoneSystem.getCallableStructFields()); // // availableStructFieldTable.setInput(availableFields); // callableStructFieldTable.setInput(phoneSystem.getCallableStructFields()); // // updateButtonStates(); // } // }); // } private void addCallableField(boolean isAll) { Collection<StructField> callableFields = callableStructFieldTable.getElements(); if (isAll) { callableFields.addAll(availableStructFieldTable.getElements()); } else { callableFields.addAll(availableStructFieldTable.getSelectedElements()); } Collection<StructField> availFields = availableStructFieldTable.getElements(); availFields.removeAll(callableFields); availableStructFieldTable.setInput(availFields); callableStructFieldTable.setInput(callableFields); } private void removeCallableField(boolean isAll) { Collection<StructField> availFields = availableStructFieldTable.getElements(); if (isAll) { availFields.addAll(callableStructFieldTable.getElements()); } else { availFields.addAll(callableStructFieldTable.getSelectedElements()); } Collection<StructField> callableFields = callableStructFieldTable.getElements(); callableFields.removeAll(availFields); availableStructFieldTable.setInput(availFields); callableStructFieldTable.setInput(callableFields); } private void updateButtonStates() { addButton.setEnabled(!availableStructFieldTable.getSelectedElements().isEmpty()); addAllButton.setEnabled(!availableStructFieldTable.getElements().isEmpty()); removeButton.setEnabled(!callableStructFieldTable.getSelectedElements().isEmpty()); removeAllButton.setEnabled(!callableStructFieldTable.getElements().isEmpty()); } private Job loadPersonStructJob; @Override public void refresh() { final Section section = getSection(); final Display display = section.getDisplay(); if (Display.getCurrent() != display) throw new IllegalStateException("Thread mismatch! This method must always be called on the SWT UI thread!!!"); availableStructFieldTable.setLoadingMessage("Loading..."); callableStructFieldTable.setLoadingMessage("Loading..."); Job job = new Job("Loading person structure") { @Override protected IStatus run(ProgressMonitor monitor) throws Exception { StructLocalID personStructID = StructLocalID.create( Organisation.DEV_ORGANISATION_ID, Person.class, Struct.DEFAULT_SCOPE, StructLocal.DEFAULT_SCOPE ); final StructLocal personStruct = StructLocalDAO.sharedInstance().getStructLocal(personStructID, monitor); // @Chairat: This is nonsense. The whole point of the configuration is the not use any constant and thus be able to use *every* // PhoneNumberDataField - not only the predefined ones. // List<StructField<? extends DataField>> availableFields = personStruct.getStructBlock(PersonStruct.PHONE).getStructFields(); final List<PhoneNumberStructField> availableFields = new ArrayList<PhoneNumberStructField>(); for (StructBlock structBlock : personStruct.getStructBlocks()) { for (StructField<?> structField : structBlock.getStructFields()) { if (structField instanceof PhoneNumberStructField) availableFields.add((PhoneNumberStructField) structField); } } final Job thisJob = this; display.asyncExec(new Runnable() { @Override public void run() { if (thisJob != loadPersonStructJob) return; if (phoneSystem == null) { availableStructFieldTable.setInput(null); callableStructFieldTable.setInput(null); return; } section.setEnabled(true); availableFields.removeAll(phoneSystem.getCallableStructFields()); availableStructFieldTable.setInput(availableFields); callableStructFieldTable.setInput(phoneSystem.getCallableStructFields()); updateButtonStates(); } }); return Status.OK_STATUS; } }; job.setPriority(Job.INTERACTIVE); loadPersonStructJob = job; section.setEnabled(false); job.schedule(); super.refresh(); } @Override public void commit(boolean onSave) { if (phoneSystem != null) { phoneSystem.removeCallableStructFields(availableStructFieldTable.getElements()); phoneSystem.addCallableStructFields(callableStructFieldTable.getElements()); } super.commit(onSave); } private PhoneSystem phoneSystem; public Collection<StructField> getCallableStructFields() { return callableStructFieldTable.getSelectedElements(); } } class StructFieldTable extends AbstractTableComposite<StructField> { public StructFieldTable(Composite parent, int style) { super(parent, style); setHeaderVisible(false); } @Override protected void createTableColumns(TableViewer tableViewer, final Table table) { TableViewerColumn viewerColumn = new TableViewerColumn(tableViewer, SWT.LEFT); table.setLayout(new WeightedTableLayout(new int[] { 1 })); } @Override public void refresh() { super.refresh(); } @Override protected void setTableProvider(TableViewer tableViewer) { tableViewer.setContentProvider(new ArrayContentProvider()); tableViewer.setLabelProvider(new LabelProvider() { @Override public String getText(Object element) { StructField structField = (StructField)element; return structField.getName().getText(); } }); } }