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 / +132 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.internalIsLeftDirty()) {
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.internalIsRightDirty()) {
1113
				if (fRightDirtyViewer == null) {
1114
					fRightDirtyViewer = cmv;
1115
				}
1116
			}
1117
		} else {
1118
			if (!cmv.internalIsLeftDirty()) {
1119
				fLeftDirtyViewer = null;
1120
			}
1121
			if (!cmv.internalIsRightDirty()) {
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
1141
	/* (non-Javadoc)
1241
	/* (non-Javadoc)
1142
	 * @see org.eclipse.compare.ICompareContainer#addCompareInputChangeListener(org.eclipse.compare.structuremergeviewer.ICompareInput, org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
1242
	 * @see org.eclipse.compare.ICompareContainer#addCompareInputChangeListener(org.eclipse.compare.structuremergeviewer.ICompareInput, org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
1143
	 */
1243
	 */
(-)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 (-73 / +95 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.ISavingSaveable;
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 1215-1221 Link Here
1215
	public final void flush(IProgressMonitor monitor) {
1166
	public final void flush(IProgressMonitor monitor) {
1216
		flushContent(getInput(), monitor);
1167
		flushContent(getInput(), monitor);
1217
	}
1168
	}
1218
	
1169
1219
	/**
1170
	/**
1220
	 * Flush the modified content back to input elements via the content provider.
1171
	 * Flush the modified content back to input elements via the content provider.
1221
	 * The provided input may be the current input of the viewer or it may be
1172
	 * The provided input may be the current input of the viewer or it may be
Lines 1227-1257 Link Here
1227
	 * @since 3.3
1178
	 * @since 3.3
1228
	 */
1179
	 */
1229
	protected void flushContent(Object input, IProgressMonitor monitor) {
1180
	protected void flushContent(Object input, IProgressMonitor monitor) {
1230
				
1181
		flushLeftSide(input, monitor);
1231
		// write back modified contents
1182
		flushRightSide(input, monitor);
1232
		IMergeViewerContentProvider content= (IMergeViewerContentProvider) getContentProvider();
1183
	}
1233
		
1184
1234
		boolean leftEmpty= content.getLeftContent(input) == null;
1185
1235
		boolean rightEmpty= content.getRightContent(input) == null;
1186
	void flushLeftSide(Object input, IProgressMonitor monitor) {
1187
		IMergeViewerContentProvider content = (IMergeViewerContentProvider) getContentProvider();
1188
1189
		boolean rightEmpty = content.getRightContent(input) == null;
1236
1190
1237
		if (getCompareConfiguration().isLeftEditable() && isLeftDirty()) {
1191
		if (getCompareConfiguration().isLeftEditable() && isLeftDirty()) {
1238
			byte[] bytes= getContents(true);
1192
			byte[] bytes = getContents(true);
1239
			if (rightEmpty && bytes != null && bytes.length == 0)
1193
			if (rightEmpty && bytes != null && bytes.length == 0)
1240
				bytes= null;
1194
				bytes = null;
1241
			setLeftDirty(false);
1195
			setLeftDirty(false);
1242
			content.saveLeftContent(input, bytes);
1196
			content.saveLeftContent(input, bytes);
1243
		}
1197
		}
1244
		
1198
	}
1199
1200
	void flushRightSide(Object input, IProgressMonitor monitor) {
1201
		IMergeViewerContentProvider content = (IMergeViewerContentProvider) getContentProvider();
1202
1203
		boolean leftEmpty = content.getLeftContent(input) == null;
1204
1245
		if (getCompareConfiguration().isRightEditable() && isRightDirty()) {
1205
		if (getCompareConfiguration().isRightEditable() && isRightDirty()) {
1246
			byte[] bytes= getContents(false);
1206
			byte[] bytes = getContents(false);
1247
			if (leftEmpty && bytes != null && bytes.length == 0)
1207
			if (leftEmpty && bytes != null && bytes.length == 0)
1248
				bytes= null;
1208
				bytes = null;
1249
			setRightDirty(false);
1209
			setRightDirty(false);
1250
			content.saveRightContent(input, bytes);
1210
			content.saveRightContent(input, bytes);
1251
		}
1211
		}
1252
	}
1212
	}
1253
1213
1254
	/**
1214
	/**
1215
	 * @param monitor
1216
	 * @noreference This method is not intended to be referenced by clients.
1217
	 */
1218
	public void flushLeft(IProgressMonitor monitor) {
1219
		flushLeftSide(getInput(), monitor);
1220
	}
1221
1222
	/**
1223
	 * @param monitor
1224
	 * @noreference This method is not intended to be referenced by clients.
1225
	 */
1226
	public void flushRight(IProgressMonitor monitor) {
1227
		flushRightSide(getInput(), monitor);
1228
	}
1229
1230
	/**
1255
	 * Return the dirty state of the right side of this viewer.
1231
	 * Return the dirty state of the right side of this viewer.
1256
	 * @return the dirty state of the right side of this viewer
1232
	 * @return the dirty state of the right side of this viewer
1257
	 * @since 3.3
1233
	 * @since 3.3
Lines 1261-1266 Link Here
1261
	}
1237
	}
1262
1238
1263
	/**
1239
	/**
1240
	 * @return the dirty state of the right side of this viewer
1241
	 * @since 3.7
1242
	 * @noreference This method is not intended to be referenced by clients.
1243
	 */
1244
	public boolean internalIsRightDirty() {
1245
		return isRightDirty();
1246
	}
1247
1248
	/**
1264
	 * Return the dirty state of the left side of this viewer.
1249
	 * Return the dirty state of the left side of this viewer.
1265
	 * @return the dirty state of the left side of this viewer
1250
	 * @return the dirty state of the left side of this viewer
1266
	 * @since 3.3
1251
	 * @since 3.3
Lines 1270-1275 Link Here
1270
	}
1255
	}
1271
1256
1272
	/**
1257
	/**
1258
	 * @return the dirty state of the left side of this viewer
1259
	 * @since 3.7
1260
	 * @noreference This method is not intended to be referenced by clients.
1261
	 */
1262
	public boolean internalIsLeftDirty() {
1263
		return isLeftDirty();
1264
	}
1265
1266
	/**
1273
	 * Handle a change to the given input reported from an {@link org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener}.
1267
	 * Handle a change to the given input reported from an {@link org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener}.
1274
	 * This class registers a listener with its input and reports any change events through
1268
	 * This class registers a listener with its input and reports any change events through
1275
	 * this method. By default, this method prompts for any unsaved changes and then refreshes
1269
	 * this method. By default, this method prompts for any unsaved changes and then refreshes
Lines 1279-1285 Link Here
1279
	protected void handleCompareInputChange() {
1273
	protected void handleCompareInputChange() {
1280
		// before setting the new input we have to save the old
1274
		// before setting the new input we have to save the old
1281
		Object input = getInput();
1275
		Object input = getInput();
1282
		if (!fIsSaving && (isLeftDirty() || isRightDirty())) {
1276
		if (!isSaving() && (isLeftDirty() || isRightDirty())) {
1283
			
1277
			
1284
			if (Utilities.RUNNING_TESTS) {
1278
			if (Utilities.RUNNING_TESTS) {
1285
				if (Utilities.TESTING_FLUSH_ON_COMPARE_INPUT_CHANGE) {
1279
				if (Utilities.TESTING_FLUSH_ON_COMPARE_INPUT_CHANGE) {
Lines 1310-1320 Link Here
1310
					break;
1304
					break;
1311
				}
1305
				}
1312
			}
1306
			}
1307
			refresh();
1313
		}
1308
		}
1314
		refresh();
1315
	}
1309
	}
1316
1310
1317
	CompareHandlerService getCompareHandlerService() {
1311
	CompareHandlerService getCompareHandlerService() {
1318
		return fHandlerService;
1312
		return fHandlerService;
1319
	}
1313
	}
1314
1315
	/**
1316
	 * @return true if any of the Saveables is being saved
1317
	 */
1318
	private boolean isSaving() {
1319
		ICompareContainer container = fCompareConfiguration.getContainer();
1320
		ISaveablesSource source = null;
1321
		if (container instanceof ISaveablesSource) {
1322
			source = (ISaveablesSource) container;
1323
		} else {
1324
			IWorkbenchPart part = container.getWorkbenchPart();
1325
			if (part instanceof ISaveablesSource) {
1326
				source = (ISaveablesSource) part;
1327
			}
1328
		}
1329
		if (source != null) {
1330
			Saveable[] saveables = source.getSaveables();
1331
			for (int i = 0; i < saveables.length; i++) {
1332
				if (saveables[i] instanceof ISavingSaveable) {
1333
					ISavingSaveable saveable = (ISavingSaveable) saveables[i];
1334
					if (saveable.isSaving())
1335
						return true;
1336
				}
1337
			}
1338
		}
1339
		return false;
1340
	} 
1341
1320
}
1342
}
(-)compare/org/eclipse/compare/contentmergeviewer/TextMergeViewer.java (-8 / +25 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
	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 4855-4867 Link Here
4855
			}
4849
			}
