/******************************************************************************* * Copyright (c) 2007, 2014 compeople AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * compeople AG - initial API and implementation *******************************************************************************/ package org.eclipse.riena.internal.ui.ridgets.swt; import java.util.List; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Table; import org.eclipse.riena.core.util.ObjectUtils; import org.eclipse.riena.ui.ridgets.IMasterDetailsRidget; import org.eclipse.riena.ui.ridgets.ITableRidget; import org.eclipse.riena.ui.ridgets.swt.AbstractMasterDetailsRidget; import org.eclipse.riena.ui.swt.AbstractMasterDetailsComposite; import org.eclipse.riena.ui.swt.MasterDetailsComposite; /** * A ridget for the {@link MasterDetailsComposite}. */ public class MasterDetailsRidget extends AbstractMasterDetailsRidget implements IMasterDetailsRidget { private final DirtyDetailsChecker dirtyDetailsChecker; public MasterDetailsRidget() { super(); dirtyDetailsChecker = new DirtyDetailsChecker(); } @Override public MasterDetailsComposite getUIControl() { return (MasterDetailsComposite) super.getUIControl(); } @Override protected void checkUIControl(final Object uiControl) { super.checkUIControl(uiControl); checkType(uiControl, MasterDetailsComposite.class); } @Override protected void bindUIControl() { final MasterDetailsComposite control = getUIControl(); if (control != null) { final Table table = control.getTable(); table.addSelectionListener(dirtyDetailsChecker); } } @Override /** * Do not unbind detail ridgets here as this method is called after details ridgets are bound and before master is bound. * TODO This callback has to be renamed! */ protected void unbindUIControl() { final MasterDetailsComposite control = getUIControl(); if (control != null) { final Table table = control.getTable(); table.removeSelectionListener(dirtyDetailsChecker); } } @Override protected final void bindTableToModel(final IObservableList rowObservables, final Class<? extends Object> rowClass, final String[] columnPropertyNames, final String[] columnHeaders) { getTableRidget().bindToModel(rowObservables, rowClass, columnPropertyNames, columnHeaders); } @Override protected void configureTableRidget() { // unused } @Override protected final void setTableSelection(final Object value) { getTableRidget().setSelection(value); } @Override protected final Object getTableSelection() { final List<Object> selection = getTableRidget().getSelection(); return selection.isEmpty() ? null : selection.get(0); } @Override protected final IObservableValue getSelectionObservable() { return getTableRidget().getSingleSelectionObservable(); } @Override protected final void revealTableSelection() { getUIControl().getTable().showSelection(); } @Override protected final void clearTableSelection() { dirtyDetailsChecker.clearSavedSelection(); getTableRidget().clearSelection(); } // helping methods // //////////////// private ITableRidget getTableRidget() { return getRidget(ITableRidget.class, AbstractMasterDetailsComposite.BIND_ID_TABLE); } /** * Non API; public for testing only. */ @Override public void handleApply() { super.handleApply(); final Table table = getUIControl().getTable(); /* * Fix for bug 283694: if only one element is in the table, remove the * selection on apply, so it can be selected again for editing. */ if (table.getItemCount() == 1) { getTableRidget().clearSelection(); } else { table.select(table.getSelectionIndex()); } table.setFocus(); } @Override public void updateFromModel() { final Object oldSelection = getTableSelection(); super.updateFromModel(); final Object tableSelection = getTableSelection(); if (!ObjectUtils.equals(oldSelection, tableSelection)) { handleSelectionChange(tableSelection); } else if (tableSelection != null) { updateDetails(tableSelection); } if (dirtyDetailsChecker != null) { dirtyDetailsChecker.clearSavedSelection(); } } // helping classes // //////////////// /** * If the details area is dirty, it will ask for confirmation when changing * selection. * <p> * Implementation note: because of we are notified after the selection * change the listener will revert to the previous selection, if * confirmation is denied. This will <b>not</b> result in clearing the * details area. */ private final class DirtyDetailsChecker extends SelectionAdapter { private int oldIndex = -1; // single selection private Object oldSelection = new Object(); @Override public void widgetSelected(final SelectionEvent e) { final Object newSelection = e.item.getData(); final Table table = (Table) e.widget; if (oldIndex == table.getSelectionIndex() || oldSelection.equals(newSelection)) { // already selected return; } if (areDetailsChanged()) { if (!getUIControl().confirmDiscardChanges()) { table.setSelection(oldIndex); return; } } oldIndex = table.getSelectionIndex(); oldSelection = newSelection; handleSelectionChange(newSelection); } void clearSavedSelection() { oldIndex = -1; oldSelection = new Object(); } } }