Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 273450 | Differences between
and this patch

Collapse All | Expand All

(-)compare/org/eclipse/compare/CompareEditorInput.java (-32 / +133 lines)
Lines 11-19 Link Here
11
package org.eclipse.compare; 
11
package org.eclipse.compare; 
12
12
13
import java.lang.reflect.InvocationTargetException;
13
import java.lang.reflect.InvocationTargetException;
14
import java.util.ArrayList;
15
import java.util.ResourceBundle;
14
import java.util.ResourceBundle;
16
15
16
import org.eclipse.compare.contentmergeviewer.ContentMergeViewer;
17
import org.eclipse.compare.contentmergeviewer.IFlushable;
17
import org.eclipse.compare.contentmergeviewer.IFlushable;
18
import org.eclipse.compare.internal.BinaryCompareViewer;
18
import org.eclipse.compare.internal.BinaryCompareViewer;
19
import org.eclipse.compare.internal.ChangePropertyAction;
19
import org.eclipse.compare.internal.ChangePropertyAction;
Lines 24-29 Link Here
24
import org.eclipse.compare.internal.CompareStructureViewerSwitchingPane;
24
import org.eclipse.compare.internal.CompareStructureViewerSwitchingPane;
25
import org.eclipse.compare.internal.CompareUIPlugin;
25
import org.eclipse.compare.internal.CompareUIPlugin;
26
import org.eclipse.compare.internal.ICompareUIConstants;
26
import org.eclipse.compare.internal.ICompareUIConstants;
27
import org.eclipse.compare.internal.IFlushable2;
27
import org.eclipse.compare.internal.OutlineViewerCreator;
28
import org.eclipse.compare.internal.OutlineViewerCreator;
28
import org.eclipse.compare.internal.Utilities;
29
import org.eclipse.compare.internal.Utilities;
29
import org.eclipse.compare.internal.ViewerDescriptor;
30
import org.eclipse.compare.internal.ViewerDescriptor;
Lines 177-183 Link Here
177
	 * @since 3.3
178
	 * @since 3.3
178
	 */
179
	 */
179
	public static final String PROP_SELECTED_EDITION= ICompareUIConstants.PROP_SELECTED_EDITION;
180
	public static final String PROP_SELECTED_EDITION= ICompareUIConstants.PROP_SELECTED_EDITION;
180
		
181
181
	private static final String COMPARE_EDITOR_IMAGE_NAME= "eview16/compare_view.gif"; //$NON-NLS-1$
182
	private static final String COMPARE_EDITOR_IMAGE_NAME= "eview16/compare_view.gif"; //$NON-NLS-1$
182
	private static Image fgTitleImage;
183
	private static Image fgTitleImage;
183
	
184
	
Lines 193-200 Link Here
193
	private String fTitle;
194
	private String fTitle;
194
	private ListenerList fListenerList= new ListenerList();
195
	private ListenerList fListenerList= new ListenerList();
195
	private CompareNavigator fNavigator;
196
	private CompareNavigator fNavigator;
196
	private boolean fDirty= false;
197
	private ContentMergeViewer fLeftDirtyViewer = null;
197
	private ArrayList fDirtyViewers= new ArrayList();
198
	private ContentMergeViewer fRightDirtyViewer = null;
198
	private IPropertyChangeListener fDirtyStateListener;
199
	private IPropertyChangeListener fDirtyStateListener;
199
	
200
	
200
	boolean fStructureCompareOnSingleClick= true;
201
	boolean fStructureCompareOnSingleClick= true;
Lines 1016-1033 Link Here
1016
	}
1017
	}
1017
	
1018
	
1018
	/**
1019
	/**
1019
	 * Returns <code>true</code> if there are unsaved changes.
1020
	 * Returns <code>true</code> if there are unsaved changes in either left or
1020
	 * The value returned is the value of the <code>DIRTY_STATE</code> property of this input object.
1021
	 * right side. The value returned is the value of the
1021
	 
1022
	 * <code>DIRTY_STATE</code> property of this input object.
1022
	 * Returns <code>true</code> if this input has unsaved changes,
1023
	 * 
1023
	 * that is if <code>setDirty(true)</code> has been called.
1024
	 * Returns <code>true</code> if left or right side has unsaved changes
1024
	 * Subclasses don't have to override if the functionality provided by <code>setDirty</code>
1025
	 * Subclasses don't have to override if the functionality provided by
1025
	 * is sufficient.
1026
	 * <code>setDirty</code> is sufficient.
1026
	 *
1027
	 * 
1027
	 * @return <code>true</code> if there are changes that need to be saved
1028
	 * @return <code>true</code> if there are changes that need to be saved
1028
	 */
1029
	 */
1029
	public boolean isSaveNeeded() {
1030
	public boolean isSaveNeeded() {
1030
		return fDirty || fDirtyViewers.size() > 0;
1031
		return isLeftSaveNeeded() || isRightSaveNeeded();
1032
	}
1033
1034
	/**
1035
	 * Returns <code>true</code> if there are unsaved changes for left side.
1036
	 * 
1037
	 * @return <code>true</code> if there are changes that need to be saved
1038
	 * @noreference This method is not intended to be referenced by clients.
1039
	 */
1040
	protected boolean isLeftSaveNeeded() {
1041
		return fLeftDirtyViewer != null;
1042
	}
1043
1044
	/**
1045
	 * Returns <code>true</code> if there are unsaved changes for right side.
1046
	 * 
1047
	 * @return <code>true</code> if there are changes that need to be saved
1048
	 * @noreference This method is not intended to be referenced by clients.
1049
	 */
1050
	protected boolean isRightSaveNeeded() {
1051
		return fRightDirtyViewer != null;
1031
	}
1052
	}