4856
		}
4850
		}
4857
		
4851
		
4852
		if (!(content instanceof MergeViewerContentProvider) || isLeftDirty()) {
4853
			super.flushLeftSide(oldInput, monitor);
4854
		}
4855
	}
4856
	
4857
	void flushRightSide(Object oldInput, IProgressMonitor monitor){
4858
		IMergeViewerContentProvider content= getMergeContentProvider();
4859
		Object rightContent = content.getRightContent(oldInput);
4860
		
4858
		if (rightContent != null && getCompareConfiguration().isRightEditable() && isRightDirty()) {
4861
		if (rightContent != null && getCompareConfiguration().isRightEditable() && isRightDirty()) {
4859
			if (fRightContributor.hasSharedDocument(rightContent)) {
4862
			if (fRightContributor.hasSharedDocument(rightContent)) {
4860
				if (flush(fRightContributor))
4863
				if (flush(fRightContributor))
4861
					setRightDirty(false);
4864
					setRightDirty(false);
4862
			}
4865
			}
4863
		}
4866
		}
4864
		
4867
4868
		if (!(content instanceof MergeViewerContentProvider) || isRightDirty()) {
4869
			super.flushRightSide(oldInput, monitor);
4870
		}
4871
	}
4872
	
4873
	/* (non-Javadoc)
4874
	 * @see org.eclipse.compare.contentmergeviewer.ContentMergeViewer#flushContent(java.lang.Object, org.eclipse.core.runtime.IProgressMonitor)
4875
	 */
