/*
* Copyright (c) 2010-2012 Research In Motion Limited. All rights reserved.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License, Version 1.0,
* which accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*
*/
package net.rim.ejde.internal.menu;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.rim.ejde.internal.core.ContextManager;
import net.rim.ejde.internal.core.IConstants;
import net.rim.ejde.internal.launching.DeviceInfo;
import net.rim.ejde.internal.launching.DeviceProfileManager;
import net.rim.ejde.internal.model.preferences.CleanSimulatorPreferences;
import net.rim.ejde.internal.ui.dialogs.CleanSimulatorDialog;
import net.rim.ejde.internal.ui.dialogs.CleanSimulatorTreeItem;
import net.rim.ejde.internal.ui.dialogs.CleanSimulatorTreeItem.ItemId;
import net.rim.ejde.internal.ui.dialogs.CleanSimulatorTreeItem.ItemType;
import net.rim.ejde.internal.ui.dialogs.CleanSimulatorTreeItemExternal;
import net.rim.ejde.internal.ui.dialogs.CleanSimulatorTreeItemInternal;
import net.rim.ejde.internal.util.FileUtils;
import net.rim.ejde.internal.util.Messages;
import net.rim.ejde.internal.util.VMUtils;
import net.rim.ide.RIA;
import net.rim.ide.core.IDEProperties;
import org.apache.log4j.Logger;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ICheckStateProvider;
import org.eclipse.jface.viewers.IColorDecorator;
import org.eclipse.jface.viewers.ILabelDecorator;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
/**
* CleanSimulatorCommandHandler
*
* @author bkurz
*
*/
public class CleanSimulatorCommandHandler extends AbstractHandler {
private static final Logger _log = Logger.getLogger( CleanSimulatorCommandHandler.class );
@Override
public Object execute( ExecutionEvent event ) throws ExecutionException {
List< CleanSimulatorTreeItem > treeStructure = createTreeStructure();
// Create and display clean simulator dialog
CleanSimulatorDialog dialog = new CleanSimulatorDialog( ContextManager.getActiveWorkbenchShell(),
new TreeLabelProvider(), new ColorLabelDecorator(), new TreeContentProvider(), new CheckStateProvider() );
dialog.setTitle( Messages.CLEAN_SIMULATOR_DIALOG_TITLE );
dialog.setMessage( Messages.CLEAN_SIMULATOR_DIALOG_MESSAGE );
dialog.setInput( treeStructure );
dialog.open();
// Execute clean for all checked items returned from the clean simulator
// dialog and set preferences
final Object[] result = dialog.getResult();
if( result != null ) {
executeClean( result );
CleanSimulatorPreferences.setCleanSimulatorPreferences( treeStructure );
}
return null;
}
/**
* Creates the tree structure for the clean options for internal SDKs and external simulator bundles
*
* @return
*/
private List< CleanSimulatorTreeItem > createTreeStructure() {
List< IVMInstall > installedSDK = VMUtils.getInstalledBBVMs();
List< CleanSimulatorTreeItem > treeStructure = new ArrayList< CleanSimulatorTreeItem >();
CleanSimulatorTreeItem rootItem;
if( installedSDK.size() == 0 ) {
return treeStructure;
}
// Create tree structure for internal simulator bundles
for( IVMInstall ivmInstall : installedSDK ) {
// list only those CPs that have simulator
List< DeviceInfo > deviceProfiles = DeviceProfileManager.getInstance().getInternalDeviceProfiles( ivmInstall );
if( !deviceProfiles.isEmpty() ) {
rootItem = createModelInternalBundel( ivmInstall );
treeStructure.add( rootItem );
}
}
// Create tree structure for external simulator bundles
List< DeviceInfo > deviceProfiles = DeviceProfileManager.getInstance().getExternalDeviceProfiles();
for( DeviceInfo deviceProfile : deviceProfiles ) {
rootItem = createModelExternalBundle( deviceProfile );
treeStructure.add( rootItem );
}
return CleanSimulatorPreferences.getCleanSimulatorPreferences( treeStructure );
}
/**
* Schedules and executes the clean job for all selected SDKs and external simulator bundles
*
* @param result
*/
private void executeClean( final Object[] result ) {
Job cleanJob = new Job( Messages.CLEAN_SIMULATOR_JOB_TITLE ) {
@Override
protected IStatus run( IProgressMonitor monitor ) {
IStatus status;
monitor.beginTask( Messages.CLEAN_SIMULATOR_JOB_TITLE, result.length );
status = executeCleanJob( result, monitor );
monitor.done();
return status;
}
};
cleanJob.setUser( true );
cleanJob.schedule();
}
/**
* Executes the clean job for all selectes SDKs and external simulator bundles
*
* @param result
* @param monitor
* @return
*/
private IStatus executeCleanJob( final Object[] result, IProgressMonitor monitor ) {
List< DeviceInfo > deviceProfiles = new ArrayList< DeviceInfo >();
DeviceInfo externalDeviceProfile = null;
IVMInstall vmInstall = null;
RIA ria = null;
CleanSimulatorTreeItem bbTreeItem;
for( Object item : result ) {
if( monitor != null && monitor.isCanceled() ) {
return Status.CANCEL_STATUS;
}
bbTreeItem = (CleanSimulatorTreeItem) item;
if( bbTreeItem.getItemType().equals( ItemType.INTERNAL_BUNDLE ) ) {
CleanSimulatorTreeItemInternal bbTreeItemInternal = (CleanSimulatorTreeItemInternal) bbTreeItem;
if( vmInstall == null || !vmInstall.equals( bbTreeItemInternal.getVMInstall() ) ) {
vmInstall = bbTreeItemInternal.getVMInstall();
ria = ContextManager.PLUGIN.getRIA( vmInstall.getInstallLocation().getPath() );
deviceProfiles = DeviceProfileManager.getInstance().getInternalDeviceProfiles( vmInstall );
}
} else if( bbTreeItem.getItemType().equals( ItemType.EXTERNAL_BUNDLE ) ) {
ria = ContextManager.PLUGIN.getRIA( VMUtils.getLatestSDK().getInstallLocation().getPath() );
externalDeviceProfile = DeviceProfileManager.getInstance().getExternalDeviceProfile(
bbTreeItem.getRootItem().getItemName() );
}
// Clean applications
if( bbTreeItem.getItemID().equals( ItemId.CLEAN_SIMULATOR_DIRECTORY ) ) {
cleanSimulator( bbTreeItem.getItemType().equals( ItemType.INTERNAL_BUNDLE ) ? deviceProfiles.get( 0 )
: externalDeviceProfile );
}
// Search for and clean devices
if( bbTreeItem.getItemType().equals( ItemType.INTERNAL_BUNDLE ) ) {
for( DeviceInfo deviceProfile : deviceProfiles ) {
cleanRIA( bbTreeItem, ria, deviceProfile );
}
} else if( bbTreeItem.getItemType().equals( ItemType.EXTERNAL_BUNDLE ) ) {
cleanRIA( bbTreeItem, ria, externalDeviceProfile );
}
if( monitor != null ) {
monitor.worked( 1 );
}
}
return Status.OK_STATUS;
}
/**
*
* @param item
* @param ria
*/
private void cleanRIA( CleanSimulatorTreeItem item, RIA ria, DeviceInfo device ) {
updateRIA( ria, device );
String deviceBundleName = device.getBundleName();
String consoleOutput = " (" + device.getDeviceName() + ")";
switch( item.getItemID() ) {
case ERASE_FILE_SYSTEM:
ria.eraseFileSystem();
_log.debug( Messages.CLEAN_SIMULATOR_ERASE_FILE_SYSTEM_DEBUG_MSG + deviceBundleName + consoleOutput );
break;
case ERASE_NON_VOLATILE_MEMORY:
ria.eraseNvStore();
_log.debug( Messages.CLEAN_SIMULATOR_ERASE_NON_VOLATILE_MEMORY_DEBUG_MSG + deviceBundleName + consoleOutput );
break;
case ERASE_REMOVABLE_MEMORY:
ria.eraseSDCard();
_log.debug( Messages.CLEAN_SIMULATOR_ERASE_REMOVABLE_DIRECTORY_DEBUG_MSG + deviceBundleName + consoleOutput );
break;
}
}
/**
* Cleans the applications (.cod and .debug files) from the simulator specified
*
* @param deviceProfile
*/
private static void cleanSimulator( DeviceInfo deviceProfile ) {
_log.info( Messages.CLEAN_SIMULATOR_CLEAN_SIMULATOR_DIRECTORY_DEBUG_MSG + " " + deviceProfile.getDirectory() );
IPath path = new Path( deviceProfile.getDirectory() ).append( IConstants.SIMULATOR_MANIFEST_FILE_NAME );
cleanSimulator( path );
}
/**
* Cleans the applications (.cod and .debug files) from the specified simulator directory
*
* @param path
*/
private static void cleanSimulator( IPath path ) {
File f = path.toFile();
if( f.exists() ) {
File[] files = f.getParentFile().listFiles();
List< String > manifestFiles = FileUtils.readFile( f );
String fileExtension;
if( manifestFiles == null ) {
_log.error( NLS.bind( Messages.CLEAN_SIMULATOR_DIR_CORRUPT_MSG, f.getParent() ) );
showCleanError( NLS.bind( Messages.CLEAN_SIMULATOR_DIR_CORRUPT_MSG, f.getParent() ) );
} else if( !f.canWrite() ) {
_log.error( NLS.bind( Messages.CLEAN_SIMULATOR_MANIFEST_PERM_MSG, path ) );
showCleanError( NLS.bind( Messages.CLEAN_SIMULATOR_MANIFEST_PERM_MSG, path ) );
} else {
manifestFiles = fixManifestFile( f, manifestFiles );
boolean first = true;
for( File file : files ) {
fileExtension = FileUtils.getFileExtension( file );
if( !manifestFiles.contains( file.getName() ) && file.isFile() && !file.equals( f )
&& !fileExtension.equals( IConstants.SIMULATOR_DMP_FILE_EXTENSION ) ) {
if( file.exists() && !file.delete() ) {
String msg1 = Messages.CLEAN_SIMULATOR_CANNOT_DEL_FILE_MSG + "'" + file.getName() + "'";
final String msg2 = msg1 + "\n"
+ NLS.bind( Messages.CLEAN_SIMULATOR_CHECK_PERM_MSG, file.getParent() );
_log.error( msg1 );
if( first ) { // pop a dialog only for the 1st artifact that could not be deleted
showCleanError( msg2 );
first = false;
}
}
}
}
}
} else {
_log.error( NLS.bind( Messages.CLEAN_SIMULATOR_MANIFEST_MISSING_MSG, path ) );
showCleanError( NLS.bind( Messages.CLEAN_SIMULATOR_MANIFEST_MISSING_MSG, path ) );
}
}
private static List< String > fixManifestFile( File f, List< String > manifestFiles ) {
// Fix for MKS2085690 and MKS2024707- when _manifest does not contains the _manefest
// entry itself we will write the entry.
FileWriter fw = null;
BufferedWriter bw = null;
try {
fw = new FileWriter( f, true );
bw = new BufferedWriter( fw );
if( !manifestFiles.contains( f.getName() ) || !manifestFiles.contains( "uninst.exe" )
|| !manifestFiles.contains( "Uninstall.dat" ) ) {
bw.append( '\n' );
}
if( !manifestFiles.contains( f.getName() ) ) {
_log.info( "_manifest file updated with \"" + f.getName() + "\" entry" );
bw.write( f.getName() + "\n" );
}
// produced by installer
if( !manifestFiles.contains( "uninst.exe" ) ) {
bw.write( "uninst.exe\n" );
manifestFiles.add( "uninst.exe\n" );
_log.info( "_manifest file updated with \"uninst.exe\" entry" );
}
if( !manifestFiles.contains( "Uninstall.dat" ) ) {
bw.write( "Uninstall.dat" );
manifestFiles.add( "Uninstall.dat" );
_log.info( "_manifest file updated with \"Uninstall.dat\" entry" );
}
} catch( IOException e ) {
_log.error( NLS.bind( Messages.CLEAN_SIMULATOR_MANIFEST_NOT_REPAIR_MSG, f.getAbsolutePath() ) );
showCleanError( NLS.bind( Messages.CLEAN_SIMULATOR_MANIFEST_NOT_REPAIR_MSG, f.getAbsolutePath() ) );
} finally {
if( bw != null )
try {
bw.close();
} catch( IOException e ) {
;
}
}
return manifestFiles;
}
private static void showCleanError( final String msg ) {
Runnable r = new Runnable() {
public void run() {
MessageDialog.openError( ContextManager.getActiveWorkbenchShell(),
Messages.CLEAN_SIMULATOR_ERASE_SIMULATOR_FILES_LABEL, msg );
}
};
ContextManager.getDisplay().asyncExec( r );
}
/**
*
* @param ria
* @param deviceProfile
*/
private void updateRIA( RIA ria, DeviceInfo deviceProfile ) {
IPath path = new Path( deviceProfile.getDirectory() ).append( IConstants.FLEDGE_FILE_NAME );
String commandLine = "\"" + path + "\" /handheld=" + deviceProfile.getDeviceName() + " /session="
+ deviceProfile.getDeviceName();
String workingDirectory = deviceProfile.getDirectory();
IDEProperties ideProperties = ria.getProperties();
ideProperties.putStringProperty( "SimulatorDirectory", workingDirectory );
ideProperties.putStringProperty( "SimulatorCommand", commandLine );
}
/**
* Creates the tree structure for the specified SDK
*
* @param vmInstall
* @return
*/
private CleanSimulatorTreeItem createModelInternalBundel( IVMInstall vmInstall ) {
CleanSimulatorTreeItemInternal item = new CleanSimulatorTreeItemInternal( vmInstall, ItemId.SDK, vmInstall.getName(),
new CleanSimulatorTreeItem[] {
new CleanSimulatorTreeItemInternal( vmInstall, ItemId.CLEAN_SIMULATOR_DIRECTORY,
Messages.CLEAN_SIMULATOR_CLEAN_SIMULATOR_DIRECTORY_LABEL ),
new CleanSimulatorTreeItemInternal( vmInstall, ItemId.ERASE_FILE_SYSTEM,
Messages.CLEAN_SIMULATOR_ERASE_FILE_SYSTEM_LABEL ),
new CleanSimulatorTreeItemInternal( vmInstall, ItemId.ERASE_REMOVABLE_MEMORY,
Messages.CLEAN_SIMULATOR_ERASE_REMOVABLE_MEMORY_LABEL ),
new CleanSimulatorTreeItemInternal( vmInstall, ItemId.ERASE_NON_VOLATILE_MEMORY,
Messages.CLEAN_SIMULATOR_ERASE_NON_VOLATILE_MEMORY_LABEL ) } );
return item;
}
/**
* Creates the tree structure for the specified SDK
*
* @param deviceProfile
* @return
*/
private CleanSimulatorTreeItem createModelExternalBundle( DeviceInfo deviceProfile ) {
CleanSimulatorTreeItemExternal item = new CleanSimulatorTreeItemExternal( deviceProfile, ItemId.SDK,
deviceProfile.getBundleName(), new CleanSimulatorTreeItem[] {
new CleanSimulatorTreeItemExternal( deviceProfile, ItemId.CLEAN_SIMULATOR_DIRECTORY,
Messages.CLEAN_SIMULATOR_CLEAN_SIMULATOR_DIRECTORY_LABEL ),
new CleanSimulatorTreeItemExternal( deviceProfile, ItemId.ERASE_FILE_SYSTEM,
Messages.CLEAN_SIMULATOR_ERASE_FILE_SYSTEM_LABEL ),
new CleanSimulatorTreeItemExternal( deviceProfile, ItemId.ERASE_REMOVABLE_MEMORY,
Messages.CLEAN_SIMULATOR_ERASE_REMOVABLE_MEMORY_LABEL ),
new CleanSimulatorTreeItemExternal( deviceProfile, ItemId.ERASE_NON_VOLATILE_MEMORY,
Messages.CLEAN_SIMULATOR_ERASE_NON_VOLATILE_MEMORY_LABEL ) } );
return item;
}
/**
* Implementation of a tree label provider
*
* @author bkurz
*
*/
private class TreeLabelProvider extends LabelProvider {
@Override
public Image getImage( Object element ) {
return null;
}
@Override
public String getText( Object element ) {
CleanSimulatorTreeItem item = (CleanSimulatorTreeItem) element;
return item.getItemName();
}
}
/**
* Implementation of a tree content provider
*
* @author bkurz
*
*/
private class TreeContentProvider extends ArrayContentProvider implements ITreeContentProvider {
@Override
public Object[] getChildren( Object parentElement ) {
CleanSimulatorTreeItem item = (CleanSimulatorTreeItem) parentElement;
return item.getChildItems();
}
@Override
public Object getParent( Object element ) {
CleanSimulatorTreeItem item = (CleanSimulatorTreeItem) element;
return item.getParentItem();
}
@Override
public boolean hasChildren( Object element ) {
CleanSimulatorTreeItem item = (CleanSimulatorTreeItem) element;
return ( item.hasChildItems() );
}
}
/**
* Implementation of a check state provider
*
* @author bkurz
*
*/
private class CheckStateProvider implements ICheckStateProvider {
@Override
public boolean isChecked( Object element ) {
CleanSimulatorTreeItem item = (CleanSimulatorTreeItem) element;
return item.isChecked();
}
@Override
public boolean isGrayed( Object element ) {
CleanSimulatorTreeItem item = (CleanSimulatorTreeItem) element;
return item.isGrayed();
}
}
/**
*
* @author bkurz
*
*/
private class ColorLabelDecorator implements ILabelDecorator, IColorDecorator {
@Override
public Image decorateImage( Image image, Object element ) {
return null;
}
@Override
public String decorateText( String text, Object element ) {
return text;
}
@Override
public void addListener( ILabelProviderListener listener ) {
// Do nothing
}
@Override
public void dispose() {
// Do nothing
}
@Override
public boolean isLabelProperty( Object element, String property ) {
return false;
}
@Override
public void removeListener( ILabelProviderListener listener ) {
// Do nothing
}
@Override
public Color decorateBackground( Object element ) {
return Display.getCurrent().getSystemColor( SWT.COLOR_LIST_BACKGROUND );
}
@Override
public Color decorateForeground( Object element ) {
CleanSimulatorTreeItem item = (CleanSimulatorTreeItem) element;
if( !item.isEnabled() ) {
return new Color( Display.getCurrent(), new RGB( 172, 168, 153 ) );
} else {
return Display.getCurrent().getSystemColor( SWT.COLOR_BLACK );
}
}
}
}