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