4876
	protected void flushContent(Object oldInput, IProgressMonitor monitor) {
4877
		flushLeftSide(oldInput, monitor);
4878
		flushRightSide(oldInput, monitor);
4879
4880
		IMergeViewerContentProvider content = getMergeContentProvider();
4881
4865
		if (!(content instanceof MergeViewerContentProvider) || isLeftDirty() || isRightDirty()) {
4882
		if (!(content instanceof MergeViewerContentProvider) || isLeftDirty() || isRightDirty()) {
4866
			super.flushContent(oldInput, monitor);
4883
			super.flushContent(oldInput, monitor);
4867
		}
4884
		}
(-)compare/org/eclipse/compare/internal/IFlushable2.java (+28 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
import org.eclipse.compare.contentmergeviewer.IFlushable;
14
import org.eclipse.core.runtime.IProgressMonitor;
15
16
/**
17
 * Interface which provides the ability to flush the contents from the specified
18
 * side of the viewer.
19
 * 
20
 * @see IFlushable
21
 * 
22
 * @since 3.7
23
 */
24
public interface IFlushable2 {
25
	void flushLeft(IProgressMonitor monitor);
26
27
	void flushRight(IProgressMonitor monitor);
28
}
(-)compare/org/eclipse/compare/internal/ISavingSaveable.java (+23 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
import org.eclipse.ui.Saveable;
14
15
/**
16
 * Interface defines API for checking if an object, preferably an instance of
17
 * {@link Saveable}, is being saved.
18
 * 
19
 * @since 3.7
20
 */
21
public interface ISavingSaveable {
22
	public boolean isSaving();
23
}
(-)src/org/eclipse/compare/tests/ContentMergeViewerTest.java (-5 / +12 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2008 IBM Corporation and others.
2
 * Copyright (c) 2008, 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 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 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 / +28 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.ISavingSaveable;
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, ISavingSaveable {
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
		// Return the name of the file element as held in the compare input
244
		if (fileElement.equals(input.getLeft())) {
245
			return input.getLeft().getName();
246
		}
247
		if (fileElement.equals(input.getRight())) {
248
			return input.getRight().getName();
249
		}
250
		// Fallback call returning name of the main non-null element of the input
251
		// see org.eclipse.team.internal.ui.mapping.AbstractCompareInput#getMainElement()
235
		return input.getName();
252
		return input.getName();
236
	}
253
	}
237
254
Lines 345-348 Link Here
345
		}
362
		}
346
		return false;
363
		return false;
347
	}
364
	}
365
366
	public boolean isSaving() {
367
		return isSaving;
368
	}
348
}
369
}
(-)src/org/eclipse/team/internal/ui/synchronize/SaveablesCompareEditorInput.java (-4 / +42 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 360-365 Link Here
360
	}
359
	}
361
360
362
	/**
361
	/**
362
	 * Returns <code>true</code> if the given saveable contains any unsaved
363
	 * changes. If the saveable doesn't match either left nor right side of the
364
	 * current editor input {@link CompareEditorInput#isSaveNeeded()} is called.
365
	 * <p>
366
	 * This method is preferred to {@link CompareEditorInput#isSaveNeeded()}.
367
	 * 
368
	 * @param the
369
	 *            the saveable to check
370
	 * @return <code>true</code> if there are changes that need to be saved
371
	 * @since 3.7
372
	 */
373
	boolean isSaveNeeded(Saveable saveable) {
374
		if (saveable == null) {
375
			return isSaveNeeded();
376
		}
377
		if (saveable.equals(fLeftSaveable)) {
378
			return isLeftSaveNeeded();
379
		}
380
		if (saveable.equals(fRightSaveable)) {
381
			return isRightSaveNeeded();
382
		}
383
		// Fallback call returning true if there are unsaved changes in either
384
		// left or right side
385
		return isSaveNeeded();
386
	}
387
388
	void saveChanges(IProgressMonitor monitor, Saveable saveable)
389
			throws CoreException {
390
		if (saveable.equals(fLeftSaveable)) {
391
			flushLeftViewers(monitor);
392
			return;
393
		} else if (saveable.equals(fRightSaveable)) {
394
			flushRightViewers(monitor);
395
			return;
396
		}
397
		Assert.isTrue(false, "invalid saveable parameter"); //$NON-NLS-1$
398
	}
399
400
	/**
363
	 * Close the editor if it is not dirty. If it is still dirty, let the
401
	 * Close the editor if it is not dirty. If it is still dirty, let the
364
	 * content merge viewer handle the compare input change.
402
	 * content merge viewer handle the compare input change.
365
	 * 
403
	 * 

Return to bug 273450