1032
	
1053
	
1033
	/**
1054
	/**
Lines 1044-1074 Link Here
1044
	}
1065
	}
1045
		
1066
		
1046
	/**
1067
	/**
1047
	 * Sets the dirty state of this input to the given
1068
	 * Sets the dirty state of this input to the given value and sends out a
1048
	 * value and sends out a <code>PropertyChangeEvent</code> if the new value differs from the old value.
1069
	 * <code>PropertyChangeEvent</code> if the new value differs from the old
1049
	 *
1070
	 * value. Direct calling this method with parameter dirty equal to
1050
	 * @param dirty the dirty state for this compare input
1071
	 * <code>false</code> when there are unsaved changes in viewers, results in
1072
	 * inconsistent state. The dirty state of compare input should be based only
1073
	 * on the information if there are changes in viewers for left or right
1074
	 * side.
1075
	 * 
1076
	 * @param dirty
1077
	 *            the dirty state for this compare input
1051
	 */
1078
	 */
1052
	public void setDirty(boolean dirty) {
1079
	public void setDirty(boolean dirty) {
1053
		boolean oldDirty = fDirty || fDirtyViewers.size() > 0;
1080
		boolean oldDirty = isSaveNeeded();
1054
		fDirty= dirty;
1081
		boolean newDirty = dirty || isSaveNeeded();
1055
		if (!fDirty)
1082
		if (!newDirty) {
1056
			fDirtyViewers.clear();
1083
			fLeftDirtyViewer = null;
1057
		if (oldDirty != dirty)
1084
			fRightDirtyViewer = null;
1058
			Utilities.firePropertyChange(fListenerList, this, DIRTY_STATE, Boolean.valueOf(oldDirty), Boolean.valueOf(dirty));
1085
		}
1086
		if (oldDirty != isSaveNeeded()) {
1087
			Utilities.firePropertyChange(fListenerList, this, DIRTY_STATE, Boolean.valueOf(oldDirty), Boolean.valueOf(isSaveNeeded()));
1088
		}
1059
	}
1089
	}
1060
	
1090
	
1091
	/**
1092
	 * Method adds or removes viewers that changed left or right side of this
1093
	 * compare input. Any modification of any of the list of viewers may result
1094
	 * in dirty state change.
1095
	 * 
1096
	 * @param source
1097
	 *            the object that fired <code>PropertyChangeEvent</code>
1098
	 *            modifying the dirty state
1099
	 * @param dirty
1100
	 *            value that describes if the changes were added or removed
1101
	 */
1061
	private void setDirty(Object source, boolean dirty) {
1102
	private void setDirty(Object source, boolean dirty) {
1062
		Assert.isNotNull(source);
1103
		Assert.isNotNull(source);
1063
		boolean oldDirty= fDirty || fDirtyViewers.size() > 0;
1104
		boolean oldDirty = isSaveNeeded();
1064
		if (dirty)
1105
		ContentMergeViewer cmv = (ContentMergeViewer) source;
1065
			fDirtyViewers.add(source);
1106
		if (dirty) {
1066
		else
1107
			if (cmv.isLeftDirty()) {
1067
			fDirtyViewers.remove(source);
1108
				if (fLeftDirtyViewer == null) {
1068
		boolean newDirty= fDirty || fDirtyViewers.size() > 0;
1109
					fLeftDirtyViewer = cmv;
1069
		if (DEBUG) System.out.println("setDirty("+source+", "+dirty+"): " + newDirty); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
1110
				}
1070
		if (oldDirty != newDirty)
1111
			}
1112
			if (cmv.isRightDirty()) {
1113
				if (fRightDirtyViewer == null) {
1114
					fRightDirtyViewer = cmv;
1115
				}
1116
			}
1117
		} else {
1118
			if (!cmv.isLeftDirty()) {
1119
				fLeftDirtyViewer = null;
1120
			}
1121
			if (!cmv.isRightDirty()) {
1122
				fRightDirtyViewer = null;
1123
			}
1124
		}
1125
		boolean newDirty = isSaveNeeded();
1126
		if (DEBUG) {
1127
			System.out.println("setDirty(" + source + ", " + dirty + "): " + newDirty); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
1128
		}
1129
		if (oldDirty != newDirty) {
1071
			Utilities.firePropertyChange(fListenerList, this, DIRTY_STATE, Boolean.valueOf(oldDirty), Boolean.valueOf(newDirty));
1130
			Utilities.firePropertyChange(fListenerList, this, DIRTY_STATE, Boolean.valueOf(oldDirty), Boolean.valueOf(newDirty));
1131
		}
1072
	}
1132
	}
1073
	
1133
	
1074
	/* (non Javadoc)
1134
	/* (non Javadoc)
Lines 1129-1135 Link Here
1129
		flushViewer(fStructurePane2, monitor);
1189
		flushViewer(fStructurePane2, monitor);
1130
		flushViewer(fContentInputPane, monitor);
1190
		flushViewer(fContentInputPane, monitor);
1131
	}
1191
	}
1132
		
1192
	
1193
	/**
1194
	 * @param monitor
1195
	 * @noreference This method is not intended to be referenced by clients.
1196
	 */
1197
	protected void flushLeftViewers(IProgressMonitor monitor) {
1198
		// flush changes in left dirty viewer
1199
		flushViewer(fStructureInputPane, monitor);
1200
		flushViewer(fStructurePane1, monitor);
1201
		flushViewer(fStructurePane2, monitor);
1202
		flushLeftViewer(fContentInputPane, monitor);
1203
	}
