Skip to main content
summaryrefslogblamecommitdiffstats
blob: 91233056da0133c7d1d6bf4b76f235c2d92c33d5 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
   

                                       









                                 
                           
                            













                                          



                                          


                                                   
                                    
                                      
                                                   


                                              
                                               


                                                   
                              



                                                                     

                                                                                        






                                                                                          
                                                                            


















                                                                                                              
                 


                                             




                                                
                                                             
                                                  
                                 

                                                                                                      

                                           

                  
                                                                                  
                                                                  








                                             



















                                                                                                            
                                                                    






                                             

                                                                               
                                                                                     


                                                     


                  
                                 
                                                            




                                                         
                                              



                                                                

                                                     
         



                                                                                        
                                         


                                                           
                                        
                                  
                                                          
                                             

                                   
         


                                                         
                                    
                                               
                                   
                                                
                                  

                                                                   









                                                                                            
                                                                                                 

                                                                                                 


                                                                                                      


                                                                                                       










                                                                                                   



                                                                   
                                                                                                                            


                                                                                  
                                                                                                                          



                                                                  







                                                                    
         
            











                                                                                                                              
                                                     























                                                                                                    


                                                                                











                                                                                          
                                                                                    
                                 
                                                               











                                                          












                                                                                                                       
                                                     
                 






                                                                                  

                                                              
                                                          
                                     

                                                                                                    
                                         
                                                                                
                  
 
                                 
                                        
                         
                                                        


                                                                                        

                                                                                                  
                          
                         
                                                                                
                                                                                           





                                                                                                       
                                 















                                                                                                                                                                 


                                                                                                  
                                                  
                                                                
                                          





                                                                        
                                                               
                                                                                                       
                          

                         
                                    













                                                                                              
                          





















                                                                                                                           
                                                                                                                        






                                                                  
                  






                                              
         

                                                                                          
                                                                                       



                                                     




                                                                          
            
                                                                          
                                                                         
           




                                                                                       
 







                                                                                              
                 
            

                                                                        



                                                           










                                                                            
                                                              


            










                                                                                                                 
                                              
















                                                                                                                                                  







                                                                                                          

















                                                                                                                                                                    









                                                                                                              
 
                                                      

                                                                                                  
                                                                                          
                  
                 
                                                                            


                                                                                                      
                                     
                                                     







                                                                                                              





















                                                                                                                                                                    





                                                              

                                                                                                   




















                                                                            
                                                                                         














                                                                                                               
                 

                                                                                                        

                                                                                      
                                                                                              
                                                                                                            

                                                                                           






                                                                                       
                                                              
                         
                                                                                               
                         











                                                                                                                                                                  






                                                                                                        





                                                                                                       
                                                                                                           
                                                                                                     
                                                     

                                                                    
                  
                 

                                                                                   



                                                                                      














                                                                                     
                                                                                                                                 






                                                            



                                                                     
                                                                                                                          


















                                                                                                                

          

                                                                                                                      















                                                                          



                                               



























                                                                                              
          

            
                                                       





                                                                                         
                 
                                                                


                                                                                                      
                                                                                                                              




                                                                                                                      
                                                                                                                         


                                
                 




























                                                                                            
                                      
                                                
                                                   



                                                                                       


                                    
                                                               



                                          












                                                                                                              



                                                                     













                                                                       

                                                                                         
                                            
                                                                                                


                                                                              
                                                                           


                                          
                                                                        
                                                 
                                                                            
                             
                                                                      
                                                                                 
                                             
                                                                                        



                                                              
                                                             








                                                                                                        

                                                                        
                                       
                                                         

                                       
                                                

                                                   
                                                 









                                                                 
                                 
                                                                                                               

                                                                                                                   
                                                                 





                                                                         

                          

          








                                                                   

                                                                

          
           
                                                                                  
            

                                           
                                     


                                                       
                                               
                         


                                                                                      
                         
                                        
                                                         
                                                                    
                                                                     


                                                                                          
                                                                                          
                                                                                                      

                                                                                           
                                                                                           
                                                                                                      



                                             
                                        
                  
                                           
                                                                                                                           
          










                                                                             
  
/*
 * (c) Copyright IBM Corp. 2000, 2001.
 * All Rights Reserved.
 */
package org.eclipse.compare;

import java.util.HashMap;
import java.util.ResourceBundle;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.HashSet;
import java.util.Calendar;
import java.io.InputStream;
import java.text.*;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Button;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.util.Assert;
import org.eclipse.jface.dialogs.IDialogConstants;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFileState;
import org.eclipse.core.runtime.CoreException;

import org.eclipse.compare.internal.*;
import org.eclipse.compare.structuremergeviewer.*;
import org.eclipse.compare.*;

