blob: 3fcdace2cfa410b92447fa86cb9c3bfa4e21e381 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Jeanderson Candido <http://jeandersonbc.github.io> - Bug 433603
*******************************************************************************/
package org.eclipse.ui.tests.manual;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.core.databinding.observable.map.ComputedObservableMap;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.databinding.observable.value.ComputedValue;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.IValueChangeListener;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.internal.databinding.provisional.swt.ControlUpdater;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.ISaveablePart;
import org.eclipse.ui.ISaveablesLifecycleListener;
import org.eclipse.ui.ISaveablesSource;
import org.eclipse.ui.Saveable;
import org.eclipse.ui.SaveablesLifecycleEvent;
import org.eclipse.ui.part.ViewPart;
public class ViewWithSaveables extends ViewPart implements ISaveablesSource,
ISaveablePart {
WritableList<Saveable> saveables = new WritableList<>();
IObservableValue<?> dirty = new ComputedValue<Object>() {
@Override
protected Object calculate() {
for (Object obj : saveables) {
MySaveable saveable = (MySaveable) obj;
if (saveable.isDirty()) {
return Boolean.TRUE;
}
}
return Boolean.FALSE;
}
};
private TableViewer viewer;
private IObservableValue<?> selection;
public ViewWithSaveables() {
}
@Override
public void createPartControl(Composite parent) {
viewer = new TableViewer(parent, SWT.BORDER);
GridDataFactory.fillDefaults().grab(true, true).span(4, 1)
.applyTo(viewer.getControl());
ObservableListContentProvider observableListContentProvider = new ObservableListContentProvider();
viewer.setContentProvider(observableListContentProvider);
viewer.setLabelProvider(new ObservableMapLabelProvider(
new DirtyObservableMap(observableListContentProvider
.getKnownElements())) {
@Override
public String getColumnText(Object element, int columnIndex) {
return getText(element);
}
@Override
public String getText(Object element) {
MySaveable saveable = (MySaveable) element;
return (saveable.isDirty() ? "*" : "") + saveable.toString();
}
});
viewer.setInput(saveables);
{
Button button = new Button(parent, SWT.PUSH);
button.setText("Add");
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
addSaveable();
}
});
}
selection = ViewersObservables.observeSingleSelection(viewer);
{
final Button button = new Button(parent, SWT.PUSH);
button.setText("Remove");
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
removeSaveable();
}
});
new ControlUpdater(button) {
@Override
protected void updateControl() {
button.setEnabled(selection.getValue() != null);
}
};
}
final Button button = new Button(parent, SWT.CHECK);
button.setText("dirty");
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
MySaveable saveable = (MySaveable) selection.getValue();
saveable.setDirty(button.getSelection());
}
});
new ControlUpdater(button) {
@Override
protected void updateControl() {
MySaveable saveable = (MySaveable) selection.getValue();
if (saveable == null) {
button.setEnabled(false);
button.setSelection(false);
} else {
button.setEnabled(true);
// we know that isDirty is implemented using a
// WritableValue,
// and thus a dependency on that writable value will
// result from
// calling isDirty().
button.setSelection(saveable.isDirty());
}
}
};
getSite().setSelectionProvider(viewer);
dirty.addValueChangeListener(event -> firePropertyChange(ISaveablePart.PROP_DIRTY));
GridLayoutFactory.fillDefaults().numColumns(4).equalWidth(false)
.generateLayout(parent);
}
void removeSaveable() {
Saveable[] toRemove = getActiveSaveables();
ISaveablesLifecycleListener lifecycleListener = getSite()
.getService(ISaveablesLifecycleListener.class);
SaveablesLifecycleEvent event = new SaveablesLifecycleEvent(this,
SaveablesLifecycleEvent.PRE_CLOSE, toRemove, false);
lifecycleListener.handleLifecycleEvent(event);
if (!event.isVeto()) {
saveables.removeAll(Arrays.asList(toRemove));
lifecycleListener.handleLifecycleEvent(new SaveablesLifecycleEvent(
this, SaveablesLifecycleEvent.POST_CLOSE, toRemove, false));
}
}
void addSaveable() {
MySaveable saveable = new MySaveable();
saveables.add(saveable);
ISaveablesLifecycleListener lifecycleListener = getSite()
.getService(ISaveablesLifecycleListener.class);
lifecycleListener.handleLifecycleEvent(new SaveablesLifecycleEvent(
this, SaveablesLifecycleEvent.POST_OPEN,
new Saveable[] { saveable }, false));
}
@Override
public void setFocus() {
}
@Override
public Saveable[] getActiveSaveables() {
Saveable selectedSaveable = (Saveable) selection.getValue();
return selectedSaveable == null ? new Saveable[0]
: new Saveable[] { selectedSaveable };
}
@Override
public Saveable[] getSaveables() {
return saveables.toArray(new Saveable[saveables.size()]);
}
@Override
public void doSave(IProgressMonitor monitor) {
Assert.isTrue(false,
"Save operations should happen through the saveables.");
}
@Override
public void doSaveAs() {
}
@Override
public boolean isDirty() {
return ((Boolean) dirty.getValue()).booleanValue();
}
@Override
public boolean isSaveAsAllowed() {
return false;
}
@Override
public boolean isSaveOnCloseNeeded() {
return true;
}
class MySaveable extends Saveable {
private IObservableValue<Boolean> myDirty = new WritableValue<>(Boolean.FALSE,
Boolean.TYPE);
@Override
public void doSave(IProgressMonitor monitor) {
setDirty(false);
}
@Override
public boolean equals(Object object) {
return this == object;
}
@Override
public ImageDescriptor getImageDescriptor() {
return null;
}
@Override
public String getName() {
return toString();
}
@Override
public String getToolTipText() {
return toString();
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
@Override
public boolean isDirty() {
return myDirty.getValue().booleanValue();
}
IObservableValue<Boolean> getDirty() {
return myDirty;
}
void setDirty(boolean dirty) {
myDirty.setValue(Boolean.valueOf(dirty));
}
}
class DirtyObservableMap extends ComputedObservableMap<Object, Object> {
Map<IObservableValue<Boolean>, MySaveable> writableValueToElement = new HashMap<>();
private IValueChangeListener<Boolean> valueChangeListener = event -> fireMapChange(
Diffs.createMapDiffSingleChange(
writableValueToElement.get(event.getSource()), event.diff.getOldValue(), event.diff.getNewValue()));
public DirtyObservableMap(IObservableSet knownElements) {
super(knownElements);
init();
}
@Override
protected Object doGet(Object key) {
MySaveable saveable = (MySaveable) key;
return Boolean.valueOf(saveable.isDirty());
}
@Override
protected Object doPut(Object key, Object value) {
MySaveable saveable = (MySaveable) key;
Boolean oldValue = Boolean.valueOf(saveable.isDirty());
saveable.setDirty(((Boolean) value).booleanValue());
keySet().add(key);
return oldValue;
}
@Override
protected void hookListener(Object key) {
MySaveable saveable = (MySaveable) key;
IObservableValue<Boolean> oValue = saveable.getDirty();
writableValueToElement.put(oValue, saveable);
oValue.addValueChangeListener(valueChangeListener);
}
@Override
protected void unhookListener(Object key) {
MySaveable saveable = (MySaveable) key;
saveable.getDirty().removeValueChangeListener(valueChangeListener);
writableValueToElement.remove(saveable.getDirty());
}
}
}