1204
1205
	/**
1206
	 * @param monitor
1207
	 * @noreference This method is not intended to be referenced by clients.
1208
	 */
1209
	protected void flushRightViewers(IProgressMonitor monitor) {
1210
		// flush changes in right dirty viewer
1211
		flushViewer(fStructureInputPane, monitor);
1212
		flushViewer(fStructurePane1, monitor);
1213
		flushViewer(fStructurePane2, monitor);
1214
		flushRightViewer(fContentInputPane, monitor);
1215
	}
1216
	
1133
	private static void flushViewer(CompareViewerPane pane, IProgressMonitor pm) {
1217
	private static void flushViewer(CompareViewerPane pane, IProgressMonitor pm) {
1134
		if (pane != null) {
1218
		if (pane != null) {
1135
			IFlushable flushable = (IFlushable)Utilities.getAdapter(pane, IFlushable.class);
1219
			IFlushable flushable = (IFlushable)Utilities.getAdapter(pane, IFlushable.class);
Lines 1138-1143 Link Here
1138
		}
1222
		}
1139
	}
1223
	}
1140
	
1224
	
1225
	private static void flushLeftViewer(CompareViewerPane pane, IProgressMonitor pm) {
1226
		if (pane != null) {
1227
			IFlushable2 flushable = (IFlushable2)Utilities.getAdapter(pane, IFlushable2.class);
1228
			if (flushable != null)
1229
				flushable.flushLeft(pm);
1230
		}
1231
	}
1232
1233
	private static void flushRightViewer(CompareViewerPane pane, IProgressMonitor pm) {
1234
		if (pane != null) {
1235
			IFlushable2 flushable = (IFlushable2)Utilities.getAdapter(pane, IFlushable2.class);
1236
			if (flushable != null)
1237
				flushable.flushRight(pm);
1238
		}
1239
	}
1240
1241
	
1141
	/* (non-Javadoc)
1242
	/* (non-Javadoc)
1142
	 * @see org.eclipse.compare.ICompareContainer#addCompareInputChangeListener(org.eclipse.compare.structuremergeviewer.ICompareInput, org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
1243
	 * @see org.eclipse.compare.ICompareContainer#addCompareInputChangeListener(org.eclipse.compare.structuremergeviewer.ICompareInput, org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
1143
	 */
1244
	 */
(-)compare/org/eclipse/compare/CompareViewerSwitchingPane.java (+9 lines)
Lines 12-17 Link Here
12
12
13
import org.eclipse.compare.contentmergeviewer.IFlushable;
13
import org.eclipse.compare.contentmergeviewer.IFlushable;
14
import org.eclipse.compare.internal.CompareMessages;
14
import org.eclipse.compare.internal.CompareMessages;
15
import org.eclipse.compare.internal.IFlushable2;
15
import org.eclipse.compare.internal.NullViewer;
16
import org.eclipse.compare.internal.NullViewer;
16
import org.eclipse.compare.internal.Utilities;
17
import org.eclipse.compare.internal.Utilities;
17
import org.eclipse.compare.structuremergeviewer.ICompareInput;
18
import org.eclipse.compare.structuremergeviewer.ICompareInput;
Lines 354-359 Link Here
354
					return flushable;
355
					return flushable;
355
			}
356
			}
356
		}
357
		}
358
		if (adapter == IFlushable2.class) {
359
			Viewer v= getViewer();
360
			if (v != null) {
361
				IFlushable2 flushable = (IFlushable2)Utilities.getAdapter(v, IFlushable2.class);
362
				if (flushable != null)
363
					return flushable;
364
			}
365
		}
357
		return super.getAdapter(adapter);
366
		return super.getAdapter(adapter);
358
	}
367
	}
359
	
368
	
(-)compare/org/eclipse/compare/contentmergeviewer/ContentMergeViewer.java (-84 / +79 lines)
Lines 25-40 Link Here
25
import org.eclipse.compare.internal.CompareHandlerService;
25
import org.eclipse.compare.internal.CompareHandlerService;
26
import org.eclipse.compare.internal.CompareMessages;
26
import org.eclipse.compare.internal.CompareMessages;
27
import org.eclipse.compare.internal.ICompareUIConstants;
27
import org.eclipse.compare.internal.ICompareUIConstants;
28
import org.eclipse.compare.internal.IFlushable2;
29
import org.eclipse.compare.internal.ISavingStateProvider;
28
import org.eclipse.compare.internal.MergeViewerContentProvider;
30
import org.eclipse.compare.internal.MergeViewerContentProvider;
29
import org.eclipse.compare.internal.Utilities;
31
import org.eclipse.compare.internal.Utilities;
30
import org.eclipse.compare.internal.ViewerSwitchingCancelled;
32
import org.eclipse.compare.internal.ViewerSwitchingCancelled;
31
import org.eclipse.compare.structuremergeviewer.Differencer;
33
import org.eclipse.compare.structuremergeviewer.Differencer;
32
import org.eclipse.compare.structuremergeviewer.ICompareInput;
34
import org.eclipse.compare.structuremergeviewer.ICompareInput;
33
import org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener;
35
import org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener;
34
import org.eclipse.core.commands.ExecutionEvent;
35
import org.eclipse.core.commands.ExecutionException;
36
import org.eclipse.core.commands.IExecutionListener;
37
import org.eclipse.core.commands.NotHandledException;
38
import org.eclipse.core.runtime.Assert;
36
import org.eclipse.core.runtime.Assert;
39
import org.eclipse.core.runtime.CoreException;
37
import org.eclipse.core.runtime.CoreException;
40
import org.eclipse.core.runtime.IProgressMonitor;
38
import org.eclipse.core.runtime.IProgressMonitor;
Lines 71-79 Link Here
71
import org.eclipse.swt.widgets.Layout;
69
import org.eclipse.swt.widgets.Layout;
72
import org.eclipse.swt.widgets.Sash;
70
import org.eclipse.swt.widgets.Sash;
73
import org.eclipse.swt.widgets.Shell;
71
import org.eclipse.swt.widgets.Shell;
74
import org.eclipse.ui.IWorkbenchCommandConstants;
72
import org.eclipse.ui.ISaveablesSource;
75
import org.eclipse.ui.PlatformUI;
73
import org.eclipse.ui.IWorkbenchPart;
76
import org.eclipse.ui.commands.ICommandService;
74
import org.eclipse.ui.Saveable;
77
75
78
/**
76
/**
79
 * An abstract compare and merge viewer with two side-by-side content areas
77
 * An abstract compare and merge viewer with two side-by-side content areas
Lines 102-108 Link Here
102
 * @see TextMergeViewer
100
 * @see TextMergeViewer
103
 */