/**
 * A dialog where one input element can be compared against
 * a list of historic variants (editions) of the same input element.
 * The dialog can be used to implement functions like "Compare/Replace with Version" or
 * "Compare/Replace from Local History" on workspace resources.
 * <p>
 * In addition it is possible to specify a subsection of the input element
 * (e.g. a method in a Java source file) by means of a "path".
 * In this case the dialog compares only the subsection (as specified by the path)
 * with the corresponding subsection in the list of editions.
 * Only those editions are shown where the subsection differs from the same subsection in
 * another edition thereby minimizing the number of presented variants.
 * This functionality can be used to implement "Replace from Local History"
 * for the Java language.
 * <p>
 * Subsections of an input element are determined by first finding an
 * <code>IStructureCreator</code> for the input's type.
 * Then the method <code>locate</code> is used to extract the subsection.
 * <p>
 * Each edition (variant in the list of variants) must implement the <code>IModificationDate</code> interface
 * so that the dialog can sort the editions and present them in a tree structure where every
 * node corresponds one day.
 * <p>
 * The functionality is surfaced in a single function <code>selectEdition</code>.
 * <p>
 * Clients may instantiate this class; it is not intended to be subclassed.
 * </p>
 *
 * @see IModificationDate
 * @see ITypedElement
 */
public class EditionSelectionDialog extends Dialog {
		
	/**
	 * An item in an underlying edition.
	 */
	private static class Pair {
		
		private ITypedElement fEdition;
		private ITypedElement fItem;
		private String fContent;
		private IStructureCreator fStructureCreator;
		private boolean fHasError= false;
				
		Pair(IStructureCreator structureCreator, ITypedElement edition, ITypedElement item) {
			fStructureCreator= structureCreator;
			fEdition= edition;
			fItem= item;
		}
		
		Pair(IStructureCreator structureCreator, ITypedElement edition) {
			this(structureCreator, edition, edition);
		}
		
		ITypedElement getEdition() {
			return fEdition;
		}

		ITypedElement getItem() {
			return fItem;
		}
		
		/**
		 * The content is lazily loaded
		 */
		private String getContent() {
			if (fContent == null) {
				if (fStructureCreator != null)
					fContent= fStructureCreator.getContents(fItem, false);
				else {
					if (fItem instanceof IStreamContentAccessor) {
						IStreamContentAccessor sca= (IStreamContentAccessor) fItem;
						try {
							InputStream is= sca.getContents();
							if (is != null)
								fContent= Utilities.readString(is);
						} catch (CoreException ex) {
						}
					}
				}
				if (fContent == null)
					fContent= ""; //$NON-NLS-1$
			}
			return fContent;
		}
		
		/**
		 * Compares content of item.
		 */
		public boolean equals(Object other) {
			if (other != null && other.getClass() == getClass()) {
				if (getContent().equals(((Pair)other).getContent()))
					return true;
			}
			return super.equals(other);
		}
	}
	
	// Configuration options
	private CompareConfiguration fCompareConfiguration;
	/** use a side-by-side compare viewer */
	private boolean fCompare= true;
	/** show target on right hand side */
	private boolean fTargetIsRight= false;
	/** hide entries which have identical content */
	private boolean fHideIdentical= true;
	/** add mode if true, otherwise replace mode */
	private boolean fAddMode= false;
	/** compare mode if true, otherwise replace/add mode */
	private boolean fCompareMode= false;
	/** perform structure compare on editions */
	private boolean fStructureCompare= false;
	
	/**
	 * Maps from members to their corresponding editions.
	 * Has only a single entry if dialog is used in "Replace" (and not "Add") mode.
	 */
	private HashMap fMemberEditions;
	/** The editions of the current selected member */
	private List fCurrentEditions;
	private Thread fThread;
	private ResourceBundle fBundle;
	private Pair fTargetPair;
	/** The selected edition in the edition viewer */
	private ITypedElement fSelectedItem;
	private String fTitleArg;
	private Image fTitleImage;
	
	// SWT controls
	private CompareViewerSwitchingPane fContentPane;
	private Button fCommitButton;
	private Table fMemberTable;
	private CompareViewerPane fMemberPane;
	private Tree fEditionTree;
	private CompareViewerPane fEditionPane;
	private Image fDateImage;
	private Image fTimeImage;
	private CompareViewerSwitchingPane fStructuredComparePane;
	
