diff -r e8e63152f320 -r 2a9601315dfc javamanager/javainstaller/installerui/javasrc/com/nokia/mj/impl/installer/ui/eswt/InstallerUiEswt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javamanager/javainstaller/installerui/javasrc/com/nokia/mj/impl/installer/ui/eswt/InstallerUiEswt.java Mon May 03 12:27:20 2010 +0300 @@ -0,0 +1,1305 @@ +/* +* Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +package com.nokia.mj.impl.installer.ui.eswt; + +import com.nokia.mj.impl.fileutils.FileUtility; +import com.nokia.mj.impl.installer.ui.ApplicationInfo; +import com.nokia.mj.impl.installer.ui.DownloadInfo; +import com.nokia.mj.impl.installer.ui.InstallerUi; +import com.nokia.mj.impl.installer.ui.InstallerUiListener; +import com.nokia.mj.impl.installer.ui.InstallInfo; +import com.nokia.mj.impl.installer.ui.LaunchAppInfo; +import com.nokia.mj.impl.installer.ui.PermissionInfo; +import com.nokia.mj.impl.installer.ui.UninstallInfo; +import com.nokia.mj.impl.rt.ui.RuntimeUi; +import com.nokia.mj.impl.rt.ui.RuntimeUiFactory; +import com.nokia.mj.impl.utils.ResourceUtil; +import com.nokia.mj.impl.utils.StartUpTrace; +import com.nokia.mj.impl.utils.exception.InstallerExceptionBase; + +import java.io.InputStream; +import java.io.IOException; +import java.util.Hashtable; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.ImageLoader; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +//import org.eclipse.swt.widgets.MessageBox; + +/** + * JavaInstaller eSWT UI. + * + * @author Nokia Corporation + * @version $Rev: 0 $ + */ +public class InstallerUiEswt extends InstallerUi +{ + /** Default shell style. */ + private static final int SHELL_STYLE = + SWT.BORDER | SWT.APPLICATION_MODAL | SWT.ON_TOP; + + private Shell iParent = null; + private Shell iDialog = null; + private ProgressView iProgressView = null; + private ProgressView iDlProgressView = null; + private ProgressView iOcspProgressView = null; + private InstallConfirmationView iInstallConfirmationView = null; + private UninstallConfirmationView iUninstallConfirmationView = null; + private PermissionConfirmationView iPermissionConfirmationView = null; + private UsernamePasswordView iUsernamePasswordView = null; + private LaunchAppQueryView iLaunchAppQueryView = null; + /** Synchronization object for waiting for the UI initialization. */ + private Object iInitWaitObject = new Object(); + /** Synchronization object for waiting for the UI termination. */ + private Object iExitWaitObject = new Object(); + /** + * Synchronization object for synchronizing progress updates + * and confirmation dialogs. Used to guard disabling and + * getting iDisplayProgress variable. + */ + private Object iProgressSyncObject = new Object(); + /** Flag telling if UI main thread exists. */ + private boolean iUiThreadExists = false; + /** Name of the application to be installed. */ + private String iAppName = null; + /** Security icon. */ + private Image iSecurityIcon = null; + /** Flag telling if progress bar should be displayed. */ + private boolean iDisplayProgress = false; + /** Flag telling if the first progress bar update has been traced. */ + private boolean iProgressBarUpdateTraced = false; + /** Flag telling if MinimalUi should be used if UI creation fails. */ + private boolean iMinimalUiEnabled = true; + + /** Hashtable for storing the loaded icons. */ + private static Hashtable iImageTable = null; + + /** Default shell bounds. */ + private Rectangle iDefaultShellBounds = null; + private Rectangle iDefaultShellClientBounds = null; + + /** Bold font for views. */ + private Font iBoldFont = null; + + private ViewBase iActiveView = null; + + /** + * Constructor. + */ + public InstallerUiEswt() + { + super(); + } + + /** + * Initialise InstallerUi after construction. + */ + public void init(int aMode, InstallerUiListener aListener) + { + super.init(aMode, aListener); + StartUpTrace.doTrace("InstallerUiEswt init"); + // Create a hashtable for icons. + iImageTable = new Hashtable(); + // Create a new thread to be the UI main thread. + iUiThreadExists = true; + new Thread(new Runnable() + { + public void run() + { + uiMain(); + } + }, "InstallerUiMainThread").start(); + // To wait InstallerUi to be ready before installer main thread + // continues, uncomment the following line. + //waitForUi(); + } + + /** + * This method is executed in UI main thread. + */ + private void uiMain() + { + log("uiMain: thread started"); + try + { + // Create the necessary views. + Display display = new Display(); + StartUpTrace.doTrace("InstallerUiEswt display created"); + display.setAppName(""); // Remove display title. + iParent = new Shell(display); + iDialog = new Shell(iParent, SHELL_STYLE); + iDefaultShellBounds = iDialog.internal_getDefaultBounds(); + iDefaultShellClientBounds = iDialog.getClientArea(); + iBoldFont = getBoldFont(); + StartUpTrace.doTrace("InstallerUiEswt shell created"); + iProgressView = new ProgressView(this, iDialog, getTitle()); + + iParent.addControlListener(new CListener(this)); + log("InstallerUiEswt CListener added"); + + display.addListener(SWT.Dispose, new Listener() + { + public void handleEvent(Event aEvent) + { + log("Dispose event for display"); + // Prevent UI from being automatically disposed. + //aEvent.doit = false; + } + }); + + synchronized (iInitWaitObject) + { + // Notify that UI is now ready. + iInitWaitObject.notify(); + } + StartUpTrace.doTrace("InstallerUiEswt ready"); + + // If there has been ui update requests, update the ui right + // away. + if (iMode == MODE_INSTALL && getOcspIndicator()) + { + setOcspIndicator(getOcspIndicator()); + } + else if (iMode == MODE_APP_CONVERSION && + iAppConversionTotal > 0) + { + updateAppConversionIndicator( + iAppConversionCurrent, iAppConversionTotal); + } + + // UI event loop must be executed in UI main thread, + // which is the thread where Display is created. + while (isUiReady()) + { + if (!display.readAndDispatch()) + { + display.sleep(); + } + } + if (iBoldFont != null && !iBoldFont.isDisposed()) + { + iBoldFont.dispose(); + } + display.dispose(); + log("uiMain: display disposed"); + synchronized (iExitWaitObject) + { + // Notify that UI main thread has been terminated. + iExitWaitObject.notify(); + } + } + catch (Throwable t) + { + logError("Exception in uiMain", t); + // Release wait object in case someone is waiting for them. + synchronized (iInitWaitObject) + { + iUiThreadExists = false; + iInitWaitObject.notify(); + } + synchronized (iExitWaitObject) + { + iExitWaitObject.notify(); + } + } + iUiThreadExists = false; + log("uiMain: thread ended"); + } + + /** + * Cancels all confirmation views that are currently displayed. + */ + public void cancelConfirmations() + { + super.cancelConfirmations(); + if (iInstallConfirmationView != null) + { + iInstallConfirmationView.confirmCancel(); + } + if (iUninstallConfirmationView != null) + { + iUninstallConfirmationView.confirmCancel(); + } + if (iPermissionConfirmationView != null) + { + iPermissionConfirmationView.confirmCancel(); + } + if (iUsernamePasswordView != null) + { + iUsernamePasswordView.confirmCancel(); + } + if (iLaunchAppQueryView != null) + { + iLaunchAppQueryView.confirmCancel(); + } + // Remove download progress bar if it visible. + if (iDlProgressView != null && !iDlProgressView.isDisposed()) + { + iDlProgressView.dispose(); + iDlProgressView = null; + } + } + + /** + * Confirm installation. UI should display an installation + * confirmation dialog to the user. UI must update + * aInstallInfo basing on user selections. + * This method blocks until user has answered to the dialog. + * + * @param aInstallInfo installation information + * @return true if user has accepted installation, false otherwise + */ + public boolean confirm(InstallInfo aInstallInfo) + { + super.confirm(aInstallInfo); + + waitForUi(); + boolean result = true; + if (!isUiReady()) + { + result = false; + if (iMinimalUiEnabled) + { + result = MinimalUi.confirmStatic(aInstallInfo); + log("MinimalUi installation confirmation returns " + result); + return result; + } + else + { + // If UI is not ready by the time confirmation is requested, + // throw an exception. + throw new RuntimeException("JavaInstallerUi not ready"); + } + } + + if (result) + { + StartUpTrace.doTrace("InstallerUiEswt confirm"); + if (iInstallConfirmationView == null) + { + final Display display = iParent.getDisplay(); + final InstallerUiEswt self = this; + display.syncExec + (new Runnable() + { + public void run() + { + iInstallConfirmationView = + new InstallConfirmationView(self, iDialog); + } + }); + } + result = iInstallConfirmationView.confirm(aInstallInfo); + iInstallConfirmationView.dispose(); + iInstallConfirmationView = null; + } + if (result) + { + iAppName = aInstallInfo.getName(); + if (iUsernamePasswordView != null) + { + // UsernamePasswordView blocks prompting until + // app name is set so that username/password + // prompt will not be displayed if the user + // does not confirm installation. + iUsernamePasswordView.setAppName(iAppName); + } + else + { + // UsernamePasswordView is not being displayed, + // let's allow progress to be displayed. + iDisplayProgress = true; + // If download progress view is in use, + // display it to user only after confirmation. + if (iDlProgressView != null && !iDlProgressView.isVisible()) + { + iDlProgressView.setVisible(true); + } + } + } + else + { + // The install confirmation has been rejected, + // nothing to display anymore. + iParent.getDisplay().syncExec + (new Runnable() + { + public void run() + { + iParent.dispose(); + } + }); + } + log("Installation confirmation returns " + result); + return result; + } + + /** + * Confirm permissions. UI should display a permission + * confirmation dialog to the user. + * This method blocks until user has answered to the dialog. + * + * @param aPermissionInfo permission information + * @return true if user has accepted permissions, false otherwise + */ + public boolean confirmPermissions(PermissionInfo aPermissionInfo) + { + super.confirmPermissions(aPermissionInfo); + + waitForUi(); + if (!isUiReady()) + { + aPermissionInfo.setPermissionAllowed(false); + return true; + } + + synchronized (iProgressSyncObject) + { + // Do not display progress bar during dialog. + iDisplayProgress = false; + } + if (iPermissionConfirmationView == null) + { + final Display display = iParent.getDisplay(); + final InstallerUiEswt self = this; + display.syncExec + (new Runnable() + { + public void run() + { + iPermissionConfirmationView = + new PermissionConfirmationView(self, iDialog); + } + }); + } + boolean result = iPermissionConfirmationView.confirm( + iInstallInfo, aPermissionInfo); + iPermissionConfirmationView.dispose(); + iPermissionConfirmationView = null; + iDisplayProgress = true; + iProgressView.setVisible(true); + log("Permission confirmation returns " + result + + ", user selection " + aPermissionInfo.isPermissionAllowed()); + return result; + } + + /** + * Confirm uninstallation. UI should display an uninstallation + * confirmation dialog to the user. + * This method blocks until user has answered to the dialog. + * + * @param aUninstallInfo uninstallation information + * @return true if user has accepted uninstallation, false otherwise + */ + public boolean confirm(UninstallInfo aUninstallInfo) + { + super.confirm(aUninstallInfo); + + waitForUi(); + boolean result = true; + if (!isUiReady()) + { + result = false; + if (iMinimalUiEnabled) + { + result = MinimalUi.confirmStatic(aUninstallInfo); + log("MinimalUi uninstallation confirmation returns " + result); + return result; + } + else + { + // If UI is not ready by the time confirmation is requested, + // throw an exception. + throw new RuntimeException("JavaInstallerUi not ready"); + } + } + if (result) + { + StartUpTrace.doTrace("InstallerUiEswt confirm"); + if (iUninstallConfirmationView == null) + { + final Display display = iParent.getDisplay(); + final InstallerUiEswt self = this; + display.syncExec + (new Runnable() + { + public void run() + { + iUninstallConfirmationView = + new UninstallConfirmationView(self, iDialog); + } + }); + } + result = iUninstallConfirmationView.confirm(aUninstallInfo); + iUninstallConfirmationView.dispose(); + iUninstallConfirmationView = null; + } + if (result) + { + iDisplayProgress = true; + } + else + { + // The uninstall confirmation has been rejected, + // nothing to display anymore. + iParent.getDisplay().syncExec + (new Runnable() + { + public void run() + { + iParent.dispose(); + } + }); + } + log("Uninstallation confirmation returns " + result); + return result; + } + + /** + * This method is used to notify UI that installation or + * uninstallation has started. Upon this call UI could + * for example display progress bar. + * This method must return quickly. + */ + public void started() + { + super.started(); + } + + /** + * This method is used to notify UI that installation or + * uninstallation has progressed. Upon this call UI can + * update progress bar. + * This method must return quickly. + * + * @param aProgress progress value between 0 and 100 + */ + public void updateProgress(int aProgress) + { + super.updateProgress(aProgress); + if (!isUiReady()) + { + return; + } + // UI is created asynchronously, so it might be that + // UI was not yet ready when started() was called. + // Ensure that iProgressView has been opened before + // updating it. + synchronized (iProgressSyncObject) + { + if (iDisplayProgress && !iProgressView.isVisible()) + { + iProgressView.setVisible(true); + } + if (iDisplayProgress && !iProgressBarUpdateTraced) + { + StartUpTrace.doTrace( + "InstallerUiEswt progress " + aProgress + " %"); + iProgressBarUpdateTraced = true; + } + } + iProgressView.updateProgress(aProgress); + + } + + /** + * This method is used to notify UI that installation or + * uninstallation has ended. Upon this call UI can + * stop displaying progress bar. + * This method must return quickly. + */ + public void ended() + { + super.ended(); + if (!isUiReady()) + { + return; + } + Display display = iParent.getDisplay(); + display.syncExec + (new Runnable() + { + public void run() + { + iParent.dispose(); + } + }); + log("ended: parent disposed"); + // Let's wait for ui to be properly terminated before returning. + synchronized (iExitWaitObject) + { + try + { + if (!display.isDisposed()) + { + iExitWaitObject.wait(); + } + } + catch (InterruptedException ie) + { + // Ignore silently. + } + } + log("ended returns"); + } + + /** + * This method is used to notify UI that a download has started. + * Upon this call UI can for example prepare to display a download + * progress bar. + * NOTE: When this method is called, the totalSize in DownlodInfo + * is not yet initialized. + * This method must return quickly. + * + * @param aDownloadInfo information about download + */ + public void started(DownloadInfo aDownloadInfo) + { + super.started(aDownloadInfo); + if (!isUiReady()) + { + return; + } + // Ensure that download progress bar is displayed and + // updated to zero progress. + long oldCurrentSize = aDownloadInfo.getCurrentSize(); + long oldTotalSize = aDownloadInfo.getTotalSize(); + aDownloadInfo.setCurrentSize(0); + aDownloadInfo.setTotalSize(100); + updateProgress(aDownloadInfo); + aDownloadInfo.setCurrentSize(oldCurrentSize); + aDownloadInfo.setTotalSize(oldTotalSize); + } + + /** + * This method is used to notify UI that a download + * has progressed. Upon this call UI can + * update download progress bar. + * This method must return quickly. + * + * @param aDownloadInfo information about download + */ + public void updateProgress(DownloadInfo aDownloadInfo) + { + super.updateProgress(aDownloadInfo); + if (!isUiReady()) + { + return; + } + + if (iDlProgressView == null) + { + final boolean indeterminate = + (aDownloadInfo.getTotalSize() <= 0); + final InstallerUiEswt self = this; + iParent.getDisplay().syncExec(new Runnable() + { + public void run() + { + iDlProgressView = new ProgressView( + self, iDialog, + InstallerUiTexts.get(InstallerUiTexts.DOWNLOADING), + indeterminate); + } + }); + iDlProgressView.addCancelCommand(); + } + + synchronized (iProgressSyncObject) + { + if (iDisplayProgress && !iDlProgressView.isVisible()) + { + iDlProgressView.setVisible(true); + } + } + if (aDownloadInfo.getTotalSize() > 0) + { + int progress = (int)((aDownloadInfo.getCurrentSize()*100)/ + aDownloadInfo.getTotalSize()); + iDlProgressView.updateProgress(progress); + } + } + + /** + * This method is used to notify UI that a download + * has ended. Upon this call UI can stop + * displaying download progress bar. + * This method must return quickly. + * + * @param aDownloadInfo information about download + */ + public void ended(DownloadInfo aDownloadInfo) + { + super.ended(aDownloadInfo); + if (!isUiReady()) + { + return; + } + if (iDlProgressView != null) + { + iDlProgressView.dispose(); + iDlProgressView = null; + } + synchronized (iProgressSyncObject) + { + if (iDisplayProgress && !iProgressView.isVisible()) + { + iProgressView.setVisible(true); + } + } + } + + /** + * Set OCSP indicator on or off. + * + * @param aOn true when OCSP is started, false when OCSP is stopped + */ + public void setOcspIndicator(boolean aOn) + { + super.setOcspIndicator(aOn); + waitForUi(); + if (!isUiReady()) + { + log("UI not ready, could not set OCSP indicator to " + aOn); + return; + } + if (aOn) + { + if (iOcspProgressView == null) + { + final InstallerUiEswt self = this; + iParent.getDisplay().syncExec + (new Runnable() + { + public void run() + { + iOcspProgressView = new ProgressView(self, iDialog, + InstallerUiTexts.get(InstallerUiTexts.OCSP_CHECK_PROGRESS), + true); + } + }); + iOcspProgressView.addCancelCommand(); + } + if (iOcspProgressView != null) + { + if (!iOcspProgressView.isVisible()) + { + iOcspProgressView.setVisible(true); + } + } + } + else + { + if (iOcspProgressView != null) + { + if (iOcspProgressView.isVisible()) + { + iOcspProgressView.setVisible(false); + } + iOcspProgressView.dispose(); + iOcspProgressView = null; + } + } + } + + /** + * Update application conversion indicator. + * + * @param aCurrent Index of the current application (1..total). + * @param aTotal Total number of applications. Setting aTotal to + * zero indicates that application conversion has been completed + * and ui can be disposed. + */ + public void updateAppConversionIndicator(int aCurrent, int aTotal) + { + super.updateAppConversionIndicator(aCurrent, aTotal); + if (!isUiReady()) + { + log("UI not ready, could not update app conversion indicator"); + return; + } + int progress = 101; + if (aTotal > 0) + { + progress = (aCurrent*100)/aTotal; + } + if (progress <= 100) + { + iProgressView.setText(getTitle()); + iProgressView.updateProgress(progress); + if (!iProgressView.isVisible()) + { + iProgressView.removeCancelCommand(); + iProgressView.setVisible(true); + } + iParent.getDisplay().syncExec(new Runnable() + { + public void run() + { + // Ensure that conversion indicator + // is drawn to the foreground. + iParent.setMaximized(true); + } + }); + } + else + { + iProgressView.updateProgress(100); + // Call ended() method which will dispose the ui. + ended(); + } + } + + /** + * Notify user that an error has occurred. + * This method must return quickly. + * + * @param aInstallerException exception indicating the error reason + */ + public void error(InstallerExceptionBase aInstallerException) + { + super.error(aInstallerException); + + waitForUi(); + // InstallerUi does not have to be ready as long as + // RuntimeUi is used to display error messages. + //if (!isUiReady()) { + // return; + //} + + boolean identified = false; + //String tmpAppName = null; + if (iInstallInfo != null) + { + //tmpAppName = iInstallInfo.getName(); + if (iInstallInfo.getCertificates() != null) + { + identified = true; + } + } + else if (iUninstallInfo != null) + { + //tmpAppName = iUninstallInfo.getName(); + if (iUninstallInfo.getCertificates() != null) + { + identified = true; + } + } + String tmpTitle = ""; + if (iMode == MODE_INSTALL) + { + tmpTitle = InstallerUiTexts.get(InstallerUiTexts.INSTALL_FAILED); + } + else if (iMode == MODE_UNINSTALL) + { + tmpTitle = InstallerUiTexts.get(InstallerUiTexts.UNINSTALL_FAILED); + } + + // Ensure that no confirmations are being displayed. + cancelConfirmations(); + // Hide progress view before displaying error message. + if (iProgressView != null) + { + iProgressView.setVisible(false); + } + // Use RuntimeUi to display error message. + RuntimeUi runtimeUi = RuntimeUiFactory.getRuntimeUi(identified); + runtimeUi.error(tmpTitle, aInstallerException); + runtimeUi.destroy(); + + /* + // Display error message using eSWT MessageBox. + final String appName = tmpAppName; + final String title = tmpTitle; + final String shortMsg = aInstallerException.getShortMessage(); + final String detailedMsg = aInstallerException.getDetailedMessage(); + // UI updates must be executed in UI thread. + iParent.getDisplay().syncExec + (new Runnable() { + public void run() { + if (detailedMsg == null || detailedMsg.length() == 0) { + // No detailed msg, display only short msg. + MessageBox messageBox = new MessageBox + (iParent, SWT.ICON_ERROR | SWT.OK); + messageBox.setText(title); + messageBox.setMessage + (getMessage(title, appName, shortMsg, false)); + messageBox.open(); + } else { + // Display both short and detailed msgs. + MessageBox messageBox = new MessageBox + (iParent, SWT.ICON_ERROR | SWT.YES | SWT.NO); + messageBox.setText(title); + messageBox.setMessage + (getMessage(title, appName, shortMsg, true)); + int answer = messageBox.open(); + if ((answer & SWT.YES) != 0) { + // User wants to see details, display them. + messageBox = new MessageBox + (iParent, SWT.ICON_ERROR | SWT.OK); + messageBox.setText(title); + messageBox.setMessage + (getMessage(title, appName, detailedMsg, false)); + messageBox.open(); + } + } + } + private String getMessage(String aTitle, String aAppName, + String aMsg, boolean aDetailsQuery) { + //String result = aTitle + "\n\n"; + String result = ""; + if (aAppName == null) { + result += aMsg; + } else { + result += aAppName + "\n\n" + aMsg; + } + if (aDetailsQuery) { + result += "\n\n"; + result += InstallerUiTexts.get + (InstallerUiTexts.DETAILS_QUERY); + } + return result; + } + }); + + */ + } + + /** + * Ask username and password for http authentication. + * This method blocks until user has answered to the dialog. + * + * @param aUrl url for which authentication is required + * @return Array of two strings, the first being username + * and second being password. If username and password + * cannot be obtained, this method returns null. + */ + public String[] getUsernamePassword(String aUrl) + { + waitForUi(); + if (!isUiReady()) + { + return null; + } + + synchronized (iProgressSyncObject) + { + // Do not display progress bar during dialog. + iDisplayProgress = false; + } + if (iUsernamePasswordView == null) + { + final Display display = iParent.getDisplay(); + final InstallerUiEswt self = this; + display.syncExec(new Runnable() + { + public void run() + { + iUsernamePasswordView = + new UsernamePasswordView(self, iDialog); + } + }); + } + iUsernamePasswordView.setAppName(iAppName); + final String[] usernamePassword = + iUsernamePasswordView.getUsernamePassword(aUrl); + iUsernamePasswordView.dispose(); + iUsernamePasswordView = null; + iDisplayProgress = true; + + if (usernamePassword != null) + { + log("Username: " + usernamePassword[0]); + // Do not write confidential information (password) to log. + //log("Password: " + usernamePassword[1]); + } + else + { + log("No username and password provided"); + } + return usernamePassword; + } + + /** + * Asks from the user if the installed application should be launched. + * + * @param aLaunchAppInfo Information about application that can + * be launched. Unless the user cancels the query, + * this data will be filled in with user's answer upon return. + * @return true if the user has chosen to launch the application, + * false if the user has canceled the query + */ + public boolean launchAppQuery(LaunchAppInfo aLaunchAppInfo) + { + waitForUi(); + if (!isUiReady() || iConfirmationsCanceled) + { + // Either UI is not yet ready, or user has cancelled + // installation, in both cases do nothing. + return false; + } + + if (iLaunchAppQueryView == null) + { + final Display display = iParent.getDisplay(); + final InstallerUiEswt self = this; + display.syncExec + (new Runnable() + { + public void run() + { + iLaunchAppQueryView = + new LaunchAppQueryView(self, iDialog); + } + }); + } + + boolean result = iLaunchAppQueryView.launchAppQuery(aLaunchAppInfo); + iParent.getDisplay().syncExec + (new Runnable() + { + public void run() + { + iParent.dispose(); + } + }); + iLaunchAppQueryView = null; + log("LaunchAppQuery returns " + result + " for " + aLaunchAppInfo); + return result; + } + + /** + * Returns string title basing on mode of this InstallerUi. + */ + protected String getTitle() + { + String result = null; + if (iMode == MODE_INSTALL) + { + result = InstallerUiTexts.get(InstallerUiTexts.INSTALLING); + } + else if (iMode == MODE_UNINSTALL) + { + result = InstallerUiTexts.get(InstallerUiTexts.UNINSTALLING); + } + else if (iMode == MODE_APP_CONVERSION) + { + result = InstallerUiTexts.get( + InstallerUiTexts.APP_CONVERSION_PROGRESS, + new Object[] { new Integer(iAppConversionCurrent), + new Integer(iAppConversionTotal) + }); + } + return result; + } + + /** + * Returns icon for indicating identified or unidentified application. + * + * @param aDisplay display to which the icon will be added + * @param aIdentified if true returns icon for identified application, + * otherwise returns icon for unidentified application + * @return icon for identified or unidentified application, or null + * if icon cannot be loaded + */ + protected Image getSecurityIcon(Display aDisplay, boolean aIdentified) + { + if (iSecurityIcon != null) + { + return iSecurityIcon; + } + String iconFilename = ResourceUtil.UNTRUSTED_ICON_NAME; + if (aIdentified) + { + iconFilename = ResourceUtil.TRUSTED_ICON_NAME; + } + String resourceDir = ResourceUtil.getResourceDir(0); + for (int i = 1; iSecurityIcon == null && resourceDir != null; i++) + { + iSecurityIcon = loadImage(aDisplay, resourceDir + iconFilename, false); + resourceDir = ResourceUtil.getResourceDir(i); + } + return iSecurityIcon; + } + + /** + * Loads image from specified InputStream. This method scales the image + * to optimum size. + * + * @param aDisplay display to which the icon will be added + * @param aInputStream InputStream where the image is loaded + * @param aImageName name of the image to be loaded + * @return image from InputStream or null if image cannot be loaded + */ + protected static Image loadImage( + Display aDisplay, InputStream aInputStream, String aImageName) + { + return loadImage(aDisplay, aInputStream, aImageName, true); + } + + /** + * Loads image from specified file. + * + * @param aDisplay display to which the icon will be added + * @param aImageFilename name of the image file to be loaded + * @param aScaleImage flag telling if the loaded image should be scaled + * @return image from file or null if image cannot be loaded + */ + private static Image loadImage( + Display aDisplay, String aImageFilename, boolean aScaleImage) + { + Image result = null; + InputStream imageInputStream = null; + try + { + FileUtility imageFile = new FileUtility(aImageFilename); + if (imageFile.exists()) + { + imageInputStream = imageFile.openInputStream(); + result = loadImage(aDisplay, imageInputStream, + aImageFilename, aScaleImage); + } + } + catch (IOException ioe) + { + log("Can not get InputStream for " + aImageFilename + ": " + ioe); + } + finally + { + if (imageInputStream != null) + { + try + { + imageInputStream.close(); + imageInputStream = null; + } + catch (IOException ioe) + { + logError("Closing image InputStream failed", ioe); + } + } + } + return result; + } + + /** + * Loads image from specified InputStream. + * + * @param aDisplay display to which the icon will be added + * @param aInputStream InputStream where the image is loaded + * @param aImageName name of the image to be loaded + * @param aScaleImage flag telling if the loaded image should be scaled + * @return image from InputStream or null if image cannot be loaded + */ + private static Image loadImage( + Display aDisplay, InputStream aInputStream, + String aImageName, boolean aScaleImage) + { + Image result = null; + if (aImageName != null) + { + result = (Image)iImageTable.get(aImageName); + } + if (result != null) + { + log("Using already loaded image " + aImageName); + return result; + } + try + { + long startTime = System.currentTimeMillis(); + ImageData[] imageDatas = new ImageLoader().load(aInputStream); + ImageData imageData = imageDatas[0]; + if (aScaleImage) + { + Point bestSize = getBestImageSize( + imageData.width, imageData.height); + if (bestSize.x != imageData.width || + bestSize.y != imageData.height) + { + imageData = imageData.scaledTo(bestSize.x, bestSize.y); + log("Image " + aImageName + " scaled from " + + imageDatas[0].width + "x" + imageDatas[0].height + + " to " + bestSize.x + "x" + bestSize.y); + } + } + result = new Image(aDisplay, imageData); + long endTime = System.currentTimeMillis(); + log("Loaded image " + aImageName + " (load time " + + (endTime - startTime) + " ms)"); + iImageTable.put(aImageName, result); + } + catch (Throwable t) + { + log("Can not load image " + aImageName + ": " + t); + //logError("Exception while loading image " + aImageName, t); + } + return result; + } + + /** + * Determines the best image size for the image of given size. + */ + private static Point getBestImageSize(int aWidth, int aHeight) + { + // Actually maximum image width and height should be obtained with + // org.eclipse.swt.internal.extension.DisplayExtension + // getBestImageWidth() and getBestImageHeight(). + final int MAX_WIDTH = 50; // max width in pixels + final int MAX_HEIGHT = 50; // max height in pixels + Point result = new Point(aWidth, aHeight); + if (result.x > MAX_WIDTH || result.y > MAX_HEIGHT) + { + if (result.x >= MAX_WIDTH) + { + result.x = MAX_WIDTH; + result.y = MAX_WIDTH * aHeight / aWidth; + } + if (result.y >= MAX_HEIGHT) + { + result.x = MAX_HEIGHT * aWidth / aHeight; + result.y = MAX_HEIGHT; + } + } + return result; + } + + /** Returns true if UI has been created and can be used. */ + protected boolean isUiReady() + { + if (iProgressView == null) + { + log("ui not ready, iProgressView is null"); + return false; + } + if (iProgressView.isDisposed()) + { + log("ui not ready, iProgressView is disposed"); + return false; + } + return true; + } + + /** + * Blocks until UI has became ready. + */ + private void waitForUi() + { + synchronized (iInitWaitObject) + { + try + { + if (iUiThreadExists && iProgressView == null) + { + iInitWaitObject.wait(); + } + } + catch (InterruptedException ie) + { + // Ignore silently. + } + } + } + + /** + * Called when screen orientation changes. + */ + private void screenOrientationChanged() + { + iDefaultShellBounds = iDialog.internal_getDefaultBounds(); + + if (iActiveView != null) + { + iActiveView.screenOrientationChanged(); + } + } + + private static class CListener implements ControlListener + { + private InstallerUiEswt iInstallerUi = null; + + CListener(InstallerUiEswt aInstallerUi) + { + iInstallerUi = aInstallerUi; + } + + public void controlMoved(ControlEvent aEvent) + { + } + + public void controlResized(ControlEvent aEvent) + { + iInstallerUi.screenOrientationChanged(); + } + } + + Rectangle defaultShellBounds() + { + return iDefaultShellBounds; + } + + Rectangle defaultShellClientBounds() + { + return iDefaultShellClientBounds; + } + + /** Get bold font for the current view. */ + Font getBoldFont() + { + if (iBoldFont == null) + { + FontData[] fontDatas = iParent.getFont().getFontData(); + FontData[] boldFontDatas = new FontData[fontDatas.length]; + for (int i = 0; i < boldFontDatas.length; i++) + { + boldFontDatas[i] = new FontData + (fontDatas[i].getName(), fontDatas[i].getHeight()+1, SWT.BOLD); + } + iBoldFont = new Font(iParent.getDisplay(), boldFontDatas); + } + return iBoldFont; + } + + void setActiveView(ViewBase aView) + { + if (iActiveView != null && iActiveView != aView && + !iActiveView.isDisposed()) + { + iActiveView.setVisible(false); + } + iActiveView = aView; + } + + ViewBase getActiveView() + { + return iActiveView; + } +}