101
 */
104
public abstract class ContentMergeViewer extends ContentViewer
102
public abstract class ContentMergeViewer extends ContentViewer
105
					implements IPropertyChangeNotifier, IFlushable {
103
					implements IPropertyChangeNotifier, IFlushable, IFlushable2 {
106
	
104
	
107
	/* package */ static final int HORIZONTAL= 1;
105
	/* package */ static final int HORIZONTAL= 1;
108
	/* package */ static final int VERTICAL= 2;
106
	/* package */ static final int VERTICAL= 2;
Lines 295-304 Link Here
295
	private boolean fIsLeftDirty;
293
	private boolean fIsLeftDirty;
296
	private boolean fIsRightDirty;
294
	private boolean fIsRightDirty;
297
295
298
	private boolean fIsSaving;
299
	private ICommandService fCommandService;
300
	private IExecutionListener fExecutionListener;
301
	
302
	private CompareHandlerService fHandlerService;
296
	private CompareHandlerService fHandlerService;
303
297
304
	// SWT widgets
298
	// SWT widgets
Lines 371-413 Link Here
371
		
365
		
372
		fIsLeftDirty = false;
366
		fIsLeftDirty = false;
373
		fIsRightDirty = false;
367
		fIsRightDirty = false;
374
375
		fIsSaving = false;
376
		fCommandService = (ICommandService)PlatformUI.getWorkbench().getAdapter(ICommandService.class);
377
		if (fCommandService != null) {
378
			fCommandService.addExecutionListener(getExecutionListener());
379
		}
380
	}
368
	}
381
369
382
	private IExecutionListener getExecutionListener() {
383
		if (fExecutionListener == null) {
384
			fExecutionListener = new IExecutionListener() {
385
				public void preExecute(String commandId, ExecutionEvent event) {
386
					if (IWorkbenchCommandConstants.FILE_SAVE.equals(commandId)
387
							|| IWorkbenchCommandConstants.FILE_SAVE_ALL.equals(commandId))
388
						fIsSaving = true;
389
				}
390
391
				public void postExecuteSuccess(String commandId, Object returnValue) {
392
					if (IWorkbenchCommandConstants.FILE_SAVE.equals(commandId)
393
							|| IWorkbenchCommandConstants.FILE_SAVE_ALL.equals(commandId))
394
						fIsSaving= false;
395
				}
396
397
				public void postExecuteFailure(String commandId, ExecutionException exception) {
398
					if (IWorkbenchCommandConstants.FILE_SAVE.equals(commandId)
399
							|| IWorkbenchCommandConstants.FILE_SAVE_ALL.equals(commandId))
400
						fIsSaving= false;
401
				}
402
403
				public void notHandled(String commandId, NotHandledException exception) {
404
					// not needed
405
				}
406
			};
407
		}
408
		return fExecutionListener;
409
	}
410
	
411
	//---- hooks ---------------------
370
	//---- hooks ---------------------
412
	
371
	