	/**
	 * Creates a new modal, resizable dialog.
	 * Various titles, icons, and labels are configured from the given resource bundle.
	 * The following resource keys are used:
	 * <pre>
	 *	key         type          description
	 *	title       String        dialog title
	 *	width       Integer       initial width of dialog
	 *	height      Integer       initial height of dialog
	 *	treeTitleFormat   MessageFormat pane title for edition tree; arg 0 is the target
	 *	dateIcon    String        icon for node in edition tree; path relative to plugin
	 *	timeIcon    String        icon for leaf in edition tree; path relative to plugin
	 *	todayFormat MessageFormat format string if date is todays date; arg 0 is date
	 *	yesterdayFormat MessageFormat format string if date is yesterdays date; arg 0 is date
	 *	dayFormat   MessageFormat format string if date is any other date; arg 0 is date
	 *	editionLabel String       label for editions side of compare viewer; arg 0 is the date
	 *	targetLabel  String       label for target side of compare viewer 
	 *  buttonLabel  String       label for OK button; default is IDialogConstants.OK_LABEL
	 * </pre>
	 *
	 * @param parent if not <code>null</code> the new dialog stays on top of this parent shell
	 * @param bundle <code>ResourceBundle</code> to configure the dialog
	 */
	public EditionSelectionDialog(Shell parent, ResourceBundle bundle) {
		super(parent);
		setShellStyle(SWT.CLOSE | SWT.APPLICATION_MODAL | SWT.RESIZE);
		
		fBundle= bundle;
	
		fCompareConfiguration= new CompareConfiguration();
		fCompareConfiguration.setLeftEditable(false);
		fCompareConfiguration.setRightEditable(false);
				
		String iconName= Utilities.getString(fBundle, "dateIcon", "obj16/day_obj.gif"); //$NON-NLS-2$ //$NON-NLS-1$
		ImageDescriptor id= CompareUIPlugin.getImageDescriptor(iconName);
		if (id != null)
			fDateImage= id.createImage();
		iconName= Utilities.getString(fBundle, "timeIcon", "obj16/resource_obj.gif"); //$NON-NLS-1$ //$NON-NLS-2$
		id= CompareUIPlugin.getImageDescriptor(iconName);
		if (id != null)
			fTimeImage= id.createImage();
	}
		
	public void setEditionTitleArgument(String titleArgument) {
		fTitleArg= titleArgument;
	}
	
	public void setEditionTitleImage(Image titleImage) {
		fTitleImage= titleImage;
	}
	
	/**
	 * Select the previous edition.
	 *
	 * @param target the input object against which the editions are compared; must not be <code>null</code>
	 * @param editions the list of editions (element type: <code>ITypedElement</code>s)
	 * @param path If <code>null</code> dialog shows full input; if non <code>null</code> it extracts a subsection
	 * @return returns the selected edition or <code>null</code> if dialog was cancelled.
	 * The returned <code>ITypedElement</code> is one of the original editions
	 * if <code>path</code> was <code>null</code>; otherwise
	 * it is an <code>ITypedElement</code> returned from <code>IStructureCreator.locate(path, item)</code>
	 */
	public ITypedElement selectPreviousEdition(final ITypedElement target, ITypedElement[] inputEditions, Object ppath) {
		Assert.isNotNull(target);
		fTargetPair= new Pair(null, target);
		
		// sort input editions
		final int count= inputEditions.length;
		final IModificationDate[] editions= new IModificationDate[count];
		for (int i= 0; i < count; i++)
			editions[i]= (IModificationDate) inputEditions[i];
		if (count > 1)
			internalSort(editions, 0, count-1);
			
		// find StructureCreator if ppath is not null
		IStructureCreator structureCreator= null;
		if (ppath != null) {
			String type= target.getType();
			IStructureCreatorDescriptor scd= CompareUIPlugin.getStructureCreator(type);
			if (scd != null)
				structureCreator= scd.createStructureCreator();
		}

		if (fAddMode) {
			// does not work in add mode
			return null;
		}
			
		if (structureCreator != null) {
			Pair pair= createPair(structureCreator, ppath, target);
			if (pair != null)
				fTargetPair= pair;
			else
				ppath= null;	// couldn't extract item because of error
		}
					
		// from front (newest) to back (oldest)
		for (int i= 0; i < count; i++) {
				
			ITypedElement edition= (ITypedElement) editions[i];
			Pair pair= null;
			
			if (structureCreator != null && ppath != null) {
				// extract sub element from edition
				pair= createPair(structureCreator, ppath, edition);
			} else {
				pair= new Pair(null, edition);
			}
			
			if (! fTargetPair.equals(pair)) {
				return pair.fItem;
			}
		}
		
		// nothing found
		return null;
	}
	
