1 /******************************************************************************* 2 * Copyright (c) 2006 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.team.ui.mapping; 15 16 import org.eclipse.core.runtime.CoreException; 17 import org.eclipse.core.runtime.IProgressMonitor; 18 import org.eclipse.core.runtime.ISafeRunnable; 19 import org.eclipse.core.runtime.ListenerList; 20 import org.eclipse.core.runtime.SafeRunner; 21 import org.eclipse.ui.IPropertyListener; 22 import org.eclipse.ui.IWorkbenchPartConstants; 23 import org.eclipse.ui.Saveable; 24 25 /** 26 * A saveable comparison is used to buffer changes made when comparing 27 * or merging model elements. A buffer can be shared between multiple 28 * typed elements within a comparison. The saveable is used by the comparison 29 * container in order to determine when a save is required. 30 * <p> 31 * Clients may subclass this class. 32 * 33 * @since 3.2 34 */ 35 public abstract class SaveableComparison extends Saveable { 36 37 /** 38 * The property id for <code>isDirty</code>. 39 */ 40 public static final int PROP_DIRTY = IWorkbenchPartConstants.PROP_DIRTY; 41 42 private boolean dirty; 43 private ListenerList<IPropertyListener> listeners = new ListenerList<>(ListenerList.IDENTITY); 44 45 /** 46 * {@inheritDoc} 47 */ 48 @Override isDirty()49 public boolean isDirty() { 50 return dirty; 51 } 52 53 /** 54 * {@inheritDoc} 55 */ 56 @Override doSave(IProgressMonitor monitor)57 public void doSave(IProgressMonitor monitor) throws CoreException { 58 if (!isDirty()) 59 return; 60 performSave(monitor); 61 setDirty(false); 62 } 63 64 /** 65 * Revert any changes in the buffer back to the last saved state. 66 * @param monitor a progress monitor on <code>null</code> 67 * if progress feedback is not required 68 */ doRevert(IProgressMonitor monitor)69 public void doRevert(IProgressMonitor monitor) { 70 if (!isDirty()) 71 return; 72 performRevert(monitor); 73 setDirty(false); 74 } 75 76 /** 77 * Add a property change listener. Adding a listener 78 * that is already registered has no effect. 79 * @param listener the listener 80 */ addPropertyListener(IPropertyListener listener)81 public void addPropertyListener(IPropertyListener listener) { 82 listeners.add(listener); 83 } 84 85 /** 86 * Remove a property change listener. Removing a listener 87 * that is not registered has no effect. 88 * @param listener the listener 89 */ removePropertyListener(IPropertyListener listener)90 public void removePropertyListener(IPropertyListener listener) { 91 listeners.remove(listener); 92 } 93 94 /** 95 * Set the dirty state of this buffer. If the state 96 * has changed, a property change event will be fired. 97 * @param dirty the dirty state 98 */ setDirty(boolean dirty)99 protected void setDirty(boolean dirty) { 100 if (this.dirty == dirty) { 101 return; 102 } 103 this.dirty = dirty; 104 firePropertyChange(PROP_DIRTY); 105 } 106 107 /** 108 * Fire a property change event for this buffer. 109 * @param property the property that changed 110 */ firePropertyChange(final int property)111 protected void firePropertyChange(final int property) { 112 Object[] allListeners = listeners.getListeners(); 113 for (Object object : allListeners) { 114 SafeRunner.run(new ISafeRunnable() { 115 @Override 116 public void run() throws Exception { 117 ((IPropertyListener)object).propertyChanged(SaveableComparison.this, property); 118 } 119 @Override 120 public void handleException(Throwable exception) { 121 // handled by platform 122 } 123 }); 124 } 125 } 126 127 /** 128 * Method invoked from {@link #doSave(IProgressMonitor)} to write 129 * out the buffer. By default, this method invokes <code>doSave</code> 130 * on the buffers saveable model. 131 * @param monitor a progress monitor 132 * @throws CoreException if errors occur 133 */ performSave(IProgressMonitor monitor)134 protected abstract void performSave(IProgressMonitor monitor) throws CoreException; 135 136 /** 137 * Method invoked from {@link #doRevert(IProgressMonitor)} to discard the 138 * changes in the buffer. 139 * @param monitor a progress monitor 140 */ performRevert(IProgressMonitor monitor)141 protected abstract void performRevert(IProgressMonitor monitor); 142 } 143