blob: b2742769002d15801c8f1d32d301df1a44a7a65b [file] [log] [blame]
package org.eclipse.compare.internal;
import java.io.*;
import java.text.*;
import java.util.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.jface.dialogs.*;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.compare.*;
public class AddFromHistoryDialog extends ResizableDialog {
static class HistoryInput implements ITypedElement, IStreamContentAccessor, IModificationDate {
IFile fFile;
IFileState fFileState;
HistoryInput(IFile file, IFileState fileState) {
fFile= file;
fFileState= fileState;
}
public InputStream getContents() throws CoreException {
return new BufferedInputStream(fFileState.getContents());
}
public String getName() {
return fFile.getName();
}
public String getType() {
return fFile.getFileExtension();
}
public Image getImage() {
return CompareUI.getImage(fFile);
}
public long getModificationDate() {
return fFileState.getModificationTime();
}
}
static class FileHistory {
private IFile fFile;
private IFileState[] fStates;
private int fSelected;
FileHistory(IFile file) {
fFile= file;
}
IFile getFile() {
return fFile;
}
IFileState[] getStates() {
if (fStates == null) {
try {
fStates= fFile.getHistory(new NullProgressMonitor());
} catch (CoreException ex) {
}
}
return fStates;
}
IFileState getSelectedState() {
return getStates()[fSelected];
}
void setSelected(IFileState state) {
for (int i= 0; i < fStates.length; i++) {
if (fStates[i] == state) {
fSelected= i;
return;
}
}
}
HistoryInput getHistoryInput() {
return new HistoryInput(fFile, getSelectedState());
}
boolean isSelected(int index) {
return index == fSelected;
}
}
private CompareConfiguration fCompareConfiguration;
private ArrayList fArrayList= new ArrayList();
private FileHistory fCurrentFileHistory;
// 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;
public AddFromHistoryDialog(Shell parent, ResourceBundle bundle) {
super(parent, bundle);
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 boolean select(IContainer root, IFile[] inputFiles) {
create(); // create widgets
String format= Utilities.getString(fBundle, "memberPaneTitle"); //$NON-NLS-1$
String title= MessageFormat.format(format, new Object[] { root.getName() });
fMemberPane.setImage(CompareUI.getImage(root));
fMemberPane.setText(title);
// sort input files
final int count= inputFiles.length;
final IFile[] files= new IFile[count];
for (int i= 0; i < count; i++)
files[i]= (IFile) inputFiles[i];
if (count > 1)
internalSort(files, 0, count-1);
String prefix= root.getFullPath().toString();
if (fMemberTable != null && !fMemberTable.isDisposed()) {
for (int i= 0; i < files.length; i++) {
IFile file= files[i];
String path= file.getFullPath().toString();
if (path.startsWith(prefix))
path= path.substring(prefix.length()+1);
TableItem ti= new TableItem(fMemberTable, SWT.NONE);
ti.setImage(CompareUI.getImage(file));
ti.setText(path);
ti.setData(new FileHistory(file));
}
}
open();
return (getReturnCode() == OK) && (fArrayList.size() > 0);
}
HistoryInput[] getSelected() {
HistoryInput[] selected= new HistoryInput[fArrayList.size()];
Iterator iter= fArrayList.iterator();
for (int i= 0; iter.hasNext(); i++) {
FileHistory h= (FileHistory) iter.next();
selected[i]= h.getHistoryInput();
}
return selected;
}
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();
}
}
);
// we need two panes: the left for the elements, the right one for the editions
Splitter hsplitter= new Splitter(vsplitter, SWT.HORIZONTAL);
Composite c= new Composite(hsplitter, SWT.NONE);
GridLayout layout= new GridLayout();
layout.marginWidth= 0;
layout.marginHeight= 2;
layout.verticalSpacing= 2;
layout.numColumns= 1;
c.setLayout(layout);
Label l1= new Label(c, SWT.NONE);
l1.setText(Utilities.getString(fBundle, "memberDescription")); //$NON-NLS-1$
fMemberPane= new CompareViewerPane(c, SWT.BORDER | SWT.FLAT);
GridData gd= new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
fMemberPane.setLayoutData(gd);
fMemberTable= new Table(fMemberPane, SWT.CHECK | SWT.H_SCROLL | SWT.V_SCROLL);
fMemberTable.addSelectionListener(
new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (e.detail == SWT.CHECK) {
if (e.item instanceof TableItem) {
TableItem ti= (TableItem) e.item;
if (ti.getChecked())
fArrayList.add(ti.getData());
else
fArrayList.remove(ti.getData());
if (fCommitButton != null)
fCommitButton.setEnabled(fArrayList.size() > 0);
}
} else {
handleMemberSelect(e.item);
}
}
}
);
fMemberPane.setContent(fMemberTable);
c= new Composite(hsplitter, SWT.NONE);
layout= new GridLayout();
layout.marginWidth= 0;
layout.marginHeight= 2;
layout.verticalSpacing= 2;
layout.numColumns= 1;
c.setLayout(layout);
Label l2= new Label(c, SWT.NONE);
l2.setText(Utilities.getString(fBundle, "editionDescription")); //$NON-NLS-1$
fEditionPane= new CompareViewerPane(c, SWT.BORDER | SWT.FLAT);
gd= new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
fEditionPane.setLayoutData(gd);
fEditionTree= new Tree(fEditionPane, SWT.H_SCROLL | SWT.V_SCROLL);
fEditionTree.addSelectionListener(
new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
feedContent(e.item);
}
}
);
fEditionPane.setContent(fEditionTree);
fContentPane= new CompareViewerSwitchingPane(vsplitter, SWT.BORDER | SWT.FLAT) {
protected Viewer getViewer(Viewer oldViewer, Object input) {
return CompareUIPlugin.findContentViewer(oldViewer, input, this, fCompareConfiguration);
}
};
vsplitter.setWeights(new int[] { 30, 70 });
return vsplitter;
}
/**
* Feeds selection from member viewer to edition viewer.
*/
private void handleMemberSelect(Widget w) {
Object data= w.getData();
if (data instanceof FileHistory) {
FileHistory h= (FileHistory) data;
fCurrentFileHistory= h;
IFile file= h.getFile();
IFileState[] states= h.getStates();
fEditionPane.setImage(CompareUI.getImage(file));
String pattern= Utilities.getString(fBundle, "treeTitleFormat"); //$NON-NLS-1$
String title= MessageFormat.format(pattern, new Object[] { file.getName() });
fEditionPane.setText(title);
if (fEditionTree != null) {
fEditionTree.setRedraw(false);
fEditionTree.removeAll();
for (int i= 0; i < states.length; i++) {
addEdition(new HistoryInput(file, states[i]), h.isSelected(i));
}
fEditionTree.setRedraw(true);
}
} else
fCurrentFileHistory= null;
}
/**
* Adds the given Pair to the edition tree.
* It takes care of creating tree nodes for different dates.
*/
private void addEdition(HistoryInput input, boolean isSelected) {
if (fEditionTree == null || fEditionTree.isDisposed())
return;
IFileState state= input.fFileState;
// find last day
TreeItem[] days= fEditionTree.getItems();
TreeItem lastDay= null;
if (days.length > 0)
lastDay= days[days.length-1];
long ldate= state.getModificationTime();
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(fTimeImage);
ti.setText(DateFormat.getTimeInstance().format(date));
ti.setData(input);
if (isSelected) {
lastDay.setExpanded(true);
fEditionTree.setSelection(new TreeItem[] { ti });
feedContent(ti);
}
}
/**
* 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;
}
/**
* Feeds the tree viewer's selection to the contentviewer
*/
private void feedContent(Widget w) {
if (fContentPane != null && !fContentPane.isDisposed()) {
Object o= w.getData();
if (o instanceof HistoryInput) {
HistoryInput selected= (HistoryInput) o;
fContentPane.setInput(selected);
fContentPane.setText(getEditionLabel(selected));
fContentPane.setImage(fTimeImage);
if (fCurrentFileHistory != null)
fCurrentFileHistory.setSelected(selected.fFileState);
} else {
fContentPane.setInput(null);
}
}
}
protected String getEditionLabel(HistoryInput input) {
String 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$
long modDate= input.getModificationDate();
String date= DateFormat.getDateTimeInstance().format(new Date(modDate));
return MessageFormat.format(format, new Object[] { date });
}
/* (non-Javadoc)
* Method declared on Dialog.
*/
protected void createButtonsForButtonBar(Composite parent) {
String buttonLabel= Utilities.getString(fBundle, "buttonLabel", IDialogConstants.OK_LABEL); //$NON-NLS-1$
// a 'Cancel' and a 'Add' button
fCommitButton= createButton(parent, IDialogConstants.OK_ID, buttonLabel, true);
fCommitButton.setEnabled(false);
createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
}
/**
* Returns true if the pathname of f1 comes after f2
*/
private static boolean greaterThan(IFile f1, IFile f2) {
String[] ss1= f1.getFullPath().segments();
String[] ss2= f2.getFullPath().segments();
int l1= ss1.length;
int l2= ss2.length;
int n= Math.max(l1, l2);
for (int i= 0; i < n; i++) {
String s1= i < l1 ? ss1[i] : ""; //$NON-NLS-1$
String s2= i < l2 ? ss2[i] : ""; //$NON-NLS-1$
int rc= s1.compareToIgnoreCase(s2);
if (rc != 0)
return rc < 0;
}
return false;
}
private static void internalSort(IFile[] keys, int left, int right) {
int original_left= left;
int original_right= right;
IFile mid= keys[(left + right) / 2];
do {
while (greaterThan(keys[left], mid))
left++;
while (greaterThan(mid, keys[right]))
right--;
if (left <= right) {
IFile 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);
}
}