	/**
	 * Presents this modal dialog with the functionality described in the class comment above.
	 *
	 * @param target the input object against which the editions are compared; must not be <code>null</code>
	 * @param editions the list of editions (element type: <code>ITypedElement</code>s)
	 * @param path If <code>null</code> dialog shows full input; if non <code>null</code> it extracts a subsection
	 * @return returns the selected edition or <code>null</code> if dialog was cancelled.
	 * The returned <code>ITypedElement</code> is one of the original editions
	 * if <code>path</code> was <code>null</code>; otherwise
	 * it is an <code>ITypedElement</code> returned from <code>IStructureCreator.locate(path, item)</code>
	 */
	public ITypedElement selectEdition(final ITypedElement target, ITypedElement[] inputEditions, Object ppath) {
		
		Assert.isNotNull(target);
		fTargetPair= new Pair(null, target);
		
		// sort input editions
		final int count= inputEditions.length;
		final IModificationDate[] editions= new IModificationDate[count];
		for (int i= 0; i < count; i++)
			editions[i]= (IModificationDate) inputEditions[i];
		if (count > 1)
			internalSort(editions, 0, count-1);
			
		// find StructureCreator if ppath is not null
		IStructureCreator structureCreator= null;
		if (ppath != null) {
			String type= target.getType();
			IStructureCreatorDescriptor scd= CompareUIPlugin.getStructureCreator(type);
			if (scd != null)
				structureCreator= scd.createStructureCreator();
		}

		if (!fAddMode) {
			// replace mode
			
			if (structureCreator != null) {
				Pair pair= createPair(structureCreator, ppath, target);
				if (pair != null)
					fTargetPair= pair;
				else
					ppath= null;	// couldn't extract item because of error
			}
			
			// set the left and right labels for the compare viewer
			String targetLabel= getTargetLabel(target, fTargetPair.getItem());
			if (fTargetIsRight)
				fCompareConfiguration.setRightLabel(targetLabel);
			else
				fCompareConfiguration.setLeftLabel(targetLabel);
			
			if (structureCreator != null && ppath != null) {	// extract sub element
				
				final IStructureCreator sc= structureCreator;
				final Object path= ppath;
				
				// construct the comparer thread
				// and perform the background extract
				fThread= new Thread() {
					public void run() {
																				
						// from front (newest) to back (oldest)
						for (int i= 0; i < count; i++) {
								
							if (fEditionTree == null || fEditionTree.isDisposed())
								break;
							ITypedElement edition= (ITypedElement) editions[i];
							
							// extract sub element from edition
							Pair pair= createPair(sc, path, edition);
							if (pair != null)
								sendPair(pair);
						}
						sendPair(null);
					}
				};
			} else {
				// create tree widget
				create();
				
				// from front (newest) to back (oldest)
				for (int i= 0; i < count; i++)
					addMemberEdition(new Pair(null, (ITypedElement) editions[i]));
			}
			
		} else {
			// add mode
			final Object container= ppath;
			Assert.isNotNull(container);
								
			if (structureCreator == null)
				return null;	// error
		
			// extract all elements of container
			final HashSet current= new HashSet();
			IStructureComparator sco= structureCreator.locate(container, target);
			if (sco != null) {
				Object[] children= sco.getChildren();
				if (children != null)
					for (int i= 0; i < children.length; i++)
						current.add(children[i]);
			}
			
			final IStructureCreator sc= structureCreator;
			
			// construct the comparer thread
			// and perform the background extract
			fThread= new Thread() {
				public void run() {
					
					// from front (newest) to back (oldest)
					for (int i= 0; i < count; i++) {
							
						if (fEditionTree == null || fEditionTree.isDisposed())
							break;
						ITypedElement edition= (ITypedElement) editions[i];
						
						IStructureComparator sco2= sc.locate(container, edition);
						if (sco2 != null) {
							Object[] children= sco2.getChildren();
							if (children != null) {
								for (int i2= 0; i2 < children.length; i2++) {
									ITypedElement child= (ITypedElement) children[i2];
									if (!current.contains(child))
										sendPair(new Pair(sc, edition, child));
								}
							}
						}
					}
					sendPair(null);
				}
			};
		}
		
		open();
		
		if (getReturnCode() == OK)
			return fSelectedItem;
		return null;
	}
	
	private Pair createPair(IStructureCreator sc, Object path, ITypedElement input) {
		IStructureComparator scmp= sc.locate(path, input);
		if (scmp == null && sc.getStructure(input) == null) {	// parse error
			Pair p= new Pair(sc, input);
			p.fHasError= true;
			return p;
		}
		if (scmp instanceof ITypedElement)
			return new Pair(sc, input, (ITypedElement) scmp);
		return null;
	}

	/**
	 * Controls whether identical entries are shown or not (default).
	 * This method must be called before <code>selectEdition</code>.
	 *
	 * @param hide if true identical entries are hidden; otherwise they are shown.
	 */
	public void setHideIdenticalEntries(boolean hide) {
		fHideIdentical= hide;
	}

	/**
	 * Controls whether workspace target is on the left (the default) or right hand side.
	 *
	 * @param isRight if true target is shown on right hand side.
	 */
	public void setTargetIsRight(boolean isRight) {
		fTargetIsRight= isRight;
	}
		
	/**
	 * Controls whether the EditionSelectionDialog is in 'add' mode
	 * or 'replace' mode (the default).
	 *
	 * @param addMode if true dialog is in 'add' mode.
	 */
	public void setAddMode(boolean addMode) {
		fAddMode= addMode;
	}
	
	/**
	 * Controls whether the EditionSelectionDialog is in 'compare' mode
	 * or 'add/replace' (the default) mode. 
	 *
	 * @param addMode if true dialog is in 'add' mode.
	 */
	public void setCompareMode(boolean compareMode) {
		fCompareMode= compareMode;
		fStructureCompare= fCompareMode && !fAddMode;
	}
	
