/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.motorolamobility.studio.android.certmanager.ui.wizards;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.internal.resources.Folder;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
import org.eclipse.ui.dialogs.ISelectionStatusValidator;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.views.navigator.ResourceComparator;
import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
import com.motorolamobility.studio.android.certmanager.i18n.CertificateManagerNLS;
@SuppressWarnings("restriction")
public class RemoveExternalPackageSignaturePage extends WizardPage
{
private Text sourceDirText = null;
private Button browseDirButton = null;
private Button workspaceDirButton = null;
private Tree packagesTree = null;
private Button selectAllButton = null;
private Button deselectAllButton = null;
private WizardSelection selection = null;
protected Composite mainComposite = null;
/**
* Create a new wizard page based on selection
*
* @param pageName
* the page name
* @param selection
* the selection
*/
public RemoveExternalPackageSignaturePage(String pageName, IStructuredSelection selection)
{
super(pageName);
setDescription(CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION);
setTitle(CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_WINDOW_TITLE);
this.selection = new WizardSelection(selection);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets
* .Composite)
*/
@Override
public void createControl(Composite parent)
{
this.mainComposite = new Composite(parent, SWT.NULL);
// create new layout with 3 columns of different sizes
GridLayout layout = new GridLayout(4, false);
this.mainComposite.setLayout(layout);
Label sourceDirLabel = new Label(this.mainComposite, SWT.NONE);
sourceDirLabel.setText(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_LABEL);
GridData layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
sourceDirLabel.setLayoutData(layoutData);
this.sourceDirText = new Text(this.mainComposite, SWT.BORDER);
layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
this.sourceDirText.setLayoutData(layoutData);
this.sourceDirText.addListener(SWT.Modify, new SourceDirectoryTextListener());
this.browseDirButton = new Button(this.mainComposite, SWT.PUSH);
this.browseDirButton.setText(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_FILESYSTEM);
layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
this.browseDirButton.setLayoutData(layoutData);
this.browseDirButton.addListener(SWT.Selection, new BrowseButtonListener());
this.workspaceDirButton = new Button(this.mainComposite, SWT.PUSH);
this.workspaceDirButton.setText(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE);
layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
this.workspaceDirButton.setLayoutData(layoutData);
this.workspaceDirButton.addListener(SWT.Selection, new WorkspaceButtonListener());
createExtendedArea(this.mainComposite);
createPackageTreeLabel();
this.packagesTree = new Tree(this.mainComposite, SWT.BORDER | SWT.CHECK | SWT.V_SCROLL);
layoutData = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 2);
layoutData.heightHint = 150;
this.packagesTree.setLayoutData(layoutData);
this.packagesTree.addListener(SWT.Selection, new TreeSelectionListener());
Composite selectionButtons = new Composite(this.mainComposite, SWT.FILL);
layoutData = new GridData(SWT.FILL, SWT.TOP, false, true, 1, 2);
selectionButtons.setLayoutData(layoutData);
FillLayout row = new FillLayout(SWT.VERTICAL);
row.spacing = 3;
selectionButtons.setLayout(row);
this.selectAllButton = new Button(selectionButtons, SWT.PUSH);
this.selectAllButton
.setText(CertificateManagerNLS.PACKAGE_EXPORT_WIZARD_AREA_SELECT_ALL_BUTTON);
SelectionButtonsListener selectionButtonsListener = new SelectionButtonsListener();
this.selectAllButton.addListener(SWT.Selection, selectionButtonsListener);
this.deselectAllButton = new Button(selectionButtons, SWT.PUSH);
this.deselectAllButton
.setText(CertificateManagerNLS.PACKAGE_EXPORT_WIZARD_AREA_DESELECT_ALL_BUTTON);
this.deselectAllButton.addListener(SWT.Selection, selectionButtonsListener);
this.sourceDirText.setText(this.selection.getSelectedDirectory());
populateTree(this.selection.getSelectedPackages());
updatePageComplete();
setControl(this.mainComposite);
}
protected void createPackageTreeLabel()
{
GridData layoutData;
Label packagesLabel = new Label(this.mainComposite, SWT.NONE);
packagesLabel
.setText(CertificateManagerNLS.RemoveExternalPackageSignaturePage_Package_Tree_Label);
layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false, 4, 1);
packagesLabel.setLayoutData(layoutData);
}
/**
* Create a composite area after the basic composite Subclasses that need
* more than the basic package selection screen should override this method
*
* @param mainComposite
*/
protected void createExtendedArea(Composite parent)
{
PlatformUI
.getWorkbench()
.getHelpSystem()
.setHelp(parent,
CertificateManagerActivator.UNSIGN_EXTERNAL_PKG_WIZARD_CONTEXT_HELP_ID);
}
/**
* Populates the tree with the packages of base dir Requires a valid folder
* set as source dir
*/
private void populateTree(List<String> selection)
{
File sourceDir = getSourcePath().toFile();
Color gray = new Color(null, 130, 130, 130);
this.packagesTree.removeAll();
if (sourceDir.isDirectory() && sourceDir.canWrite())
{
File[] list = sourceDir.listFiles();
for (File file : list)
{
if (file.canRead() && file.isFile() && file.getName().endsWith("apk")) //$NON-NLS-1$
{
TreeItem fileItem = new TreeItem(this.packagesTree, SWT.NONE);
String text = file.getName();
if (!file.canWrite())
{
text += " [" + CertificateManagerNLS.READ_ONLY_TEXT //$NON-NLS-1$
+ "]"; //$NON-NLS-1$
fileItem.setForeground(gray);
}
fileItem.setText(text);
fileItem.setData(file);
if ((selection != null) && selection.contains(file.getName())
&& file.canWrite())
{
fileItem.setChecked(true);
}
}
}
}
}
/**
* Validates if the source directory is valid one
*
* @return true if the source dir text is valid, false otherwise
*/
private boolean isSourceDirValid()
{
String messageAux = null;
int severity = IMessageProvider.NONE;
/*
* Check if the selected location is valid, even if non existent.
*/
IPath path = new Path(this.sourceDirText.getText());
// Test if path is blank, to warn user instead of show an error message
if (this.sourceDirText.getText().equals("")) //$NON-NLS-1$
{
messageAux =
CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_EMPTY;
severity = IMessageProvider.INFORMATION;
}
/*
* Do Win32 Validation
*/
if ((messageAux == null) && Platform.getOS().equalsIgnoreCase(Platform.OS_WIN32))
{
// test path size
if (path.toString().length() > 255)
{
messageAux =
CertificateManagerNLS.SELECTOR_MESSAGE_LOCATION_ERROR_PATH_TOO_LONG;
severity = IMessageProvider.WARNING;
}
String device = path.getDevice();
File deviceFile = null;
if (device != null)
{
deviceFile = new File(path.getDevice());
}
if ((device != null) && !deviceFile.exists())
{
messageAux =
CertificateManagerNLS.SELECTOR_MESSAGE_LOCATION_ERROR_INVALID_DEVICE + " ["
+ device + "]";
severity = IMessageProvider.ERROR;
}
}
// test if path is absolute
if (messageAux == null)
{
if (!path.isAbsolute() || !path.toFile().exists())
{
messageAux =
CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_INVALID;
severity = IMessageProvider.ERROR;
}
}
if (messageAux == null)
{
for (String folderName : path.segments())
{
if (!ResourcesPlugin.getWorkspace().validateName(folderName, IResource.FOLDER)
.isOK())
{
messageAux =
CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_INVALID;
severity = IMessageProvider.ERROR;
}
}
}
if ((messageAux == null) && ((path.toFile().exists() && !path.toFile().isDirectory())))
{
messageAux =
CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_SOURCE_DIR_NOT_DIRECTORY;
severity = IMessageProvider.ERROR;
}
/*
* Setting message
*/
if (messageAux == null)
{
messageAux = CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION;
severity = IMessageProvider.NONE;
}
setMessage(messageAux, severity);
return severity == IMessageProvider.NONE;
}
/**
* @return the path of base dir where packages are located
*/
public IPath getSourcePath()
{
return new Path(this.sourceDirText.getText());
}
/**
*
* @return the list with selected packages
*/
public List<String> getSelectedPackages()
{
ArrayList<String> selected = new ArrayList<String>();
for (TreeItem item : this.packagesTree.getItems())
{
if (item.getChecked())
{
selected.add(item.getData().toString());
}
}
return selected;
}
/**
* Update the page status, validating each field of this page Subclasses
* that overrides createExtendedArea method should override this method too
* to validate the new fields
*/
public void updatePageComplete()
{
String messageAux = null;
int severity = IMessageProvider.NONE;
/*
* Check if there are available certificates and if selection isn't null
*/
if (isSourceDirValid())
{
if (this.packagesTree.getItemCount() == 0)
{
messageAux =
CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_NO_AVAILABLE_PACKAGES;
severity = IMessageProvider.ERROR;
}
}
else
{
messageAux = getMessage();
severity = getMessageType();
}
if ((messageAux == null) && (getSelectedPackages().size() == 0))
{
messageAux =
CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_NO_PACKAGES_SELECTED;
severity = IMessageProvider.INFORMATION;
}
if (messageAux == null)
{
messageAux =
CertificateManagerNLS.UNSIGN_EXTERNAL_PKG_WIZARD_DESCRIPTION;
severity = IMessageProvider.NONE;
}
setMessage(messageAux, severity);
setPageComplete(severity == IMessageProvider.NONE);
}
/**
* This class implements the listener of filesystem button, opening the browse
* window and updating the dir text
*/
class BrowseButtonListener implements Listener
{
/*
* (non-Javadoc)
*
* @see
* org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
* .Event)
*/
@Override
public void handleEvent(Event event)
{
DirectoryDialog dialog =
new DirectoryDialog(
RemoveExternalPackageSignaturePage.this.mainComposite.getShell());
dialog.setFilterPath(!RemoveExternalPackageSignaturePage.this.sourceDirText.getText()
.trim().equals("") ? RemoveExternalPackageSignaturePage.this.sourceDirText
.getText() : null);
String path = dialog.open();
if (path != null)
{
RemoveExternalPackageSignaturePage.this.sourceDirText.setText(path);
populateTree(null);
updatePageComplete();
}
}
}
/**
* This class implements the listener of workspace button, opening the browse
* window and updating the dir text
*/
class WorkspaceButtonListener implements Listener
{
/*
* (non-Javadoc)
*
* @see
* org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
* .Event)
*/
@Override
public void handleEvent(Event event)
{
ElementTreeSelectionDialog dialog =
new ElementTreeSelectionDialog(getShell(), new WorkbenchLabelProvider(),
new WorkbenchContentProvider());
dialog.setTitle(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_WORKSPACE_SIMPLE);
dialog.setMessage(CertificateManagerNLS.SIGN_EXTERNAL_PKG_WIZARD_CHOOSE);
// set the workspace as the limit
dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
dialog.setComparator(new ResourceComparator(ResourceComparator.NAME));
//don't display files
dialog.addFilter(new ViewerFilter()
{
@Override
public boolean select(Viewer viewer, Object parentElement, Object element)
{
boolean filtered = false;
if (element instanceof IFile)
{
filtered = true;
}
return !filtered;
}
});
//user can select only one folder
dialog.setValidator(new ISelectionStatusValidator()
{
@Override
public IStatus validate(Object[] selection)
{
IStatus valid =
new Status(IStatus.ERROR, CertificateManagerActivator.PLUGIN_ID, ""); //$NON-NLS-1$
if (selection.length == 1)
{
if (selection[0] instanceof Folder)
{
valid =
new Status(IStatus.OK, CertificateManagerActivator.PLUGIN_ID,
""); //$NON-NLS-1$
}
}
return valid;
}
});
String path = null;
if (dialog.open() == IDialogConstants.OK_ID)
{
Folder resource = (Folder) dialog.getFirstResult();
path = resource.getLocation().toString();
}
if (path != null)
{
RemoveExternalPackageSignaturePage.this.sourceDirText.setText(path);
populateTree(null);
updatePageComplete();
}
}
}
/**
* Listener to validate any SourceDirectory text Change
*/
class SourceDirectoryTextListener implements Listener
{
/*
* (non-Javadoc)
*
* @see
* org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
* .Event)
*/
@Override
public void handleEvent(Event event)
{
RemoveExternalPackageSignaturePage.this.packagesTree.removeAll();
if (isSourceDirValid())
{
populateTree(null);
}
updatePageComplete();
}
}
/**
* This class handles clicks on select all and deselect all buttons
*/
class SelectionButtonsListener implements Listener
{
/**
* Check/Uncheck all items
*
* @param check
* : true for check, false for unckeck
*/
private void setCheckedAll(boolean check)
{
for (TreeItem item : RemoveExternalPackageSignaturePage.this.packagesTree.getItems())
{
item.setChecked(check);
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
* .Event)
*/
@Override
public void handleEvent(Event event)
{
if (event.widget == RemoveExternalPackageSignaturePage.this.selectAllButton)
{
setCheckedAll(true);
}
else if (event.widget == RemoveExternalPackageSignaturePage.this.deselectAllButton)
{
setCheckedAll(false);
}
updatePageComplete();
}
}
/**
* Listener to update wizard status according tree selection
*/
class TreeSelectionListener implements Listener
{
/*
* (non-Javadoc)
*
* @see
* org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
* .Event)
*/
@Override
public void handleEvent(Event event)
{
updatePageComplete();
}
}
/**
* This class gets the workspace selection and makes a suitable selection to
* the wizard
*/
class WizardSelection
{
private ArrayList<String> packages = null;
private IPath directory = null;
public WizardSelection(IStructuredSelection selection)
{
this.packages = new ArrayList<String>();
Iterator<?> iterator = selection.iterator();
while (iterator.hasNext())
{
Object obj = iterator.next();
if (obj instanceof IFile)
{
IFile file = (IFile) obj;
if (file.getLocation().getFileExtension().equals("apk")) //$NON-NLS-1$
{
if (this.directory == null)
{
this.directory = file.getLocation().removeLastSegments(1);
this.packages.add(file.getName());
}
else
{
if (file.getLocation().matchingFirstSegments(this.directory) == this.directory
.segmentCount())
{
this.packages.add(file.getName());
}
}
}
}
else if (obj instanceof IFolder)
{
if (this.directory == null)
{
this.directory = ((IFolder) obj).getLocation();
}
}
}
if (this.directory == null)
{
this.directory = new Path(""); //$NON-NLS-1$
}
}
/**
*
* @return the selected directory
*/
public String getSelectedDirectory()
{
return this.directory.toOSString();
}
/**
*
* @return the selected packages
*/
public List<String> getSelectedPackages()
{
return this.packages;
}
}
}