413
	/**
372
	/**
Lines 1037-1048 Link Here
1037
			fHVSashCursor= null;
996
			fHVSashCursor= null;
1038
		}
997
		}
1039
		
998
		
1040
		if (fCommandService != null) {
1041
			fCommandService.removeExecutionListener(fExecutionListener);
1042
			fCommandService = null;
1043
			fExecutionListener = null;
1044
		}
1045
1046
		super.handleDispose(event);
999
		super.handleDispose(event);
1047
  	}
1000
  	}
1048
  	
1001
  	
Lines 1168-1176 Link Here
1168
	protected void setLeftDirty(boolean dirty) {
1121
	protected void setLeftDirty(boolean dirty) {
1169
		if (isLeftDirty() != dirty) {
1122
		if (isLeftDirty() != dirty) {
1170
			fIsLeftDirty = dirty;
1123
			fIsLeftDirty = dirty;
1171
			// Only fire the event if the combined dirty state has changed
1124
			// Always fire the event if the dirty state has changed
1172
			if (!isRightDirty())
1125
			fireDirtyState(dirty);
1173
				fireDirtyState(dirty);
1174
		}
1126
		}
1175
	}
1127
	}
1176
	
1128
	
Lines 1186-1194 Link Here
1186
	protected void setRightDirty(boolean dirty) {
1138
	protected void setRightDirty(boolean dirty) {
1187
		if (isRightDirty() != dirty) {
1139
		if (isRightDirty() != dirty) {
1188
			fIsRightDirty = dirty;
1140
			fIsRightDirty = dirty;
1189
			// Only fire the event if the combined dirty state has changed
1141
			// Always fire the event if the dirty state has changed
1190
			if (!isLeftDirty())
1142
			fireDirtyState(dirty);
1191
				fireDirtyState(dirty);
1192
		}
1143
		}
1193
	}
1144
	}
1194
	
1145
	
Lines 1216-1262 Link Here
1216
		flushContent(getInput(), monitor);
1167
		flushContent(getInput(), monitor);
1217
	}
1168
	}
1218
	
1169
	
1219
	/**
1170
	public void flushLeft(IProgressMonitor monitor) {
1220
	 * Flush the modified content back to input elements via the content provider.
1171
		flushLeftSide(getInput(), monitor);
1221
	 * The provided input may be the current input of the viewer or it may be
1172
	}
1222
	 * the previous input (i.e. this method may be called to flush modified content
1173
1223
	 * during an input change).
1174
	public void flushRight(IProgressMonitor monitor) {
1224
	 * @param input the compare input
1175
		flushRightSide(getInput(), monitor);
1225
	 * @param monitor a progress monitor or <code>null</code> if the method
1176
	}
1226
	 * was call from a place where a progress monitor was not available.
1177
1227
	 * @since 3.3
1178
	protected void flushLeftSide(Object input, IProgressMonitor monitor) {
1228
	 */
1179
		IMergeViewerContentProvider content = (IMergeViewerContentProvider) getContentProvider();
1229
	protected void flushContent(Object input, IProgressMonitor monitor) {
1180
1230
				
1181
		boolean rightEmpty = content.getRightContent(input) == null;
1231
		// write back modified contents
1232
		IMergeViewerContentProvider content= (IMergeViewerContentProvider) getContentProvider();
1233
		
1234
		boolean leftEmpty= content.getLeftContent(input) == null;
1235
		boolean rightEmpty= content.getRightContent(input) == null;
1236
1182
1237
		if (getCompareConfiguration().isLeftEditable() && isLeftDirty()) {
1183
		if (getCompareConfiguration().isLeftEditable() && isLeftDirty()) {
1238
			byte[] bytes= getContents(true);
1184
			byte[] bytes = getContents(true);
1239
			if (rightEmpty && bytes != null && bytes.length == 0)
1185
			if (rightEmpty && bytes != null && bytes.length == 0)
1240
				bytes= null;
1186
				bytes = null;
1241
			setLeftDirty(false);
1187
			setLeftDirty(false);
1242
			content.saveLeftContent(input, bytes);
1188
			content.saveLeftContent(input, bytes);
1243
		}
1189
		}
1244
		
1190
	}
1191
1192
	protected void flushRightSide(Object input, IProgressMonitor monitor) {
1193
		IMergeViewerContentProvider content = (IMergeViewerContentProvider) getContentProvider();
1194
1195
		boolean leftEmpty = content.getLeftContent(input) == null;
1196
1245
		if (getCompareConfiguration().isRightEditable() && isRightDirty()) {
1197
		if (getCompareConfiguration().isRightEditable() && isRightDirty()) {
1246
			byte[] bytes= getContents(false);
1198
			byte[] bytes = getContents(false);
1247
			if (leftEmpty && bytes != null && bytes.length == 0)
1199
			if (leftEmpty && bytes != null && bytes.length == 0)
1248
				bytes= null;
1200
				bytes = null;
1249
			setRightDirty(false);
1201
			setRightDirty(false);
1250
			content.saveRightContent(input, bytes);
1202
			content.saveRightContent(input, bytes);
1251
		}
1203
		}
1252
	}
1204
	}
1253
1205
1254
	/**
1206
	/**
1207
	 * Flush the modified content back to input elements via the content provider.
1208
	 * The provided input may be the current input of the viewer or it may be
1209
	 * the previous input (i.e. this method may be called to flush modified content
1210
	 * during an input change).
1211
	 * @param input the compare input
1212
	 * @param monitor a progress monitor or <code>null</code> if the method
1213
	 * was call from a place where a progress monitor was not available.
1214
	 * @since 3.3
1215
	 */
1216
	protected void flushContent(Object input, IProgressMonitor monitor) {
1217
		flushLeftSide(input, monitor);
1218
		flushRightSide(input, monitor);
1219
	}
1220
1221
	/**
1255
	 * Return the dirty state of the right side of this viewer.
1222
	 * Return the dirty state of the right side of this viewer.
1256
	 * @return the dirty state of the right side of this viewer
1223
	 * @return the dirty state of the right side of this viewer
1257
	 * @since 3.3
1224
	 * @since 3.3
1258
	 */
1225
	 */
1259
	protected boolean isRightDirty() {
1226
	public boolean isRightDirty() {
1260
		return fIsRightDirty;
1227
		return fIsRightDirty;
1261
	}
1228
	}
1262
1229
Lines 1265-1271 Link Here
1265
	 * @return the dirty state of the left side of this viewer
1232
	 * @return the dirty state of the left side of this viewer
1266
	 * @since 3.3
1233
	 * @since 3.3
1267
	 */
1234
	 */
1268
	protected boolean isLeftDirty() {
1235
	public boolean isLeftDirty() {
1269
		return fIsLeftDirty;
1236
		return fIsLeftDirty;
1270
	}
1237
	}