	/**
	 * Returns the input target that has been specified with the most recent call
	 * to <code>selectEdition</code>. If a not <code>null</code> path was specified this method
	 * returns a subsection of this target (<code>IStructureCreator.locate(path, target)</code>)
	 * instead of the input target.
	 * <p>
	 * For example if the <code>target</code> is a Java compilation unit and <code>path</code> specifies
	 * a method, the value returned from <code>getTarget</code> will be the method not the compilation unit.
	 *
	 * @return the last specified target or a subsection thereof.
	 */
	public ITypedElement getTarget() {
		return fTargetPair.getItem();
	}
 	
 	/**
 	 * Returns a label for identifying the target side of a compare viewer.
 	 * This implementation extracts the value for the key "targetLabel" from the resource bundle
 	 * and passes it as the format argument to <code>MessageFormat.format</code>.
 	 * The single format argument for <code>MessageFormat.format</code> ("{0}" in the format string)
 	 * is the name of the given input element.
	 * <p>
	 * Subclasses may override to create their own label.
	 * </p>
 	 *
 	 * @param target the target element for which a label must be returned
 	 * @param item if a path has been specified in <code>selectEdition</code> a sub element of the given target; otherwise the same as target
 	 * @return a label the target side of a compare viewer
  	 */
	protected String getTargetLabel(ITypedElement target, ITypedElement item) {
		String format= null;
		if (target instanceof ResourceNode)
			format= Utilities.getString(fBundle, "workspaceTargetLabel", null); //$NON-NLS-1$
		if (format == null)
			format= Utilities.getString(fBundle, "targetLabel"); //$NON-NLS-1$
		if (format == null)
			format= "x{0}"; //$NON-NLS-1$
		
		return MessageFormat.format(format, new Object[] { target.getName() });
	}
	
 	/**
 	 * Returns a label for identifying the edition side of a compare viewer.
 	 * This implementation extracts the value for the key "editionLabel" from the resource bundle
 	 * and passes it as the format argument to <code>MessageFormat.format</code>.
 	 * The single format argument for <code>MessageFormat.format</code> ("{0}" in the format string)
 	 * is the formatted modification date of the given input element.
 	 * <p>
	 * Subclasses may override to create their own label.
	 * </p>
	 *
	 * @param selectedEdition the selected edition for which a label must be returned
 	 * @param item if a path has been specified in <code>selectEdition</code> a sub element of the given selectedEdition; otherwise the same as selectedEdition
 	 * @return a label the edition side of a compare viewer
  	 */
	protected String getEditionLabel(ITypedElement selectedEdition, ITypedElement item) {
		String format= null;
		if (selectedEdition instanceof ResourceNode)
			format= Utilities.getString(fBundle, "workspaceEditionLabel", null);	//$NON-NLS-1$
		else if (selectedEdition instanceof HistoryItem)
			format= Utilities.getString(fBundle, "historyEditionLabel", null);	//$NON-NLS-1$
		if (format == null)
			format= Utilities.getString(fBundle, "editionLabel");	//$NON-NLS-1$
		if (format == null)
			format= "x{0}";	//$NON-NLS-1$
		

		String date= "";	//$NON-NLS-1$
		if (selectedEdition instanceof IModificationDate) {
			long modDate= ((IModificationDate)selectedEdition).getModificationDate();
			date= DateFormat.getDateTimeInstance().format(new Date(modDate));
		}
		
		return MessageFormat.format(format, new Object[] { date });
	}
	
	protected String getShortEditionLabel(ITypedElement edition, ITypedElement item, Date date) {
		String format= null;
		if (edition instanceof ResourceNode)
			format= Utilities.getString(fBundle, "workspaceTreeFormat", null);	//$NON-NLS-1$
		if (format == null)
			format= Utilities.getString(fBundle, "treeFormat", null);	//$NON-NLS-1$
		if (format == null)
			format= "x{0}"; //$NON-NLS-1$

		String ds= DateFormat.getTimeInstance().format(date);
		return MessageFormat.format(format, new Object[] { ds });
	}
	
 	/**
 	 * Returns an image for identifying the edition side of a compare viewer.
 	 * This implementation extracts the value for the key "editionLabel" from the resource bundle
 	 * and passes it as the format argument to <code>MessageFormat.format</code>.
 	 * The single format argument for <code>MessageFormat.format</code> ("{0}" in the format string)
 	 * is the formatted modification date of the given input element.
 	 * <p>
	 * Subclasses may override to create their own label.
	 * </p>
	 *
	 * @param selectedEdition the selected edition for which a label must be returned
 	 * @param item if a path has been specified in <code>selectEdition</code> a sub element of the given selectedEdition; otherwise the same as selectedEdition
 	 * @return a label the edition side of a compare viewer
  	 */
	protected Image getEditionImage(ITypedElement selectedEdition, ITypedElement item) {
		if (selectedEdition instanceof ResourceNode)
			return selectedEdition.getImage();
		if (selectedEdition instanceof HistoryItem)
			return fTimeImage;
		return null;
	}
	
