/**
* Aptana Studio
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions).
* Please see the license.html included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.ide.syncing.ui.internal;
import java.io.File;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.SameShellProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.internal.ide.dialogs.FileFolderSelectionDialog;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import com.aptana.core.CoreStrings;
import com.aptana.core.io.efs.EFSUtils;
import com.aptana.core.util.StringUtil;
import com.aptana.filesystem.ftp.FTPConnectionPoint;
import com.aptana.ide.core.io.ConnectionPointUtils;
import com.aptana.ide.core.io.CoreIOPlugin;
import com.aptana.ide.core.io.IConnectionPoint;
import com.aptana.ide.syncing.core.DefaultSiteConnection;
import com.aptana.ide.syncing.core.ISiteConnection;
import com.aptana.ide.syncing.core.SiteConnectionUtils;
import com.aptana.ui.IPropertyDialog;
import com.aptana.ui.ftp.internal.FTPPropertyDialogProvider;
/**
* @author Max Stepanov
* @author Michael Xia
*/
@SuppressWarnings("restriction")
public class SiteConnectionPropertiesWidget extends Composite implements ModifyListener
{
public static interface Client
{
public void setErrorMessage(String message);
}
private Client client;
private ISiteConnection siteConnection;
private Text nameText;
private TargetEditor sourceEditor;
private TargetEditor destinationEditor;
private boolean changed;
/**
* @param parent
* the parent composite
* @param style
* SWT style bits
* @param client
* a callback client to receive necessary notifications
*/
public SiteConnectionPropertiesWidget(Composite parent, int style, Client client)
{
super(parent, style);
this.client = client;
setLayout(GridLayoutFactory.swtDefaults().numColumns(2).create());
/* row 1 - name */
Label label = new Label(this, SWT.NONE);
label.setText(StringUtil.makeFormLabel(Messages.SiteConnectionPropertiesWidget_LBL_Name));
label.setLayoutData(GridDataFactory.swtDefaults().create());
nameText = new Text(this, SWT.SINGLE | SWT.BORDER);
nameText.setLayoutData(GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).create());
nameText.addModifyListener(this);
/* row 2 - source */
Group group = new Group(this, SWT.NONE);
group.setLayoutData(GridDataFactory.fillDefaults().span(2, 1).grab(true, true).create());
group.setText(Messages.SiteConnectionPropertiesWidget_LBL_Source);
sourceEditor = new TargetEditor(Messages.SiteConnectionPropertiesWidget_LBL_Source);
// currently not allowing remote site to be a source
sourceEditor.createTargets(group, false);
/* row 3 - destination */
group = new Group(this, SWT.NONE);
group.setLayoutData(GridDataFactory.fillDefaults().span(2, 1).grab(true, true).create());
group.setText(Messages.SiteConnectionPropertiesWidget_LBL_Destination);
destinationEditor = new TargetEditor(Messages.SiteConnectionPropertiesWidget_LBL_Destination);
destinationEditor.createTargets(group, true);
}
public void setSource(ISiteConnection source)
{
if (this.siteConnection == source && source != null)
{
return;
}
this.siteConnection = source;
if (source == null)
{
((GridData) getLayoutData()).exclude = true;
setVisible(false);
getParent().layout();
validateAll();
changed = false;
return;
}
if (!isVisible())
{
((GridData) getLayoutData()).exclude = false;
setVisible(true);
getParent().layout();
}
nameText.setText(source.getName());
nameText.setEnabled(source != DefaultSiteConnection.getInstance());
sourceEditor.setTarget(source.getSource());
destinationEditor.setTarget(source.getDestination());
validateAll();
changed = source.getSource() == null
|| (source != DefaultSiteConnection.getInstance() && source.getDestination() == null);
}
public ISiteConnection getSource()
{
return siteConnection;
}
public boolean isChanged()
{
return siteConnection != null && changed;
}
public boolean applyChanges()
{
if (!validateAll())
{
return false;
}
siteConnection.setName(nameText.getText());
IConnectionPoint connectionPoint = sourceEditor.getTarget();
if (connectionPoint != null)
{
CoreIOPlugin.getConnectionPointManager().addConnectionPoint(connectionPoint);
}
siteConnection.setSource(connectionPoint);
sourceEditor.clearNewConnections(false);
connectionPoint = destinationEditor.getTarget();
if (connectionPoint != null)
{
CoreIOPlugin.getConnectionPointManager().addConnectionPoint(connectionPoint);
}
siteConnection.setDestination(connectionPoint);
destinationEditor.clearNewConnections(false);
changed = false;
return true;
}
public void cancelChanges()
{
sourceEditor.clearNewConnections(true);
destinationEditor.clearNewConnections(true);
}
public void modifyText(ModifyEvent e)
{
if (validateAll())
{
changed = true;
}
}
private boolean validateAll()
{
String message = null;
if (siteConnection != null)
{
String name = nameText.getText().trim();
if (name.length() == 0)
{
message = Messages.SiteConnectionPropertiesWidget_ERR_EmptyName;
}
else if (siteConnection != DefaultSiteConnection.getInstance() && name.equals(DefaultSiteConnection.NAME))
{
message = MessageFormat.format(Messages.SiteConnectionPropertiesWidget_ERR_DuplicateNames, name);
}
else if ((siteConnection == null || !name.equalsIgnoreCase(siteConnection.getName()))
&& !SiteConnectionUtils.isSiteNameUnique(name))
{
message = MessageFormat.format(Messages.SiteConnectionPropertiesWidget_ERR_DuplicateNames, name);
}
if (message == null)
{
message = sourceEditor.validate();
}
if (message == null)
{
message = destinationEditor.validate();
}
}
client.setErrorMessage(message);
return message == null;
}
private IConnectionPoint createNewRemoteConnection()
{
Dialog dlg = new FTPPropertyDialogProvider().createPropertyDialog(new SameShellProvider(this));
if (dlg instanceof IPropertyDialog)
{
((IPropertyDialog) dlg).setPropertySource(CoreIOPlugin.getConnectionPointManager().getType(
FTPConnectionPoint.TYPE));
}
if (dlg.open() == Window.OK)
{
Object result = null;
if (dlg instanceof IPropertyDialog)
{
result = ((IPropertyDialog) dlg).getPropertySource();
}
if (result instanceof IConnectionPoint)
{
return (IConnectionPoint) result;
}
}
return null;
}
private IContainer browseWorkspace(IContainer container, IPath path)
{
FileFolderSelectionDialog dlg = new FileFolderSelectionDialog(getShell(), false, IResource.FOLDER);
IFileStore input = EFSUtils.getFileStore(container);
dlg.setInput(input);
dlg.setInitialSelection(input.getFileStore(path));
if (dlg.open() == Window.OK)
{
if (dlg.getFirstResult() instanceof IAdaptable)
{
return (IContainer) ((IAdaptable) dlg.getFirstResult()).getAdapter(IResource.class);
}
}
return null;
}
private IPath browseFilesystem(IPath path)
{
DirectoryDialog dlg = new DirectoryDialog(getShell());
dlg.setFilterPath(path.toOSString());
String result = dlg.open();
if (result != null)
{
return Path.fromOSString(result);
}
return null;
}
private class TargetEditor implements SelectionListener, ISelectionChangedListener
{
private static final int REMOTE = 1;
private static final int PROJECT = 2;
private static final int FILESYSTEM = 3;
private String name;
private Composite mainComp;
private Button remoteRadio;
private ComboViewer remotesViewer;
private Button remoteNewButton;
private Button projectRadio;
private ComboViewer projectViewer;
private Text projectFolderText;
private Button projectBrowseButton;
private Button filesystemRadio;
private Text filesystemFolderText;
private Button filesystemBrowseButton;
private Label defaultDescriptionLabel;
private boolean isDefault = false;
private List<IConnectionPoint> newRemoteConnections;
TargetEditor(String name)
{
this.name = name;
newRemoteConnections = new ArrayList<IConnectionPoint>();
}
/**
* @param remove
* true if the newly created connections should be discarded, false if we are only resetting the list
*/
public void clearNewConnections(boolean remove)
{
if (remove)
{
for (IConnectionPoint connection : newRemoteConnections)
{
CoreIOPlugin.getConnectionPointManager().removeConnectionPoint(connection);
}
}
newRemoteConnections.clear();
}
public void widgetDefaultSelected(SelectionEvent e)
{
}
public void widgetSelected(SelectionEvent e)
{
Object source = e.getSource();
if (source == remoteNewButton)
{
IConnectionPoint result = createNewRemoteConnection();
if (result != null)
{
newRemoteConnections.add(result);
updateRemotesViewer();
setType(REMOTE);
remotesViewer.setSelection(new StructuredSelection(result));
changed = true;
}
validateAll();
}
else if (source == projectBrowseButton)
{
IContainer container = (IContainer) ((IStructuredSelection) projectViewer.getSelection())
.getFirstElement();
if (container == null)
{
container = ResourcesPlugin.getWorkspace().getRoot();
}
IContainer result = browseWorkspace(container, Path.fromPortableString(projectFolderText.getText()));
if (result != null)
{
projectViewer.setSelection(new StructuredSelection(result.getProject()), true);
projectFolderText.setText(result.getProjectRelativePath().toPortableString());
changed = true;
}
validateAll();
}
else if (source == filesystemBrowseButton)
{
IPath path = browseFilesystem(Path.fromPortableString(filesystemFolderText.getText()));
if (path != null)
{
filesystemFolderText.setText(path.toPortableString());
changed = true;
}
validateAll();
}
else
{
setEnabled(getType());
if (validateAll())
{
changed = true;
}
}
}
public void selectionChanged(SelectionChangedEvent event)
{
Object source = event.getSource();
if (source == projectViewer)
{
projectFolderText.setText(Path.ROOT.toPortableString());
setEnabled(getType());
}
if (validateAll())
{
changed = true;
}
}
private void createTargets(Composite parent, boolean showRemote)
{
parent.setLayout(GridLayoutFactory.swtDefaults().create());
mainComp = new Composite(parent, SWT.NONE);
mainComp.setLayout(GridLayoutFactory.swtDefaults().margins(0, 0).numColumns(4).create());
mainComp.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create());
/* row 1 - remote */
remoteRadio = new Button(mainComp, SWT.RADIO);
remoteRadio.setText(Messages.SiteConnectionPropertiesWidget_LBL_Remote);
remoteRadio.setLayoutData(GridDataFactory.swtDefaults().exclude(!showRemote).create());
remoteRadio.addSelectionListener(this);
remotesViewer = new ComboViewer(mainComp, SWT.DROP_DOWN | SWT.READ_ONLY);
remotesViewer.getControl().setLayoutData(
GridDataFactory.swtDefaults().exclude(!showRemote).align(SWT.FILL, SWT.CENTER).span(2, 1)
.grab(true, false).create());
remotesViewer.setContentProvider(ArrayContentProvider.getInstance());
remotesViewer.addSelectionChangedListener(this);
updateRemotesViewer();
remoteNewButton = new Button(mainComp, SWT.PUSH);
remoteNewButton.setText(StringUtil.ellipsify(CoreStrings.NEW));
remoteNewButton.setLayoutData(GridDataFactory.swtDefaults().exclude(!showRemote).create());
remoteNewButton.addSelectionListener(this);
/* row 2 - project */
projectRadio = new Button(mainComp, SWT.RADIO);
projectRadio.setText(Messages.SiteConnectionPropertiesWidget_LBL_Project);
projectRadio.setLayoutData(GridDataFactory.swtDefaults().create());
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
projectRadio.setEnabled(projects.length > 0);
projectRadio.addSelectionListener(this);
projectViewer = new ComboViewer(mainComp, SWT.DROP_DOWN | SWT.READ_ONLY);
projectViewer.getControl().setLayoutData(
GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).span(3, 1).grab(true, false).create());
projectViewer.setContentProvider(ArrayContentProvider.getInstance());
if (projects.length == 0)
{
projectViewer.setLabelProvider(new LabelProvider());
Object[] input = new Object[] { Messages.SiteConnectionPropertiesWidget_NoProject };
projectViewer.setInput(input);
projectViewer.setSelection(new StructuredSelection(input[0]), true);
}
else
{
projectViewer.setLabelProvider(WorkbenchLabelProvider.getDecoratingWorkbenchLabelProvider());
Arrays.sort(projects, new Comparator<IProject>()
{
public int compare(IProject o1, IProject o2)
{
return o1.getName().compareTo(o2.getName());
}
});
projectViewer.setInput(projects);
projectViewer.setSelection(new StructuredSelection(projects[0]), true);
}
projectViewer.addSelectionChangedListener(this);
/* row 3 - project folder */
new Label(mainComp, SWT.NONE).setLayoutData(GridDataFactory.swtDefaults().create());
Composite folder = new Composite(mainComp, SWT.NONE);
folder.setLayout(GridLayoutFactory.fillDefaults().numColumns(2).create());
folder.setLayoutData(GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).span(2, 1).grab(true, false)
.create());
Label label = new Label(folder, SWT.NONE);
label.setText(StringUtil.makeFormLabel(Messages.SiteConnectionPropertiesWidget_LBL_Folder));
label.setLayoutData(GridDataFactory.swtDefaults().create());
projectFolderText = new Text(folder, SWT.BORDER);
projectFolderText.setText(Path.ROOT.toPortableString());
projectFolderText.setLayoutData(GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false)
.create());
projectFolderText.addModifyListener(SiteConnectionPropertiesWidget.this);
projectBrowseButton = new Button(mainComp, SWT.PUSH);
projectBrowseButton.setText(StringUtil.ellipsify(CoreStrings.BROWSE));
projectBrowseButton.setLayoutData(GridDataFactory.swtDefaults().create());
projectBrowseButton.addSelectionListener(this);
/* row 4 - filesystem */
filesystemRadio = new Button(mainComp, SWT.RADIO);
filesystemRadio.setText(Messages.SiteConnectionPropertiesWidget_LBL_Filesystem);
filesystemRadio.setLayoutData(GridDataFactory.swtDefaults().create());
filesystemRadio.addSelectionListener(this);
filesystemFolderText = new Text(mainComp, SWT.BORDER);
filesystemFolderText.setLayoutData(GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).span(2, 1)
.grab(true, false).create());
filesystemFolderText.addModifyListener(SiteConnectionPropertiesWidget.this);
filesystemBrowseButton = new Button(mainComp, SWT.PUSH);
filesystemBrowseButton.setText(StringUtil.ellipsify(CoreStrings.BROWSE));
filesystemBrowseButton.setLayoutData(GridDataFactory.swtDefaults().create());
filesystemBrowseButton.addSelectionListener(this);
/* description text for the default connection */
defaultDescriptionLabel = new Label(parent, SWT.WRAP);
defaultDescriptionLabel.setText(Messages.SiteConnectionPropertiesWidget_LBL_DefaultDescription);
defaultDescriptionLabel.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).exclude(true)
.create());
}
private void updateRemotesViewer()
{
IConnectionPoint[] sites = ConnectionPointUtils.getRemoteConnectionPoints();
if (sites.length == 0)
{
remoteRadio.setEnabled(false);
remotesViewer.setLabelProvider(new LabelProvider());
Object[] input = new Object[] { Messages.SiteConnectionPropertiesWidget_NoRemoteSite };
remotesViewer.setInput(input);
remotesViewer.setSelection(new StructuredSelection(input[0]), true);
}
else
{
remoteRadio.setEnabled(true);
remoteRadio.setSelection(true);
remotesViewer.setLabelProvider(WorkbenchLabelProvider.getDecoratingWorkbenchLabelProvider());
Arrays.sort(sites, new Comparator<IConnectionPoint>()
{
public int compare(IConnectionPoint o1, IConnectionPoint o2)
{
return o1.getName().compareTo(o2.getName());
}
});
remotesViewer.setInput(sites);
remotesViewer.setSelection(new StructuredSelection(sites[0]), true);
Control control = remotesViewer.getControl();
control.setForeground(control.getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND));
}
}
private void setType(int type)
{
remoteRadio.setSelection(false);
projectRadio.setSelection(false);
filesystemRadio.setSelection(false);
switch (type)
{
case REMOTE:
remoteRadio.setSelection(true);
break;
case PROJECT:
projectRadio.setSelection(true);
break;
case FILESYSTEM:
filesystemRadio.setSelection(true);
break;
}
setEnabled(type);
}
private int getType()
{
if (remoteRadio.getSelection())
{
return REMOTE;
}
else if (projectRadio.getSelection())
{
return PROJECT;
}
else if (filesystemRadio.getSelection())
{
return FILESYSTEM;
}
return -1;
}
private void setEnabled(int type)
{
setEnabled(type, true);
switch (type)
{
case REMOTE:
setEnabled(PROJECT, false);
setEnabled(FILESYSTEM, false);
break;
case PROJECT:
setEnabled(REMOTE, false);
setEnabled(FILESYSTEM, false);
break;
case FILESYSTEM:
setEnabled(REMOTE, false);
setEnabled(PROJECT, false);
break;
default:
setEnabled(REMOTE, false);
setEnabled(PROJECT, false);
setEnabled(FILESYSTEM, false);
break;
}
}
private void setEnabled(int type, boolean enabled)
{
switch (type)
{
case REMOTE:
if (remoteRadio.getEnabled())
{
remotesViewer.getControl().setEnabled(true);
remoteNewButton.setEnabled(enabled);
}
else
{
Control control = remotesViewer.getControl();
control.setEnabled(false);
control.setForeground(control.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_FOREGROUND));
}
break;
case PROJECT:
if (!projectRadio.getEnabled())
{
Control control = projectViewer.getControl();
control.setEnabled(false);
control.setForeground(control.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_FOREGROUND));
projectFolderText.setEnabled(false);
projectBrowseButton.setEnabled(false);
return;
}
projectViewer.getControl().setEnabled(enabled);
IProject project = (IProject) ((IStructuredSelection) projectViewer.getSelection())
.getFirstElement();
boolean hasFolders = false;
if (project != null)
{
try
{
IResource[] resources = project.members();
for (IResource resource : resources)
{
if (resource instanceof IContainer)
{
hasFolders = true;
break;
}
}
}
catch (CoreException e)
{
}
}
projectFolderText.setEnabled(enabled && hasFolders);
projectBrowseButton.setEnabled(enabled && hasFolders);
break;
case FILESYSTEM:
filesystemFolderText.setEnabled(enabled);
filesystemBrowseButton.setEnabled(enabled);
break;
}
}
private void setTarget(IConnectionPoint connectionPoint)
{
isDefault = (siteConnection == DefaultSiteConnection.getInstance() && connectionPoint == siteConnection
.getDestination());
mainComp.setVisible(!isDefault);
((GridData) mainComp.getLayoutData()).exclude = isDefault;
defaultDescriptionLabel.setVisible(isDefault);
((GridData) defaultDescriptionLabel.getLayoutData()).exclude = !isDefault;
layout(true, true);
if (ConnectionPointUtils.isRemote(connectionPoint))
{
setType(REMOTE);
remotesViewer.setSelection(new StructuredSelection(connectionPoint), true);
}
else if (ConnectionPointUtils.isWorkspace(connectionPoint))
{
setType(PROJECT);
IResource resource = (IResource) connectionPoint.getAdapter(IResource.class);
if (resource != null)
{
projectViewer.setSelection(new StructuredSelection(resource.getProject()), true);
IPath path = resource.getProjectRelativePath();
if (path.isEmpty())
{
path = Path.ROOT;
}
projectFolderText.setText(path.toPortableString());
}
}
else if (ConnectionPointUtils.isLocal(connectionPoint))
{
setType(FILESYSTEM);
File file = (File) connectionPoint.getAdapter(File.class);
if (file != null)
{
filesystemFolderText.setText(Path.fromOSString(file.getAbsolutePath()).toPortableString());
}
}
}
private IConnectionPoint getTarget()
{
if (isDefault)
{
return null;
}
if (remoteRadio.getSelection())
{
return (IConnectionPoint) ((IStructuredSelection) remotesViewer.getSelection()).getFirstElement();
}
else if (projectRadio.getSelection())
{
IProject project = (IProject) ((IStructuredSelection) projectViewer.getSelection()).getFirstElement();
IPath path = Path.fromPortableString(projectFolderText.getText());
IContainer container = (IContainer) project.findMember(path);
return ConnectionPointUtils.findOrCreateWorkspaceConnectionPoint(container);
}
else if (filesystemRadio.getSelection())
{
IPath path = Path.fromPortableString(filesystemFolderText.getText());
return ConnectionPointUtils.findOrCreateLocalConnectionPoint(path);
}
return null;
}
private String validate()
{
if (isDefault)
{
return null;
}
if (remoteRadio.getSelection())
{
Object element = ((IStructuredSelection) remotesViewer.getSelection()).getFirstElement();
if (!(element instanceof IConnectionPoint))
{
return Messages.SiteConnectionPropertiesWidget_ERR_NoRemote;
}
}
else if (projectRadio.getSelection())
{
Object element = ((IStructuredSelection) projectViewer.getSelection()).getFirstElement();
if (!(element instanceof IProject))
{
return Messages.SiteConnectionPropertiesWidget_ERR_NoProject;
}
IProject project = (IProject) element;
IPath path = Path.fromPortableString(projectFolderText.getText());
if (!(project.findMember(path) instanceof IContainer))
{
return Messages.SiteConnectionPropertiesWidget_ERR_InvalidProjectFolder;
}
}
else if (filesystemRadio.getSelection())
{
IPath path = Path.fromPortableString(filesystemFolderText.getText());
if (!path.toFile().isDirectory())
{
return Messages.SiteConnectionPropertiesWidget_ERR_InvalidFilesystemFolder;
}
}
else
{
return MessageFormat.format(Messages.SiteConnectionPropertiesWidget_ERR_NoType, name.toLowerCase());
}
return null;
}
}
}