1271
1238
Lines 1279-1285 Link Here
1279
	protected void handleCompareInputChange() {
1246
	protected void handleCompareInputChange() {
1280
		// before setting the new input we have to save the old
1247
		// before setting the new input we have to save the old
1281
		Object input = getInput();
1248
		Object input = getInput();
1282
		if (!fIsSaving && (isLeftDirty() || isRightDirty())) {
1249
		if (!isSaving() && (isLeftDirty() || isRightDirty())) {
1283
			
1250
			
1284
			if (Utilities.RUNNING_TESTS) {
1251
			if (Utilities.RUNNING_TESTS) {
1285
				if (Utilities.TESTING_FLUSH_ON_COMPARE_INPUT_CHANGE) {
1252
				if (Utilities.TESTING_FLUSH_ON_COMPARE_INPUT_CHANGE) {
Lines 1317-1320 Link Here
1317
	CompareHandlerService getCompareHandlerService() {
1284
	CompareHandlerService getCompareHandlerService() {
1318
		return fHandlerService;
1285
		return fHandlerService;
1319
	}
1286
	}
1287
	
1288
	/**
1289
	 * @return true if any of the Saveables is being saved
1290
	 */
1291
	private boolean isSaving() {
1292
		ICompareContainer container = fCompareConfiguration.getContainer();
1293
		ISaveablesSource source = null;
1294
		if (container instanceof ISaveablesSource) {
1295
			source = (ISaveablesSource) container;
1296
		} else {
1297
			IWorkbenchPart part = container.getWorkbenchPart();
1298
			if (part instanceof ISaveablesSource) {
1299
				source = (ISaveablesSource) part;
1300
			}
1301
		}
1302
		if (source != null) {
1303
			Saveable[] saveables = source.getSaveables();
1304
			for (int i = 0; i < saveables.length; i++) {
1305
				if (saveables[i] instanceof ISavingStateProvider) {
1306
					ISavingStateProvider saveable = (ISavingStateProvider) saveables[i];
1307
					if (saveable.isSaving())
1308
						return true;
1309
				}
1310
			}
1311
		}
1312
		return false;
1313
	} 
1314
1320
}
1315
}
(-)compare/org/eclipse/compare/contentmergeviewer/TextMergeViewer.java (-8 / +17 lines)
Lines 4838-4852 Link Here
4838
		return fMerger.virtualToRealPosition(contributor, v);
4838
		return fMerger.virtualToRealPosition(contributor, v);
4839
	}
4839
	}
4840
	
4840
	
4841
	/* (non-Javadoc)
4841
	protected void flushLeftSide(Object oldInput, IProgressMonitor monitor){
4842
	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#flushContent(java.lang.Object, org.eclipse.core.runtime.IProgressMonitor)
4843
	 */
4844
	protected void flushContent(Object oldInput, IProgressMonitor monitor) {
4845
				
4846
		// check and handle any shared buffers
4847
		IMergeViewerContentProvider content= getMergeContentProvider();
4842
		IMergeViewerContentProvider content= getMergeContentProvider();
4848
		Object leftContent = content.getLeftContent(oldInput);
4843
		Object leftContent = content.getLeftContent(oldInput);
4849
		Object rightContent = content.getRightContent(oldInput);
4850
		
4844
		
4851
		if (leftContent != null && getCompareConfiguration().isLeftEditable() && isLeftDirty()) {
4845
		if (leftContent != null && getCompareConfiguration().isLeftEditable() && isLeftDirty()) {
4852
			if (fLeftContributor.hasSharedDocument(leftContent)) {
4846
			if (fLeftContributor.hasSharedDocument(leftContent)) {
Lines 4854-4859 Link Here
4854
					setLeftDirty(false);
4848
					setLeftDirty(false);
4855
			}
4849
			}
4856
		}
4850
		}
4851
	}
4852
	
4853
	protected void flushRightSide(Object oldInput, IProgressMonitor monitor){
4854
		IMergeViewerContentProvider content= getMergeContentProvider();
4855
		Object rightContent = content.getRightContent(oldInput);
4857
		
4856
		
4858
		if (rightContent != null && getCompareConfiguration().isRightEditable() && isRightDirty()) {
4857
		if (rightContent != null && getCompareConfiguration().isRightEditable() && isRightDirty()) {
4859
			if (fRightContributor.hasSharedDocument(rightContent)) {
4858
			if (fRightContributor.hasSharedDocument(rightContent)) {
Lines 4861-4867 Link Here
4861
					setRightDirty(false);
4860
					setRightDirty(false);
4862
			}
4861
			}
4863
		}
4862
		}
4864
		
4863
	}
4864
	
4865
	/* (non-Javadoc)
4866
	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#flushContent(java.lang.Object, org.eclipse.core.runtime.IProgressMonitor)
4867
	 */
4868
	protected void flushContent(Object oldInput, IProgressMonitor monitor) {
4869
		flushLeftSide(oldInput, monitor);
4870
		flushRightSide(oldInput, monitor);
4871
4872
		IMergeViewerContentProvider content = getMergeContentProvider();
4873
4865
		if (!(content instanceof MergeViewerContentProvider) || isLeftDirty() || isRightDirty()) {
4874
		if (!(content instanceof MergeViewerContentProvider) || isLeftDirty() || isRightDirty()) {
4866
			super.flushContent(oldInput, monitor);
4875
			super.flushContent(oldInput, monitor);
4867
		}
4876
		}
(-)compare/org/eclipse/compare/internal/IFlushable2.java (+8 lines)
Added Link Here
1
package org.eclipse.compare.internal;
2
3
import org.eclipse.core.runtime.IProgressMonitor;
4
5
public interface IFlushable2 {
6
	void flushLeft(IProgressMonitor monitor);
7
	void flushRight(IProgressMonitor monitor);
8
}
(-)compare/org/eclipse/compare/internal/ISavingStateProvider.java (+15 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 * IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.compare.internal;
12
13
public interface ISavingStateProvider {
14
	public boolean isSaving();
15
}
(-)src/org/eclipse/compare/tests/ContentMergeViewerTest.java (-6 / +13 lines)
Lines 21-26 Link Here
21
public class ContentMergeViewerTest extends TestCase {
21
public class ContentMergeViewerTest extends TestCase {
22
22
23
	private MyContentMergeViewer myContentMergeViewer;
23
	private MyContentMergeViewer myContentMergeViewer;
24
	/**
25
	 * result[0]-event occurred or not; result[1]-new state that was set
26
	 */
24
	boolean[] result = new boolean[] { false, false };
27
	boolean[] result = new boolean[] { false, false };
25
28
26
	public ContentMergeViewerTest() {
29
	public ContentMergeViewerTest() {
Lines 40-50 Link Here
40
		public boolean leftDirty = false;
43
		public boolean leftDirty = false;
41
		public boolean rightDirty = false;
44
		public boolean rightDirty = false;
42
45
43
		protected boolean isLeftDirty() {
46
		public boolean isLeftDirty() {
44
			return leftDirty;
47
			return leftDirty;
45
		}
48
		}
46
49
47
		protected boolean isRightDirty() {
50
		public boolean isRightDirty() {
48
			return rightDirty;
51
			return rightDirty;
49
		}
52
		}
50
53
Lines 109-115 Link Here
109
		myContentMergeViewer.rightDirty = true;
112
		myContentMergeViewer.rightDirty = true;
110
		myContentMergeViewer.setLeftDirty(true);
113
		myContentMergeViewer.setLeftDirty(true);
111
114
112
		Assert.assertEquals(false, result[0]);
115
		Assert.assertEquals(true, result[0]);
116
		Assert.assertEquals(true, result[1]);
113
	}
117
	}
114
118
115
	public void testTFTX() {
119
	public void testTFTX() {
Lines 160-166 Link Here
160
		myContentMergeViewer.rightDirty = true;
164
		myContentMergeViewer.rightDirty = true;
161
		myContentMergeViewer.setLeftDirty(false);
165
		myContentMergeViewer.setLeftDirty(false);
162
166
163
		Assert.assertEquals(false, result[0]);
167
		Assert.assertEquals(true, result[0]);
168
		Assert.assertEquals(false, result[1]);
164
	}
169
	}
165
170
166
	// set right to true
171
	// set right to true
Lines 187-193 Link Here
187
		myContentMergeViewer.rightDirty = false;
192
		myContentMergeViewer.rightDirty = false;
188
		myContentMergeViewer.setRightDirty(true);
193
		myContentMergeViewer.setRightDirty(true);
189
194
190
		Assert.assertEquals(false, result[0]);
195
		Assert.assertEquals(true, result[0]);
196
		Assert.assertEquals(true, result[1]);
191
	}
197
	}
192
198
193
	public void testTTXT() {
199
	public void testTTXT() {
Lines 230-235 Link Here
230
		myContentMergeViewer.rightDirty = true;
236
		myContentMergeViewer.rightDirty = true;
231
		myContentMergeViewer.setRightDirty(false);
237
		myContentMergeViewer.setRightDirty(false);
232
238
233
		Assert.assertEquals(false, result[0]);
239
		Assert.assertEquals(true, result[0]);
240
		Assert.assertEquals(false, result[1]);
234
	}
241
	}
235
}
242
}
(-)src/org/eclipse/team/internal/ui/synchronize/LocalResourceSaveableComparison.java (-7 / +31 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2006, 2007 IBM Corporation and others.
2
 * Copyright (c) 2006, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 11-16 Link Here
11
package org.eclipse.team.internal.ui.synchronize;
11
package org.eclipse.team.internal.ui.synchronize;
12
12
13
import org.eclipse.compare.*;
13
import org.eclipse.compare.*;
14
import org.eclipse.compare.internal.ISavingStateProvider;
14
import org.eclipse.compare.structuremergeviewer.ICompareInput;
15
import org.eclipse.compare.structuremergeviewer.ICompareInput;
15
import org.eclipse.core.resources.IFile;
16
import org.eclipse.core.resources.IFile;
16
import org.eclipse.core.runtime.*;
17
import org.eclipse.core.runtime.*;
Lines 35-41 Link Here
35
 * @see LocalResourceTypedElement
36
 * @see LocalResourceTypedElement
36
 * @since 3.3
37
 * @since 3.3
37
 */
38
 */
38
public abstract class LocalResourceSaveableComparison extends SaveableComparison implements IPropertyChangeListener {
39
public abstract class LocalResourceSaveableComparison extends SaveableComparison implements IPropertyChangeListener, ISavingStateProvider {
39
40
40
	private final ICompareInput input;
41
	private final ICompareInput input;
41
	private final CompareEditorInput editorInput;
42
	private final CompareEditorInput editorInput;
Lines 130-139 Link Here
130
			flushViewers(Policy.subMonitorFor(monitor, 40));
131
			flushViewers(Policy.subMonitorFor(monitor, 40));
131
			// Then we tell the input to commit its changes
132
			// Then we tell the input to commit its changes
132
			// Only the left is ever saveable
133
			// Only the left is ever saveable
133
			ITypedElement left = getFileElement();
134
			ITypedElement te = getFileElement();
134
			if (left instanceof LocalResourceTypedElement) {
135
			if (te instanceof LocalResourceTypedElement) {
135
				LocalResourceTypedElement te = (LocalResourceTypedElement) left;
136
				LocalResourceTypedElement lrte = (LocalResourceTypedElement) te;
136
				te.commit(Policy.subMonitorFor(monitor, 60));
137
				lrte.commit(Policy.subMonitorFor(monitor, 60));
137
			}
138
			}
138
		} finally {
139
		} finally {
139
			// Make sure we fire a change for the compare input to update the viewers
140
			// Make sure we fire a change for the compare input to update the viewers
Lines 150-156 Link Here
150
	 * @throws CoreException
151
	 * @throws CoreException
151
	 */
152
	 */
152
	protected void flushViewers(IProgressMonitor monitor) throws CoreException {
153
	protected void flushViewers(IProgressMonitor monitor) throws CoreException {
153
		editorInput.saveChanges(monitor);
154
		if (editorInput instanceof SaveablesCompareEditorInput) {
155
			((SaveablesCompareEditorInput) editorInput).saveChanges(monitor, this);
156
		} else {
157
			editorInput.saveChanges(monitor);
158
		}
154
	}
159
	}
155
160
156
	/**
161
	/**
Lines 206-211 Link Here
206
	public boolean isDirty() {
211
	public boolean isDirty() {
207
		// We need to get the dirty state from the compare editor input
212
		// We need to get the dirty state from the compare editor input
208
		// since it is our only connection to the merge viewer
213
		// since it is our only connection to the merge viewer
214
		if (editorInput instanceof SaveablesCompareEditorInput) {
215
			return ((SaveablesCompareEditorInput) editorInput).isSaveNeeded(this);
216
		}
209
		return editorInput.isSaveNeeded();
217
		return editorInput.isSaveNeeded();
210
	}
218
	}
211
	
219
	
Lines 232-237 Link Here
232
	 * @see org.eclipse.ui.Saveable#getName()
240
	 * @see org.eclipse.ui.Saveable#getName()
233
	 */
241
	 */
234
	public String getName() {
242
	public String getName() {
243
		// When we compare two files with each other we need to know the exact
244
		// name of each of the files, not the name taken from the input. Input
245
		// gives the name based on the main element of the input. The way how
246
		// the main element is calculated is described in method
247
		// org.eclipse.team.internal.ui.mapping.AbstractCompareInput#getMainElement()
248
		// See bug 273450.
249
		if (fileElement.equals(input.getLeft())) {
250
			return input.getLeft().getName();
251
		}
252
		if (fileElement.equals(input.getRight())) {
253
			return input.getRight().getName();
254
		}
235
		return input.getName();
255
		return input.getName();
236
	}
256
	}
237
257
Lines 345-348 Link Here
345
		}
365
		}
346
		return false;
366
		return false;
347
	}
367
	}
368
369
	public boolean isSaving() {
370
		return isSaving;
371
	}
348
}
372
}
(-)src/org/eclipse/team/internal/ui/synchronize/SaveablesCompareEditorInput.java (-4 / +36 lines)
Lines 126-135 Link Here
126
						closed = closeEditor(true);
126
						closed = closeEditor(true);
127
					}