	/* (non Javadoc)
	 * Returns the size initialized with the constructor.
	 */
	protected Point getInitialSize() {
		Point size= new Point(Utilities.getInteger(fBundle, "width", 0), //$NON-NLS-1$
					Utilities.getInteger(fBundle, "height", 0)); //$NON-NLS-1$
		
		Shell shell= getParentShell();
		if (shell != null) {
			Point parentSize= shell.getSize();
			if (size.x <= 0)
				size.x= parentSize.x-300;
			if (size.y <= 0)
				size.y= parentSize.y-200;
		}
		if (size.x < 700)
			size.x= 700;
		if (size.y < 500)
			size.y= 500;
		return size;
	}

 	/* (non Javadoc)
 	 * Creates SWT control tree.
 	 */
	protected synchronized Control createDialogArea(Composite parent) {
		
		getShell().setText(Utilities.getString(fBundle, "title")); //$NON-NLS-1$
		
		Splitter vsplitter= new Splitter(parent,  SWT.VERTICAL);
		vsplitter.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL
					| GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL));

		vsplitter.addDisposeListener(
			new DisposeListener() {
				public void widgetDisposed(DisposeEvent e) {
					if (fDateImage != null)
						fDateImage.dispose();
					if (fTimeImage != null)
						fTimeImage.dispose();
				}
			}
		);
		
		if (fAddMode) {
			// we need two panes: the left for the elements, the right one for the editions
			Splitter hsplitter= new Splitter(vsplitter,  SWT.HORIZONTAL);
			
			fMemberPane= new CompareViewerPane(hsplitter, SWT.BORDER | SWT.FLAT);
			fMemberPane.setText(Utilities.getString(fBundle, "memberPaneTitle")); //$NON-NLS-1$
			fMemberTable= new Table(fMemberPane, SWT.H_SCROLL + SWT.V_SCROLL);
			fMemberTable.addSelectionListener(
				new SelectionAdapter() {
					public void widgetSelected(SelectionEvent e) {
						handleMemberSelect(e.item);
					}
				}
			);
			
			fMemberPane.setContent(fMemberTable);
			
			fEditionPane= new CompareViewerPane(hsplitter, SWT.BORDER | SWT.FLAT);
		} else {
			if (fStructureCompare) {
				// we need two panes: the left for the elements, the right one for the structured diff
				Splitter hsplitter= new Splitter(vsplitter,  SWT.HORIZONTAL);
				
				fEditionPane= new CompareViewerPane(hsplitter, SWT.BORDER | SWT.FLAT);
				fStructuredComparePane= new CompareViewerSwitchingPane(hsplitter, SWT.BORDER | SWT.FLAT, true) {
					protected Viewer getViewer(Viewer oldViewer, Object input) {
						if (input instanceof ICompareInput)
							return CompareUIPlugin.findStructureViewer(oldViewer, (ICompareInput)input, this, fCompareConfiguration);
						return null;
					}
				};
				fStructuredComparePane.addSelectionChangedListener(
					new ISelectionChangedListener() {
						public void selectionChanged(SelectionChangedEvent e) {
							feedInput2(e.getSelection());
						}
					}
				);
			} else {
				// only a single pane showing the editions
				fEditionPane= new CompareViewerPane(vsplitter, SWT.BORDER | SWT.FLAT);
			}
			if (fTitleArg == null)
				fTitleArg= fTargetPair.getItem().getName();
			String titleFormat= Utilities.getString(fBundle, "treeTitleFormat"); //$NON-NLS-1$
			String title= MessageFormat.format(titleFormat, new String[] { fTitleArg });
			fEditionPane.setText(title);
			if (fTitleImage != null)
				fEditionPane.setImage(fTitleImage);
		}
		
		fEditionTree= new Tree(fEditionPane, SWT.H_SCROLL + SWT.V_SCROLL);
		fEditionTree.addSelectionListener(
			new SelectionAdapter() {
//				public void widgetDefaultSelected(SelectionEvent e) {
//					handleDefaultSelected();
//				}
				public void widgetSelected(SelectionEvent e) {
					feedInput(e.item);
				}
			}
		);
		fEditionPane.setContent(fEditionTree);		
		
		// now start the thread (and forget about it)
		if (fThread != null) {
			fThread.start();
			fThread= null;
		}
		
		fContentPane= new CompareViewerSwitchingPane(vsplitter, SWT.NONE) {
			protected Viewer getViewer(Viewer oldViewer, Object input) {
				return CompareUIPlugin.findContentViewer(oldViewer, input, this, fCompareConfiguration);	
			}
		};
		vsplitter.setWeights(new int[] { 30, 70 });
				
		return vsplitter;
	}
	
	/* (non-Javadoc)
	 * Method declared on Dialog.
	 */
	protected void createButtonsForButtonBar(Composite parent) {
		String buttonLabel= Utilities.getString(fBundle, "buttonLabel", IDialogConstants.OK_LABEL); //$NON-NLS-1$
		if (fCompareMode) {
			// only a 'Done' button
			createButton(parent, IDialogConstants.CANCEL_ID, buttonLabel, false);
		} else {
			// a 'Cancel' and a 'Add/Replace' button
			fCommitButton= createButton(parent, IDialogConstants.OK_ID, buttonLabel, true);
			fCommitButton.setEnabled(false);
			createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
		}
	}

	/**
	 * Overidden to disable dismiss on double click in compare mode.
	 */
	protected void okPressed() {
		if (fCompareMode)
			;	// don't dismiss dialog
		else
			super.okPressed();
	}

	//---- private stuff ----------------------------------------------------------------------------------------
				
	/**
	 * Asynchroneously sends a Pair (or null) to the UI thread.
	 */
	private void sendPair(final Pair pair) {		
		if (fEditionTree != null && !fEditionTree.isDisposed()) {
			Display display= fEditionTree.getDisplay();
			display.asyncExec(
				new Runnable() {
					public void run() {
						addMemberEdition(pair);
					}
				}
			);
		}
	}

