blob: e9e17ae25bd96450a4fccd9723b2d1a7fafd0c84 [file] [log] [blame]
/*
* 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.motorola.studio.android.packaging.ui.export;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.security.UnrecoverableKeyException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;
import org.eclipse.core.resources.IMarker;
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.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.IJobChangeListener;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.DecorationOverlayIcon;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
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.plugin.AbstractUIPlugin;
import com.motorola.studio.android.AndroidPlugin;
import com.motorola.studio.android.adt.AdtUtils;
import com.motorola.studio.android.adt.SdkUtils;
import com.motorola.studio.android.common.log.StudioLogger;
import com.motorola.studio.android.common.utilities.EclipseUtils;
import com.motorola.studio.android.packaging.ui.PackagingUIPlugin;
import com.motorola.studio.android.packaging.ui.i18n.Messages;
import com.motorolamobility.studio.android.certmanager.CertificateManagerActivator;
import com.motorolamobility.studio.android.certmanager.core.KeyStoreManager;
import com.motorolamobility.studio.android.certmanager.exception.InvalidPasswordException;
import com.motorolamobility.studio.android.certmanager.exception.KeyStoreManagerException;
import com.motorolamobility.studio.android.certmanager.job.CreateKeyJob;
import com.motorolamobility.studio.android.certmanager.packaging.PackageFile;
import com.motorolamobility.studio.android.certmanager.packaging.sign.PackageFileSigner;
import com.motorolamobility.studio.android.certmanager.packaging.sign.SignException;
import com.motorolamobility.studio.android.certmanager.ui.model.IKeyStore;
import com.motorolamobility.studio.android.certmanager.ui.model.ITreeNode;
import com.motorolamobility.studio.android.certmanager.ui.wizards.CreateKeyWizard;
import com.motorolamobility.studio.android.certmanager.ui.wizards.CreateKeystoreWizard;
import com.motorolamobility.studio.android.certmanager.ui.wizards.SelectExistentKeystoreWizard;
/**
*
* This Class is an area implementation for Package Export Wizards It contains
* all UI and finish logics
*
*/
@SuppressWarnings("restriction")
public class PackageExportWizardArea
{
/**
* It holds the selection
*/
private final IStructuredSelection selection;
/**
* The destination Folder selected by the user
*/
private Text destinationText;
private Button selectAllButton;
private Button deselectAllButton;
private Button packageDestinationBrowseButton;
private Button defaultDestination;
private Button signCheckBox;
private final Composite parentComposite;
private final boolean signingEnabled;
private final HashMap<IProject, Integer> projectSeverity;
/**
* The tree which contains all descriptor files
*/
private Tree tree;
private String message;
private int severity;
private boolean treeSelectionChanged;
private final Image icon_ok, icon_nok;
private Combo keystores;
private Combo keysCombo;
private Group signingGroup;
private Button buttonAddKey;
// Used in parallel with keystore combo. Use it with the selection index.
private static ArrayList<IKeyStore> keystoreList = new ArrayList<IKeyStore>();
//maps keystore->password
private final Map<IKeyStore, String> keystorePasswords = new HashMap<IKeyStore, String>();
private IKeyStore previousSelectedKeystore;
private String previousSelectedKey;
private Button buttonExisting;
private Button buttonAddNew;
/**
* Creates a new Export Area.
*
* @param selection
* The current Selection
*/
public PackageExportWizardArea(IStructuredSelection selection, Composite parent,
boolean signingEnabled)
{
this.selection = normalizeSelection(selection);
this.parentComposite = parent;
this.signingEnabled = signingEnabled;
this.projectSeverity = new HashMap<IProject, Integer>();
validateProjects();
ImageDescriptor adtProjectImageDescriptor =
AbstractUIPlugin.imageDescriptorFromPlugin("com.android.ide.eclipse.adt", //$NON-NLS-1$
"icons/android_project.png"); //$NON-NLS-1$
ImageDescriptor errorImageDescriptor = JavaPluginImages.DESC_OVR_ERROR;
ImageDescriptor projectImage =
PlatformUI.getWorkbench().getSharedImages()
.getImageDescriptor(org.eclipse.ui.ide.IDE.SharedImages.IMG_OBJ_PROJECT);
// (IDecoration.TOP_LEFT, IDecoration.TOP_RIGHT,
// IDecoration.BOTTOM_LEFT, IDecoration.BOTTOM_RIGHT and
// IDecoration.UNDERLAY).
ImageDescriptor[] overlays = new ImageDescriptor[5];
overlays[1] = adtProjectImageDescriptor;
icon_ok = new DecorationOverlayIcon(projectImage.createImage(), overlays).createImage();
overlays[2] = errorImageDescriptor;
icon_nok = new DecorationOverlayIcon(projectImage.createImage(), overlays).createImage();
createControl(parent);
this.treeSelectionChanged = false;
}
/**
* It opens the Directory Selection Dialog that allows the user enter the
* destination folder
*
* @param originalPath
* The Folder to show first
*
* @return The entire path of the user choice
*/
private String directoryDialog(String originalPath)
{
DirectoryDialog directoryDialog;
directoryDialog = new DirectoryDialog(parentComposite.getShell());
File directory = new File(originalPath);
if (directory.exists())
{
directoryDialog.setFilterPath(directory.getPath());
}
String returnedPath = directoryDialog.open();
return returnedPath;
}
/**
* This method normalize the selection only to contain projects and
* descriptors
*
* @return
* @throws CoreException
*/
@SuppressWarnings("unchecked")
private IStructuredSelection normalizeSelection(IStructuredSelection selection)
{
ArrayList<Object> normalized = new ArrayList<Object>();
Iterator<Object> iterator = selection.iterator();
while (iterator.hasNext())
{
Object item = iterator.next();
IResource resource = null;
if (item instanceof IResource)
{
resource = (IResource) item;
}
else if (item instanceof IAdaptable)
{
try
{
resource = (IResource) ((IAdaptable) item).getAdapter(IResource.class);
}
catch (Exception e)
{
StudioLogger.warn("Error retrieving projects.");
}
}
if (resource != null)
{
IProject project = resource.getProject();
if (!normalized.contains(project))
{
normalized.add(project);
}
}
}
return new StructuredSelection(normalized);
}
/**
* This method is responsible to add all the existent descriptor files of
* the current workspace in the tree shown in the wizard.
*/
private void populateTree()
{
tree.removeAll();
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
try
{
for (IProject project : projects)
{
if (project.isOpen() && (project.getNature(AndroidPlugin.Android_Nature) != null)
&& !SdkUtils.isLibraryProject(project))
{
TreeItem item = new TreeItem(tree, SWT.NONE);
item.setData(project);
item.setText(project.getName());
item.setImage(projectSeverity.get(project) == IMessageProvider.ERROR ? icon_nok
: icon_ok);
if (selection.toList().contains(project))
{
item.setChecked(true);
}
}
}
}
catch (CoreException e)
{
StudioLogger.error(PackageExportWizardArea.class,
"Error populating tree: " + e.getMessage()); //$NON-NLS-1$
}
}
/**
* Create the destination selection group
*
* @param mainComposite
* : the parent composite
*/
private void createDestinationGroup(Composite mainComposite)
{
// create destination group
Group destinationGroup = new Group(mainComposite, SWT.SHADOW_ETCHED_OUT);
GridLayout layout = new GridLayout(3, false);
destinationGroup.setLayout(layout);
GridData defaultDestGridData = new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1);
destinationGroup.setLayoutData(defaultDestGridData);
destinationGroup.setText(Messages.PACKAGE_EXPORT_WIZARD_AREA_DESTINATION_LABEL);
// Default Destination
this.defaultDestination = new Button(destinationGroup, SWT.CHECK);
defaultDestGridData = new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1);
this.defaultDestination.setLayoutData(defaultDestGridData);
this.defaultDestination.addListener(SWT.Selection, new DefaultDestinationListener());
this.defaultDestination.setText(Messages.PACKAGE_EXPORT_WIZARD_USE_DEFAULT_DESTINATION);
this.defaultDestination.setSelection(true);
// Package Destination Label
Label packageDestinationLabel = new Label(destinationGroup, SWT.NONE);
packageDestinationLabel.setText(Messages.PACKAGE_EXPORT_WIZARD_PACKAGE_DESTINATION_LABEL);
GridData folderGridData = new GridData(SWT.LEFT, SWT.CENTER, false, false);
packageDestinationLabel.setLayoutData(folderGridData);
// Package Destination
this.destinationText = new Text(destinationGroup, SWT.SINGLE | SWT.BORDER);
folderGridData = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
this.destinationText.setLayoutData(folderGridData);
this.destinationText.setEnabled(!this.defaultDestination.getSelection());
this.destinationText.addListener(SWT.Modify, new DestinationTextListener());
// Browse Button
this.packageDestinationBrowseButton = new Button(destinationGroup, SWT.PUSH);
folderGridData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
this.packageDestinationBrowseButton.setLayoutData(folderGridData);
this.packageDestinationBrowseButton
.setText(Messages.PACKAGE_EXPORT_WIZARD_AREA_BROWSE_BUTTON_LABEL);
this.packageDestinationBrowseButton.setEnabled(!this.defaultDestination.getSelection());
this.packageDestinationBrowseButton.addListener(SWT.Selection,
new PackageDestinationButtonListener());
}
public final String[] getKeys(IKeyStore iKeyStore) throws KeyStoreManagerException,
InvalidPasswordException
{
List<String> aliases = new ArrayList<String>();
aliases = iKeyStore.getAliases(getKeyStorePassword(iKeyStore));
return aliases.toArray(new String[0]);
}
public String openNewKeyWizard(IKeyStore keyStore, IJobChangeListener createKeyJobListener)
{
CreateKeyWizard wizard =
new CreateKeyWizard(keyStore, getKeyStorePassword(getSelectedKeyStore()),
createKeyJobListener);
WizardDialog dialog =
new WizardDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
wizard);
dialog.open();
return wizard.getAlias();
}
private void selectKeystore(IKeyStore newKeystore)
{
if (newKeystore != null)
{
int index = keystoreList.indexOf(newKeystore);
if (keystores.getItemCount() > index)
{
keystores.select(index);
loadKeys(newKeystore);
setEnablement(true);
}
}
else
{
keystores.deselectAll();
}
previousSelectedKeystore = getSelectedKeyStore();
}
private void selectKeystoreWithoutLoadingKeys(IKeyStore newKeystore)
{
if (newKeystore != null)
{
int index = keystoreList.indexOf(newKeystore);
keysCombo.removeAll();
if (keystores.getItemCount() > index)
{
keystores.select(index);
setEnablement(true);
}
}
else
{
keystores.deselectAll();
}
previousSelectedKeystore = getSelectedKeyStore();
}
private boolean loadKeys(IKeyStore newKeystore)
{
boolean successfullyLoaded = true;
keysCombo.removeAll();
try
{
String[] keys = getKeys(newKeystore);
if (keys != null)
{
keysCombo.setItems(keys);
}
}
catch (Exception e)
{
successfullyLoaded = false;
StudioLogger.info(PackageExportWizardArea.class,
NLS.bind("Could not load keys for keystore: {0}", newKeystore.getFile() //$NON-NLS-1$
.getAbsolutePath()));
}
selectKey(0);
return successfullyLoaded;
}
private void selectKey(String key)
{
String[] keys = keysCombo.getItems();
int index = -1;
int i = 0;
for (String k : keys)
{
if (k.equals(key))
{
index = i;
break;
}
i++;
}
selectKey(index);
}
private void selectKey(int index)
{
if ((index >= 0) && (index < keysCombo.getItemCount()))
{
keysCombo.select(index);
setEnablement(true);
}
else
{
keysCombo.deselectAll();
}
}
private void restorePreviousSelections()
{
selectKeystore(previousSelectedKeystore);
selectKey(previousSelectedKey);
}
private String getSelectedKey()
{
String result = null;
if (keysCombo.getSelectionIndex() >= 0)
{
result = keysCombo.getText();
}
return result;
}
protected IKeyStore getSelectedKeyStore()
{
IKeyStore result = null;
if (keystores.getSelectionIndex() >= 0)
{
result = keystoreList.get(keystores.getSelectionIndex());
}
return result;
}
/**
* Create the sign selection group
*
* @param mainComposite: the parent composite
*/
private void createSignGroup(Composite mainComposite)
{
// Create signing group
signingGroup = new Group(mainComposite, SWT.SHADOW_ETCHED_OUT);
GridLayout layout = new GridLayout(4, false);
GridData layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 4, 1);
signingGroup.setLayout(layout);
signingGroup.setLayoutData(layoutData);
signingGroup.setText(Messages.PACKAGE_EXPORT_WIZARD_AREA_SIGNING_TAB_TEXT);
// Sign button/Check box
this.signCheckBox = new Button(signingGroup, SWT.CHECK);
layoutData = new GridData(SWT.LEFT, SWT.CENTER, true, false, 4, 1);
this.signCheckBox.setLayoutData(layoutData);
this.signCheckBox.setText(Messages.PACKAGE_EXPORT_WIZARD_AREA_SIGN_CHECK_LABEL);
this.signCheckBox.addListener(SWT.Selection, new SignButtonListener());
this.signCheckBox.setSelection(true);
//--------------
// Keystore label
Label keystoreLabel = new Label(signingGroup, SWT.NONE);
keystoreLabel.setText(Messages.PACKAGE_EXPORT_WIZARD_AREA_SIGN_KEYSTORE_LABEL);
GridData gridData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 1, 1);
keystoreLabel.setLayoutData(gridData);
// Keystore combo
this.keystores = new Combo(signingGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
gridData = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
gridData.widthHint = 250;
this.keystores.setLayoutData(gridData);
//populate mapped keystores from view
populateKeystoresFromView();
keystores.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
IKeyStore selectedKeystore = keystoreList.get(keystores.getSelectionIndex());
boolean keysLoaded = loadKeys(selectedKeystore);
if (!keysLoaded)
{
ITreeNode keystoreNode = (ITreeNode) selectedKeystore;
if (keystoreNode.getNodeStatus().getCode() == IKeyStore.WRONG_KEYSTORE_TYPE_ERROR_CODE)
{
EclipseUtils.showInformationDialog(
Messages.PackageExportWizardArea_WrongKeystoreTypeDialogTitle,
NLS.bind(
Messages.PackageExportWizardArea_WrongKeystoreTypeDialogMessage,
keystoreNode.getName()));
}
restorePreviousSelections();
}
else
{
previousSelectedKeystore = getSelectedKeyStore();
previousSelectedKey = getSelectedKey();
}
setEnablement(true);
}
});
if (keystores.getItemCount() <= 0)
{
signCheckBox.setSelection(false);
}
// Add keystore buttons
buttonExisting = new Button(signingGroup, SWT.NONE);
buttonAddNew = new Button(signingGroup, SWT.NONE);
gridData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
buttonExisting.setLayoutData(gridData);
gridData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
buttonAddNew.setLayoutData(gridData);
buttonExisting.setText(Messages.PackageExportWizardArea_MenuItem_UseExistent);
buttonExisting.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
openSelectKeystoreWizard();
}
});
buttonAddNew.setText(Messages.PackageExportWizardArea_MenuItem_AddNew);
buttonAddNew.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
CreateKeystoreWizard createKeystoreWizard =
new CreateKeystoreWizard(new CreateKeystoreJobListener());
WizardDialog dialog =
new WizardDialog(parentComposite.getShell(), createKeystoreWizard);
//open the wizard to create keystores
dialog.create();
if (dialog.open() == Window.OK)
{
//user really created keystore
String keystorePassword = createKeystoreWizard.getCreatedKeystorePassword();
addKeystore(createKeystoreWizard.getCreatedKeystoreNode(), true,
keystorePassword);
//required for case when just keystore is created, but no key is created
//DO NOT call selectKeystore here because it has loadKeys, that may conflict with createKey (if a key is created), for this case the CreateKeystoreJobListener will solve the problem.
selectKeystoreWithoutLoadingKeys(createKeystoreWizard.getCreatedKeystoreNode());
}
}
});
// Key label
Label keyLabel = new Label(signingGroup, SWT.NONE);
keyLabel.setText(Messages.PACKAGE_EXPORT_WIZARD_AREA_SIGN_KEY_LABEL);
gridData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false, 1, 1);
keyLabel.setLayoutData(gridData);
// Key Combo
this.keysCombo = new Combo(signingGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
gridData = new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1);
this.keysCombo.setLayoutData(gridData);
if (keysCombo.getItemCount() <= 0)
{
signCheckBox.setSelection(false);
}
keysCombo.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
super.widgetSelected(e);
previousSelectedKey = getSelectedKey();
parentComposite.notifyListeners(SWT.Modify, new Event());
}
});
// Add keystore button
buttonAddKey = new Button(signingGroup, SWT.PUSH);
buttonAddKey.setText(Messages.PackageExportWizardArea_AddKeyButton_Text);
gridData = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
buttonAddKey.setLayoutData(gridData);
buttonAddKey.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
IKeyStore keyStore = null;
if (keystores.getSelectionIndex() >= 0)
{
keyStore =
PackageExportWizardArea.keystoreList.get(keystores.getSelectionIndex());
}
if (keyStore != null)
{
openNewKeyWizard(keyStore, new CreateKeyJobListener());
}
setEnablement(true);
}
});
setEnablement(false);
}
/**
* This class is required because when creating a new key during export, the threads are not synchronized (createKey and loadKeys).
* Otherwise, wizard page could not finish accordingly.
*/
private class CreateKeyJobListener extends JobChangeAdapter
{
/* (non-Javadoc)
* @see org.eclipse.core.runtime.jobs.JobChangeAdapter#done(org.eclipse.core.runtime.jobs.IJobChangeEvent)
*/
@Override
public void done(final IJobChangeEvent event)
{
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
{
@Override
public void run()
{
IKeyStore keyStore = ((CreateKeyJob) event.getJob()).getKeyStore();
String key = ((CreateKeyJob) event.getJob()).getCreatedKeyAlias();
loadKeys(keyStore);
selectKey(key);
}
});
}
}
/**
* This class is required because when creating a new key and new keystore during export, the threads are not synchronized (createKey and loadKeys).
* Otherwise, wizard page could not finish accordingly.
*/
private class CreateKeystoreJobListener extends JobChangeAdapter
{
/* (non-Javadoc)
* @see org.eclipse.core.runtime.jobs.JobChangeAdapter#done(org.eclipse.core.runtime.jobs.IJobChangeEvent)
*/
@Override
public void done(final IJobChangeEvent event)
{
PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
{
@Override
public void run()
{
IKeyStore keyStore = ((CreateKeyJob) event.getJob()).getKeyStore();
String key = ((CreateKeyJob) event.getJob()).getCreatedKeyAlias();
loadKeys(keyStore);
selectKeystore(keyStore);
selectKey(key);
}
});
}
}
/**
* Inserts keystores mapped into keystore combo
*/
protected void populateKeystoresFromView()
{
try
{
//when reopening wizard, we need to clear the list
if (!keystoreList.isEmpty())
{
keystoreList.clear();
keystores.removeAll();
}
if ((KeyStoreManager.getInstance() != null)
&& (KeyStoreManager.getInstance().getKeyStores() != null))
{
List<IKeyStore> keyStores = KeyStoreManager.getInstance().getKeyStores();
if (keyStores != null)
{
for (IKeyStore keyStore : keyStores)
{
insertKeystoreIntoCombo(keyStore);
}
}
}
}
catch (KeyStoreManagerException e)
{
StudioLogger.error(PackageExportWizardArea.class, "Error retrieving keystore list", //$NON-NLS-1$
e);
}
}
protected void insertKeystoreIntoCombo(IKeyStore iKeyStore)
{
File ksFile = iKeyStore.getFile();
keystores.add(ksFile.getName() + " - ( " + ksFile.getPath() + " )"); //$NON-NLS-1$ //$NON-NLS-2$
keystoreList.add(iKeyStore);
}
/**
* Adds keystore to keystores combo box and model from GUI
* @param iKeyStore
* @param canSavePassword true if create/select and need to import into view, false if selecting and does NOT need to import into the view
* @param password to retrieve keys
*/
protected void addKeystore(IKeyStore iKeyStore, boolean canSavePassword, String password)
{
keystorePasswords.put(iKeyStore, password);
insertKeystoreIntoCombo(iKeyStore);
}
/**
* Update the Default Destination The behavior is: if only one project is
* selected, then default destination text is set to the folder of this
* project if have more than one project selected or none than default
* destination text is set to workspace root
*/
private void updateDefaultDestination()
{
ArrayList<IProject> selectedProjects = getSelectedProjects();
if (this.defaultDestination.getSelection())
{
if ((selectedProjects != null) && (selectedProjects.size() == 1))
{
this.destinationText.setText(selectedProjects.get(0).getLocation().toOSString());
}
else
{
this.destinationText.setText(ResourcesPlugin.getWorkspace().getRoot().getLocation()
.toOSString());
}
}
}
/**
* Get selected projects from the tree
*
* @return
*/
private ArrayList<IProject> getSelectedProjects()
{
ArrayList<IProject> projects = new ArrayList<IProject>();
for (TreeItem item : tree.getItems())
{
if (item.getChecked())
{
projects.add((IProject) item.getData());
}
}
return projects;
}
/**
* Get selected items from the tree
*
* @return
*/
private ArrayList<TreeItem> getSelectedItems()
{
ArrayList<TreeItem> items = new ArrayList<TreeItem>();
for (TreeItem item : tree.getItems())
{
if (item.getChecked())
{
items.add(item);
}
}
return items;
}
/**
* This method creates the entire structure of the wizard page. Also, it
* stores the user input.
*
* @param parent
* Composite for all the elements.
*/
public void createControl(Composite parent)
{
Composite mainComposite = new Composite(parent, SWT.NONE);
GridLayout gridLayout = new GridLayout(3, false);
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1);
mainComposite.setLayout(gridLayout);
mainComposite.setLayoutData(gridData);
// Tree structure
this.tree = new Tree(mainComposite, SWT.CHECK | SWT.MULTI | SWT.V_SCROLL | SWT.BORDER);
gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 2);
gridData.heightHint = 150;
this.tree.setLayoutData(gridData);
this.tree.addListener(SWT.Selection, new TreeListener());
// Add all the descriptor files to the tree
populateTree();
// Select All Button
this.selectAllButton = new Button(mainComposite, SWT.PUSH);
gridData = new GridData(SWT.FILL, SWT.UP, false, false, 1, 1);
this.selectAllButton.setLayoutData(gridData);
this.selectAllButton.setText(Messages.PACKAGE_EXPORT_WIZARD_AREA_SELECT_ALL_BUTTON);
this.selectAllButton.addListener(SWT.Selection, new TreeSelectionButtonListener(true));
// Deselect All button
this.deselectAllButton = new Button(mainComposite, SWT.PUSH);
gridData = new GridData(SWT.FILL, SWT.UP, false, false, 1, 1);
this.deselectAllButton.setLayoutData(gridData);
this.deselectAllButton.setText(Messages.PACKAGE_EXPORT_WIZARD_AREA_DESELECT_ALL_BUTTON);
this.deselectAllButton.addListener(SWT.Selection, new TreeSelectionButtonListener(false));
createDestinationGroup(mainComposite);
if (this.signingEnabled)
{
createSignGroup(mainComposite);
}
String path = ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString();
Object prj = this.selection.getFirstElement();
if ((prj != null) && (this.selection.size() == 1))
{
if (prj instanceof IProject)
{
String realPath = ((IProject) prj).getLocation().toOSString();
this.destinationText.setText(realPath);
}
else if (prj instanceof IResource)
{
String realPath = path + ((IResource) prj).getProject().getFullPath().toOSString();
this.destinationText.setText(realPath);
}
}
else
{
this.destinationText.setText(path);
}
/**
* Force the focus to parent. This action make help ok
*/
if (!parent.isFocusControl())
{
parent.forceFocus();
}
}
/**
* Get all projects severities to avoid user selects erroneous projects
*/
private void validateProjects()
{
try
{
for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects())
{
if (project.isOpen())
{
int sev = project.findMaxProblemSeverity(null, true, IResource.DEPTH_INFINITE);
int projectSev;
switch (sev)
{
case IMarker.SEVERITY_ERROR:
projectSev = IMessageProvider.ERROR;
break;
case IMarker.SEVERITY_INFO:
projectSev = IMessageProvider.INFORMATION;
break;
case IMarker.SEVERITY_WARNING:
projectSev = IMessageProvider.WARNING;
break;
default:
projectSev = IMessageProvider.NONE;
break;
}
projectSeverity.put(project, new Integer(projectSev));
}
}
}
catch (CoreException e)
{
StudioLogger.error(PackageExportWizardArea.class, "Impossible to get project severity"); //$NON-NLS-1$
}
}
/**
* Can finish used in {@link IWizardPage} This method validate the page and
* change the severity/message.
*
* @return true if can finish this wizard, false otherwise
*/
public boolean canFinish()
{
String messageAux = null;
int severity_aux = IMessageProvider.NONE;
/*
* Check is has selected items
*/
if (!hasItemChecked())
{
messageAux = Messages.SELECTOR_MESSAGE_NO_SELECTION;
if (treeSelectionChanged)
{
severity_aux = IMessageProvider.ERROR;
}
else
{
severity_aux = IMessageProvider.INFORMATION;
}
}
// validate if some selected project has errors
if (messageAux == null)
{
Iterator<IProject> iterator = getSelectedProjects().iterator();
while (iterator.hasNext() && (severity_aux != IMessageProvider.ERROR))
{
severity_aux = projectSeverity.get(iterator.next());
}
if (severity_aux == IMessageProvider.ERROR)
{
messageAux = Messages.PACKAGE_EXPORT_WIZARD_AREA_PROJECTS_WITH_ERRORS_SELECTED;
}
}
/*
* Check if the selected location is valid, even if non existent.
*/
IPath path = new Path(this.destinationText.getText());
if (!this.defaultDestination.getSelection() && (messageAux == null))
{
// Test if path is blank, to warn user instead of show an error
// message
if (this.destinationText.getText().equals("")) //$NON-NLS-1$
{
messageAux = Messages.SELECTOR_MESSAGE_LOCATION_ERROR_INVALID;
severity_aux = IMessageProvider.INFORMATION;
}
/*
* Do Win32 Validation
*/
if ((messageAux == null) && Platform.getOS().equalsIgnoreCase(Platform.OS_WIN32))
{
// test path size
if (path.toString().length() > 255)
{
messageAux = Messages.SELECTOR_MESSAGE_LOCATION_ERROR_PATH_TOO_LONG;
severity_aux = IMessageProvider.ERROR;
}
String device = path.getDevice();
File deviceFile = null;
if (device != null)
{
deviceFile = new File(path.getDevice());
}
if ((device != null) && !deviceFile.exists())
{
messageAux =
Messages.SELECTOR_MESSAGE_LOCATION_ERROR_INVALID_DEVICE + " [" + device //$NON-NLS-1$
+ "]"; //$NON-NLS-1$
severity_aux = IMessageProvider.ERROR;
}
}
// test if path is absolute
if (messageAux == null)
{
if (!path.isAbsolute())
{
messageAux = Messages.SELECTOR_MESSAGE_LOCATION_ERROR_INVALID;
severity_aux = IMessageProvider.ERROR;
}
}
if (messageAux == null)
{
for (String folderName : path.segments())
{
if (!ResourcesPlugin.getWorkspace().validateName(folderName, IResource.FOLDER)
.isOK())
{
messageAux = Messages.SELECTOR_MESSAGE_LOCATION_ERROR_INVALID;
severity_aux = IMessageProvider.ERROR;
}
}
}
if ((messageAux == null) && path.toFile().exists() && !path.toFile().isDirectory())
{
messageAux = Messages.SELECTOR_MESSAGE_LOCATION_ERROR_NOT_DIRECTORY;
severity_aux = IMessageProvider.ERROR;
}
}
/*
* Check if there are available certificates and if selection isn't null
*/
if (messageAux == null)
{
if (this.signingEnabled && (this.signCheckBox != null)
&& this.signCheckBox.getSelection()
&& !((this.keystores != null) && (this.keystores.getItemCount() > 0)))
{
messageAux = Messages.PACKAGE_EXPORT_WIZARD_AREA_SIGN_NO_KEYSTORE_AVAILABLE;
severity_aux = IMessageProvider.ERROR;
}
else if (this.signCheckBox.getSelection()
&& !((this.keysCombo != null) && (this.keysCombo.getItemCount() > 0)
&& (this.keysCombo.getSelectionIndex() >= 0)
&& (this.keysCombo.getItem(this.keysCombo.getSelectionIndex()) != null) && !this.keysCombo
.getItem(this.keysCombo.getSelectionIndex()).equals(""))) //$NON-NLS-1$
{
messageAux = Messages.PACKAGE_EXPORT_WIZARD_AREA_SIGN_NO_KEYSTORE_OR_KEY_SELECTED;
severity_aux = IMessageProvider.ERROR;
}
}
if (messageAux == null)
{
if (!this.signCheckBox.getSelection())
{
messageAux = Messages.PACKAGE_EXPORT_WIZARD_AREA_UNSIGNEDPACKAGE_WARNING;
severity_aux = IMessageProvider.WARNING;
}
}
/*
* Setting message
*/
if (messageAux == null)
{
messageAux = Messages.PACKAGE_EXPORT_WIZARD_AREA_DESCRIPTION;
severity_aux = IMessageProvider.NONE;
}
this.message = messageAux;
this.severity = severity_aux;
boolean result;
switch (severity_aux)
{
case IMessageProvider.ERROR:
// ERROR. can't finish wizard
result = false;
break;
case IMessageProvider.WARNING:
// WARNING. ok to finish the wizard
result = true;
break;
case IMessageProvider.INFORMATION:
// INFORMATION. Path is empty, so it's NOT OK to finish the wizard
result = false;
break;
default:
// by default, canFinish returns true
result = true;
break;
}
return result;
}
/**
* Check if we have at least one item checked
*
* @param items
* @return true if some of tree item is checked, false otherwise
*/
private boolean hasItemChecked()
{
boolean checked = false;
TreeItem[] items = tree.getItems();
int i = 0;
while (!checked && (i < items.length))
{
if (items[i].getChecked())
{
checked = true;
}
i++;
}
return checked;
}
/**
* Check if the destination folder is valid during finish action If the
* package don't exist, ask to create
*
* @return true if the destination is valid
* @throws CoreException
* when errors with directory creation occurs
*/
private boolean checkDestination() throws CoreException
{
boolean destinationOK = true;
if (!defaultDestination.getSelection())
{
File destination = new File(destinationText.getText());
if (!destination.exists())
{
destinationOK = createDestinationFolderDialog();
if (destinationOK)
{
if (!destination.mkdirs())
{
throw new CoreException(new Status(IStatus.ERROR,
PackagingUIPlugin.PLUGIN_ID,
Messages.PACKAGE_EXPORT_WIZARD_AREA_ERROR_DESTINATION_CHECK));
}
}
}
}
else
{
for (TreeItem item : getSelectedItems())
{
IProject project = (IProject) item.getData();
IPath dist =
project.getLocation().append(
CertificateManagerActivator.PACKAGE_PROJECT_DESTINATION);
File file = dist.toFile();
if (file.exists() && !file.isDirectory())
{
if (!file.delete())
{
throw new CoreException(new Status(IStatus.ERROR,
PackagingUIPlugin.PLUGIN_ID,
Messages.PACKAGE_EXPORT_WIZARD_AREA_ERROR_DESTINATION_CHECK));
}
}
if (!file.exists())
{
if (!file.mkdir())
{
throw new CoreException(new Status(IStatus.ERROR,
PackagingUIPlugin.PLUGIN_ID,
Messages.PACKAGE_EXPORT_WIZARD_AREA_ERROR_DESTINATION_CHECK));
}
}
project.refreshLocal(IResource.DEPTH_ONE, new NullProgressMonitor());
}
}
return destinationOK;
}
/**
* Create a destination folder, asking user's permission
*
* @return
*/
private boolean createDestinationFolderDialog()
{
MessageBox box =
new MessageBox(parentComposite.getShell(), SWT.ICON_QUESTION | SWT.YES | SWT.NO);
box.setMessage(Messages.PACKAGE_EXPORT_WIZARD_AREA_CREATE_DIRECTORIES_BOX_MESSAGE);
box.setText(Messages.PACKAGE_EXPORT_WIZARD_AREA_CREATE_DIRECTORIES_BOX_TITLE);
return box.open() == SWT.YES;
}
/**
* do the finish: Create the package for each selected descriptor
*/
public boolean performFinish()
{
final boolean[] finished =
{
false
};
boolean destOK = false;
final MultiStatus status =
new MultiStatus(PackagingUIPlugin.PLUGIN_ID, IStatus.OK, "", null); //$NON-NLS-1$
ProgressMonitorDialog monitorDialog = null;
String DESCRIPTION_TO_LOG = StudioLogger.DESCRIPTION_DEFAULT;
try
{
destOK = checkDestination();
}
catch (CoreException e)
{
status.add(e.getStatus());
}
if (destOK)
{
monitorDialog = new ProgressMonitorDialog(parentComposite.getShell());
try
{
monitorDialog.run(false, false, new IRunnableWithProgress()
{
@Override
public void run(IProgressMonitor aMonitor) throws InvocationTargetException,
InterruptedException
{
int finishSize =
getSelectedItems().size()
* PackagingUIPlugin.PROGRESS_MONITOR_MULTIPLIER;
SubMonitor monitor = SubMonitor.convert(aMonitor);
monitor.beginTask(Messages.PACKAGE_EXPORT_WIZARD_AREA_FINISH_ACTION_LABEL,
finishSize);
IPath exportDestinationFolder = new Path(destinationText.getText());
IPath exportDestinationFile = null;
for (TreeItem item : getSelectedItems())
{
// get the eclipse project as a java project to get
// the project
// destination
IProject eclipseProject = (IProject) item.getData();
try
{
monitor.worked(PackagingUIPlugin.PROGRESS_MONITOR_MULTIPLIER / 4);
JavaProject javaProject = new JavaProject();
javaProject.setProject(eclipseProject);
// find all packages built by Android builder
Map<String, String> apkConfigurations =
SdkUtils.getAPKConfigurationsForProject(eclipseProject);
Set<String> apkConfNames = new HashSet<String>();
if (apkConfigurations != null)
{
apkConfNames.addAll(apkConfigurations.keySet());
}
apkConfNames.add(""); // the default package //$NON-NLS-1$
SubMonitor submonitor =
monitor.newChild(PackagingUIPlugin.PROGRESS_MONITOR_MULTIPLIER / 4);
submonitor.beginTask(
Messages.PACKAGE_EXPORT_WIZARD_AREA_EXPORTING_ACTION_LABEL,
3 * PackagingUIPlugin.PROGRESS_MONITOR_MULTIPLIER
* apkConfNames.size());
for (String apkConfName : apkConfNames)
{
String apkName =
eclipseProject.getName()
+ (apkConfName.isEmpty() ? apkConfName : "-" //$NON-NLS-1$ //$NON-NLS-2$
+ apkConfName);
if (defaultDestination.getSelection())
{
exportDestinationFolder =
eclipseProject
.getLocation()
.append(CertificateManagerActivator.PACKAGE_PROJECT_DESTINATION);
}
exportDestinationFile =
exportDestinationFolder
.append(apkName)
.addFileExtension(
CertificateManagerActivator.PACKAGE_EXTENSION);
File file = exportDestinationFile.toFile();
submonitor
.worked(PackagingUIPlugin.PROGRESS_MONITOR_MULTIPLIER);
//always export unsigned package
AdtUtils.exportUnsignedReleaseApk(javaProject.getProject(),
file, submonitor);
submonitor
.worked(PackagingUIPlugin.PROGRESS_MONITOR_MULTIPLIER);
if (signCheckBox.getSelection())
{
//sign the package if required
IStatus signStatus = signPackage(eclipseProject, file);
status.add(signStatus);
}
//zipalign the file and we are done exporting the package
PackageFile.zipAlign(file);
submonitor
.worked(PackagingUIPlugin.PROGRESS_MONITOR_MULTIPLIER);
}
submonitor.done();
}
catch (CoreException e)
{
StudioLogger.error(PackageExportWizardArea.class,
"Error while building project or getting project output folder" //$NON-NLS-1$
+ eclipseProject.getName(), e);
status.add(new Status(IStatus.ERROR, PackagingUIPlugin.PLUGIN_ID,
Messages.PACKAGE_EXPORT_WIZARD_AREA_ERROR_PROJECT_BUILD
+ " " + eclipseProject.getName())); //$NON-NLS-1$
}
finally
{
try
{
eclipseProject.refreshLocal(
IResource.DEPTH_INFINITE,
monitor.newChild(PackagingUIPlugin.PROGRESS_MONITOR_MULTIPLIER / 4));
}
catch (CoreException e)
{
// do nothing
}
}
monitor.worked(PackagingUIPlugin.PROGRESS_MONITOR_MULTIPLIER / 4);
}
finished[0] = true;
}
});
}
catch (Exception e)
{
StudioLogger.warn("Error finishing package export.");
}
}
if (!status.isOK())
{
status.getMessage();
DESCRIPTION_TO_LOG = Messages.PACKAGE_EXPORT_WIZARD_AREA_READONLY_TITLE;
ErrorDialog.openError(parentComposite.getShell(),
Messages.PACKAGE_EXPORT_WIZARD_AREA_READONLY_TITLE,
Messages.PACKAGE_EXPORT_WIZARD_AREA_READONLY_MESSAGE, status);
}
// Saving usage data
try
{
StudioLogger.collectUsageData(StudioLogger.WHAT_APP_MANAGEMENT_PACKAGE,
StudioLogger.KIND_APP_MANAGEMENT, DESCRIPTION_TO_LOG,
PackagingUIPlugin.PLUGIN_ID, PackagingUIPlugin.getDefault().getBundle()
.getVersion().toString());
}
catch (Throwable e)
{
// Do nothing, but error on the log should never prevent app from
// working
}
return finished[0];
}
/**
*
* @return key entry password
*/
public String getKeyEntryPassword()
{
String keyEntryPassword = new String();
try
{
keyEntryPassword =
getSelectedKeyStore().getPasswordProvider().getPassword(
this.keysCombo.getItem(this.keysCombo.getSelectionIndex()), true);
}
catch (KeyStoreManagerException e)
{
StudioLogger.error(this.getClass(), "Error retrieving keys entry password", e); //$NON-NLS-1$
}
return keyEntryPassword;
}
/**
* @param eclipseProject The project being exported.
* @param exportedPackage The package to be signed
* @throws InvalidPasswordException
* @throws KeyStoreManagerException
*/
private IStatus signPackage(IProject eclipseProject, File exportedPackage)
{
IStatus status = Status.OK_STATUS;
String keyAlias = keysCombo.getItem(keysCombo.getSelectionIndex());
String keystorePassword = getKeyStorePassword(getSelectedKeyStore());
String keyPassword = getKeyEntryPassword();
JarFile jar = null;
try
{
PackageFile pack = null;
boolean keepTrying;
if (keyPassword != null)
{
keepTrying = true;
}
else
{
keepTrying = false;
}
while (keepTrying)
{
try
{
// Open package and remove signature
jar = new JarFile(exportedPackage);
pack = new PackageFile(jar);
pack.removeMetaEntryFiles();
// Sign the new package
PackageFileSigner.signPackage(pack,
getSelectedKeyStore().getEntry(keyAlias, keystorePassword),
keyPassword, PackageFileSigner.MOTODEV_STUDIO);
keepTrying = false;
}
catch (UnrecoverableKeyException sE)
{
try
{
keyPassword =
getSelectedKeyStore().getPasswordProvider().getPassword(keyAlias,
true, false);
}
catch (KeyStoreManagerException e)
{
status =
new Status(Status.ERROR, CertificateManagerActivator.PLUGIN_ID,
e.getMessage());
StudioLogger.error(PackageExportWizardArea.this.getClass(),
"Could not retrieve key password on export: " + e.getMessage()); //$NON-NLS-1$
}
if (keyPassword == null)
{
keepTrying = false;
status = Status.CANCEL_STATUS;
}
else
{
keepTrying = true;
}
}
catch (InvalidPasswordException e)
{
// Should never happen as the entry alias is only available if the keystore password
// was typed correctly.
// Unless the user changed the keystore password outside the tool while exporting the package.
status =
new Status(Status.ERROR, CertificateManagerActivator.PLUGIN_ID,
e.getMessage());
}
catch (KeyStoreManagerException e)
{
// Should never happen as the entry alias is only available if the keystore password
// was typed correctly.
// Unless the user changed the keystore password outside the tool while exporting the package.
status =
new Status(Status.ERROR, CertificateManagerActivator.PLUGIN_ID,
e.getMessage());
}
}
if (status.isOK())
{
FileOutputStream fileToWrite = null;
try
{
// Write the new package file
fileToWrite = new FileOutputStream(exportedPackage);
pack.write(fileToWrite);
}
finally
{
fileToWrite.close();
}
}
else
{
EclipseUtils.showErrorDialog("Package Signing", "Could not sign the package.");
}
}
catch (IOException e)
{
StudioLogger.error(PackageExportWizardArea.this.getClass(),
"Could not sign the package: " + e.getMessage()); //$NON-NLS-1$
status =
new Status(IStatus.ERROR, PackagingUIPlugin.PLUGIN_ID,
Messages.PackageExportWizardArea_ErrorWritingSignedPackageFile + " " //$NON-NLS-1$
+ eclipseProject.getName());
}
catch (SignException e)
{
StudioLogger.error(PackageExportWizardArea.this.getClass(),
"Could not sign the package: " + e.getMessage()); //$NON-NLS-1$
status =
new Status(IStatus.ERROR, PackagingUIPlugin.PLUGIN_ID,
Messages.PackageExportWizardArea_ErrorSigningPackage
+ " " + eclipseProject.getName()); //$NON-NLS-1$
}
finally
{
try
{
jar.close();
}
catch (IOException e)
{
StudioLogger.error(PackageExportWizardArea.this.getClass(),
"Could not sign the package: " + e.getMessage()); //$NON-NLS-1$
}
}
return status;
}
/**
* Get the area message
*
* @return the message for the wizard
*/
public String getMessage()
{
return this.message;
}
/**
* Get the area error severity
*
* @return
*/
public int getSeverity()
{
return this.severity;
}
/**
* "Browser..." button for package destination.
*
*/
private class PackageDestinationButtonListener implements Listener
{
/*
* (non-Javadoc)
*
* @see
* org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
* .Event)
*/
@Override
public void handleEvent(Event event)
{
String path = destinationText.getText();
if (path.equals("")) //$NON-NLS-1$
{
path =
ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString()
.subSequence(0, 2).toString();
}
String executablePath = directoryDialog(path);
if ((executablePath != null) && !executablePath.equals("")) //$NON-NLS-1$
{
destinationText.setText(executablePath);
}
parentComposite.notifyListeners(SWT.Modify, new Event());
}
}
/**
* Update the default destination status
*
*/
private class DestinationTextListener implements Listener
{
@Override
public void handleEvent(Event event)
{
if (!defaultDestination.getSelection())
{
parentComposite.notifyListeners(SWT.Modify, new Event());
}
}
}
/**
* A Listener for the Tree.
*
*/
private class TreeListener implements Listener
{
@Override
public void handleEvent(Event event)
{
updateDefaultDestination();
parentComposite.notifyListeners(SWT.Modify, new Event());
treeSelectionChanged = true;
}
}
/**
* Enable Destination Text.
*
*/
private class DefaultDestinationListener implements Listener
{
/*
* (non-Javadoc)
*
* @see
* org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
* .Event)
*/
@Override
public void handleEvent(Event event)
{
Button defaultDestination = (Button) event.widget;
destinationText.setEnabled(!defaultDestination.getSelection());
packageDestinationBrowseButton.setEnabled(!defaultDestination.getSelection());
if (defaultDestination.getSelection())
{
updateDefaultDestination();
}
else
{
destinationText.setText(""); //$NON-NLS-1$
}
destinationText.notifyListeners(SWT.Modify, new Event());
parentComposite.notifyListeners(SWT.Modify, new Event());
}
}
/**
*
* @param notify Notifies listener that validates if Finish can be enabled
*/
private void setEnablement(boolean notify)
{
boolean signEnabled = signCheckBox.getSelection();
keysCombo.setEnabled(signEnabled);
keystores.setEnabled(signEnabled);
buttonAddKey.setEnabled(signEnabled);
//toolbar.setEnabled(signEnabled);
buttonExisting.setEnabled(signEnabled);
buttonAddNew.setEnabled(signEnabled);
if (signEnabled)
{
if (keystores.getSelectionIndex() < 0)
{
//no keystore selected, clear keys combo
buttonAddKey.setEnabled(false);
keysCombo.setEnabled(false);
keysCombo.removeAll();
}
if (keystores.getItemCount() <= 0)
{
keysCombo.setEnabled(false);
keystores.setEnabled(false);
buttonAddKey.setEnabled(false);
//toolbar.setEnabled(true);
buttonExisting.setEnabled(signEnabled);
buttonAddNew.setEnabled(signEnabled);
}
}
if (notify)
{
parentComposite.notifyListeners(SWT.Modify, new Event());
}
}
protected void openSelectKeystoreWizard()
{
SelectExistentKeystoreWizard selectExistentKeystoreWizard =
new SelectExistentKeystoreWizard();
WizardDialog dialog =
new WizardDialog(parentComposite.getShell(), selectExistentKeystoreWizard);
//open the wizard to select keystores
dialog.create();
if (dialog.open() == Window.OK)
{
//keystore was really selected : adding keystore to the list
IKeyStore iKeyStore = selectExistentKeystoreWizard.getSelectedKeystore();
boolean canSavePassword = selectExistentKeystoreWizard.canSavePassword();
String password = selectExistentKeystoreWizard.getPassword();
addKeystore(iKeyStore, canSavePassword, password);
selectKeystore(iKeyStore);
}
}
/**
* This method must be used to retrieve the passwod of any keystore in the context of this wizard.
* It is purpose is to cache the passwords of the keystores, mainly of the ones that do not have its password saved,
* so the password will be asked only once for each keystore, during the lifetime of this wizard.
* */
protected String getKeyStorePassword(IKeyStore keystore)
{
String password = keystorePasswords.get(keystore);
//check if password is already cached
if (password == null)
{
password = keystore.getKeyStorePassword(true);
}
if (password != null)
{
keystorePasswords.put(keystore, password);
}
return password;
}
/**
* Sign button listener to enable/disable combos, buttons and finish/next
*
*/
private class SignButtonListener implements Listener
{
/*
* (non-Javadoc)
*
* @see
* org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
* .Event)
*/
@Override
public void handleEvent(Event event)
{
if (event.widget == signCheckBox)
{
setEnablement(true);
}
}
}
/**
* This class will handle the (Des)Select All buttons
*
*/
private class TreeSelectionButtonListener implements Listener
{
private final boolean checked;
/**
* Create a new instance of the listener with the desired check state
*
* @param selectItems
*/
public TreeSelectionButtonListener(boolean selectItems)
{
this.checked = selectItems;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets
* .Event)
*/
@Override
public void handleEvent(Event event)
{
for (TreeItem item : tree.getItems())
{
item.setChecked(checked);
}
updateDefaultDestination();
parentComposite.notifyListeners(SWT.Modify, new Event());
treeSelectionChanged = true;
}
}
}