127
					}
128
					if (!closed) {
128
					if (!closed) {
129
						// The editor was closed either because the compare
129
						// The editor was not closed either because the compare
130
						// input still has changes
130
						// input still has changes or because the editor input
131
						// or because the editor input is dirty. In either case,
131
						// is dirty. In either case, fire the changes
132
						// fire the changes
133
						// to the registered listeners
132
						// to the registered listeners
134
						propogateInputChange();
133
						propogateInputChange();
135
					}
134
					}
Lines 359-364 Link Here
359
		return super.isDirty();
358
		return super.isDirty();
360
	}
359
	}
361
360
361
	/* package */ boolean isSaveNeeded(Saveable saveable) {
362
		// Method gives information if the Saveable given as a parameter needs
363
		// to be saved. Parameter arg can be either equal to fLeftSaveable or to
364
		// fRightSaveable. If the parameter is null or differs from both left
365
		// and right Saveable then default isSaveNeeded() is called. Default
366
		// method isSaveNeeded() is not aware which Saveable we wish to check
367
		// therefore it returns the state of the whole CompareEditorInput.
368
		// Whenever possible this method should be called instead of default
369
		// isSaveNeeded(). See bug 273450.
370
		if (saveable == null) {
371
			return isSaveNeeded();
372
		}
373
		if (saveable.equals(fLeftSaveable)) {
374
			return isLeftSaveNeeded();
375
		}
376
		if (saveable.equals(fRightSaveable)) {
377
			return isRightSaveNeeded();
378
		}
379
		return isSaveNeeded();
380
	}
381
382
	void saveChanges(IProgressMonitor monitor, Saveable saveable)
383
			throws CoreException {
384
		if (saveable.equals(fLeftSaveable)) {
385
			flushLeftViewers(monitor);
386
			return;
387
		} else if (saveable.equals(fRightSaveable)) {
388
			flushRightViewers(monitor);
389
			return;
390
		}
391
		Assert.isTrue(false, "invalid saveable parameter"); //$NON-NLS-1$
392
	}
393
362
	/**
394
	/**
363
	 * Close the editor if it is not dirty. If it is still dirty, let the
395
	 * Close the editor if it is not dirty. If it is still dirty, let the
364
	 * content merge viewer handle the compare input change.
396
	 * content merge viewer handle the compare input change.

Return to bug 273450