//	private void handleDefaultSelected() {
//		if (fSelectedItem != null)
//			okPressed();
//	}
	
	private static void internalSort(IModificationDate[] keys, int left, int right) { 
	
		int original_left= left;
		int original_right= right;
		
		IModificationDate mid= keys[(left + right) / 2]; 
		do { 
			while (keys[left].getModificationDate() > mid.getModificationDate())
				left++; 
			
			while (mid.getModificationDate() > keys[right].getModificationDate())
				right--; 
		
			if (left <= right) { 
				IModificationDate tmp= keys[left]; 
				keys[left]= keys[right]; 
				keys[right]= tmp;			
				left++; 
				right--; 
			} 
		} while (left <= right);
		
		if (original_left < right)
			internalSort(keys, original_left, right); 
		
		if (left < original_right)
			internalSort(keys, left, original_right); 
	}
	
	/**
	 * Adds the given Pair to the member editions.
	 * If HIDE_IDENTICAL is true the new Pair is only added if its contents
	 * is different from the preceeding Pair.
	 * If the argument is <code>null</code> the message "No Editions found" is shown
	 * in the member or edition viewer.
	 */
	private void addMemberEdition(Pair pair) {
		
		if (pair == null) {	// end of list of pairs
			if (fMemberTable != null) {
				if (!fMemberTable.isDisposed() && fMemberTable.getItemCount() == 0) {
					TableItem ti= new TableItem(fMemberTable, SWT.NONE);
					ti.setText(Utilities.getString(fBundle, "noAdditionalMembersMessage")); //$NON-NLS-1$
				}
				return;
			}			
			if (fEditionTree != null && !fEditionTree.isDisposed() && fEditionTree.getItemCount() == 0) {
				TreeItem ti= new TreeItem(fEditionTree, SWT.NONE);
				ti.setText(Utilities.getString(fBundle, "notFoundInLocalHistoryMessage")); //$NON-NLS-1$
			}
			return;
		}
		
		if (fMemberEditions == null)
			fMemberEditions= new HashMap();
		
		ITypedElement item= pair.getItem();
		List editions= (List) fMemberEditions.get(item);
		if (editions == null) {
			editions= new ArrayList();
			fMemberEditions.put(item, editions);
			if (fMemberTable != null && !fMemberTable.isDisposed()) {
				ITypedElement te= (ITypedElement)item;
				String name= te.getName();
				
				// find position
				TableItem[] items= fMemberTable.getItems();
				int where= items.length;
				for (int i= 0; i < where; i++) {
					String n= items[i].getText();
					if (n.compareTo(name) > 0) {
						where= i;
						break;
					}
				}
				
				TableItem ti= new TableItem(fMemberTable, where, SWT.NULL);
				ti.setImage(te.getImage());
				ti.setText(name);
				ti.setData(editions);
			}
		}
		if (fHideIdentical) {
			Pair last= fTargetPair;
			int size= editions.size();
			if (size > 0)
				last= (Pair) editions.get(size-1);
			if (last != null && last.equals(pair))
				return;	// don't add since the new one is equal to old
		}
		editions.add(pair);
		
		if (!fAddMode || editions == fCurrentEditions)
			addEdition(pair);
	}
	
	/**
	 * Returns the number of s since Jan 1st, 1970.
	 * The given date is converted to GMT and daylight saving is taken into account too.
	 */
	private long dayNumber(long date) {
		int ONE_DAY_MS= 24*60*60 * 1000; // one day in milli seconds
		
		Calendar calendar= Calendar.getInstance();
		long localTimeOffset= calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
		
		return (date + localTimeOffset) / ONE_DAY_MS;
	}
	
	/**
	 * Adds the given Pair to the edition tree.
	 * It takes care of creating tree nodes for different dates.
	 */
	private void addEdition(Pair pair) {
		if (fEditionTree == null || fEditionTree.isDisposed())
			return;
		
		// find last day
		TreeItem[] days= fEditionTree.getItems();
		TreeItem lastDay= null;
		if (days.length > 0)
			lastDay= days[days.length-1];
		
		boolean first= lastDay == null;
		
		ITypedElement edition= pair.getEdition();
		ITypedElement item= pair.getItem();
		
		long ldate= ((IModificationDate)edition).getModificationDate();		
		long day= dayNumber(ldate);
		Date date= new Date(ldate);
		if (lastDay == null || day != dayNumber(((Date)lastDay.getData()).getTime())) {
			lastDay= new TreeItem(fEditionTree, SWT.NONE);
			lastDay.setImage(fDateImage);
			String df= DateFormat.getDateInstance().format(date);
			long today= dayNumber(System.currentTimeMillis());
			
			String formatKey;
			if (day == today)
				formatKey= "todayFormat"; //$NON-NLS-1$
			else if (day == today-1)
				formatKey= "yesterdayFormat"; //$NON-NLS-1$
			else
				formatKey= "dayFormat"; //$NON-NLS-1$
			String pattern= Utilities.getString(fBundle, formatKey);
			if (pattern != null)
				df= MessageFormat.format(pattern, new String[] { df });
			lastDay.setText(df);
			lastDay.setData(date);
		}
		TreeItem ti= new TreeItem(lastDay, SWT.NONE);
		ti.setImage(getEditionImage(edition, item));
		
		String s= getShortEditionLabel(edition, item, date);
		if (pair.fHasError) {
			String pattern= Utilities.getString(fBundle, "parseErrorFormat"); //$NON-NLS-1$
			s= MessageFormat.format(pattern, new String[] { s } );
		}
		ti.setText(s);
		
		ti.setData(pair);
		if (first) {
			fEditionTree.setSelection(new TreeItem[] {ti});
			if (!fAddMode)
				fEditionTree.setFocus();
			feedInput(ti);
		}
		if (first) // expand first node
			lastDay.setExpanded(true);
	}
						
	/**
	 * Feeds selection from member viewer to edition viewer.
	 */
	private void handleMemberSelect(Widget w) {
		Object data= w.getData();
		if (data instanceof List) {
			List editions= (List) data;
			if (editions != fCurrentEditions) {
				fCurrentEditions= editions;
				fEditionTree.removeAll();
				
				String pattern= Utilities.getString(fBundle, "treeTitleFormat"); //$NON-NLS-1$
				String title= MessageFormat.format(pattern, new Object[] { ((Item)w).getText() });
				fEditionPane.setText(title);
								
				Iterator iter= editions.iterator();
				while (iter.hasNext()) {
					Object item= iter.next();
					if (item instanceof Pair)
						addEdition((Pair) item);
				}
			}
		}
	}
	
	private void setInput(Object input) {
		if (!fCompare && input instanceof ICompareInput) {
			ICompareInput ci= (ICompareInput) input;
			if (fTargetIsRight)
				input= ci.getLeft();
			else
				input= ci.getRight();
		}
		fContentPane.setInput(input);
		if (fStructuredComparePane != null)
			fStructuredComparePane.setInput(input);
	}
	
	/*
	 * Feeds selection from edition viewer to content (and structure) viewer.
	 */
	private void feedInput(Widget w) {
		Object input= w.getData();
		boolean isOK= false;
		if (input instanceof Pair) {
			Pair pair= (Pair) input;
			fSelectedItem= pair.getItem();
			isOK= !pair.fHasError;
			
			ITypedElement edition= pair.getEdition();
			String editionLabel= getEditionLabel(edition, fSelectedItem);
			Image editionImage= getEditionImage(edition, fSelectedItem);
			
			if (fAddMode) {
				setInput(fSelectedItem);
				fContentPane.setText(editionLabel);
				fContentPane.setImage(editionImage);
			} else {
				if (fTargetIsRight) {
					fCompareConfiguration.setLeftLabel(editionLabel);
					fCompareConfiguration.setLeftImage(editionImage);
					setInput(new DiffNode(fSelectedItem, fTargetPair.getItem()));
				} else {
					fCompareConfiguration.setRightLabel(editionLabel);
					fCompareConfiguration.setRightImage(editionImage);
					setInput(new DiffNode(fTargetPair.getItem(), fSelectedItem));
				}
			}
		} else {
			fSelectedItem= null;
			setInput(null);
		}
		if (fCommitButton != null)
			fCommitButton.setEnabled(isOK && fSelectedItem != null && fTargetPair.getItem() != fSelectedItem);
	}
	
	/*
	 * Feeds selection from structure viewer to content viewer.
	 */
	private void feedInput2(ISelection sel) {
		if (sel instanceof IStructuredSelection) {
			IStructuredSelection ss= (IStructuredSelection) sel;
			if (ss.size() == 1)
				fContentPane.setInput(ss.getFirstElement());
		}
	}
}

Back to the top