sysperfana/heapanalyser/UI/UIs/Graphical/Wizard/HASetupWizard.cs
author Matti Laitinen <matti.t.laitinen@nokia.com>
Tue, 15 Jun 2010 12:47:20 +0300
changeset 8 15296fd0af4a
permissions -rw-r--r--
HeapAnalyser 1.1.0

/*
* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
*   this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
*   this list of conditions and the following disclaimer in the documentation
*   and/or other materials provided with the distribution.
* - Neither the name of Nokia Corporation nor the names of its contributors
*   may be used to endorse or promote products derived from this software
*   without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* 
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

using System;
using System.IO;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Management;
using System.Text;
using SymbianUtils.Settings;
using SymbianUtilsUi.Dialogs;
using HeapAnalyser.Engine;
using HeapAnalyser.Engine.Types;
using HeapLib;
using HeapLib.Constants;
using HeapLib.Reconstructor;
using HeapLib.Reconstructor.Misc;
using HeapLib.Reconstructor.DataSources;
using HeapLib.Reconstructor.DataSources.Analyser;
using HeapUiLib.Dialogs;
using SymbianWizardLib.Engine;
using SymbianWizardLib.GUI;
using SymbianDebugLib.Engine;
using SymbianDebugLibUi.Controls;

namespace HeapAnalyser.UIs.Graphical.Wizard
{
    public partial class HASetupWizard : Form
    {
		#region Constructors & destructors
        public HASetupWizard( XmlSettings aSettings, HeapWizardEngine aEngine )
		{
			iSettings = aSettings;
			iEngine = aEngine;
			//
			InitializeComponent();
		}
		#endregion

		#region Form event handlers
        private void Form_Load( object sender, System.EventArgs e )
		{
            // Set up version information
            iLbl_Version.Text = HeapLibConstants.Version + " " + HeapLibConstants.Copyright;
			iSettings[ "Wizard", "DialogResult"] = DialogResult.None.ToString();
			//
            Setup_OpType();
            //
            Setup_SourceData_LogFileName();
            Setup_SourceData_HeapDataComparison();
            Setup_SourceData_HeapCSVComparison();
            //
            Setup_Cmn_Symbolics();
            Setup_Cmn_Filters();
            //
            Setup_Output_Directory();
            Setup_Output_File();
		}

		private void Form_Closing( object sender, System.ComponentModel.CancelEventArgs e )
		{
			iSettings.Store();
		}

        private void iWizard_WizardClosedFromAuxillary( SymWizardClosureEvent aEventArgs )
		{
			iSettings[ "Wizard", "DialogResult"] = DialogResult.Cancel.ToString();
		}

        private void iWizard_WizardClosedFromFinish( SymWizardClosureEvent aEventArgs )
		{
			iSettings[ "Wizard", "DialogResult"] = DialogResult.OK.ToString();
		}
		#endregion

        #region Pages

        #region Page [Operation type]
        private void Setup_OpType()
		{
			string opType = iSettings[ "Wizard", "OperationType" ];

			// Make sure something is selected
            if ( opType == HeapWizardEngine.TOperationType.EOperationTypeCompareHeapDumps.ToString() )
            {
                iPG1_RB_OpType_CompareHeapDump.Checked = true;
            }
            else if ( opType == HeapWizardEngine.TOperationType.EOperationTypeCompareHeapCSV.ToString() )
            {
                iPG1_RB_OpType_CompareCSV.Checked = true;
            }
            else
            {
                // Default
                iPG1_RB_OpType_HeapViewer.Checked = true;
            }
        }

        private void iPG1_OpType_CloseFromNext( SymWizardPageTransitionEvent aEventArgs )
		{
			if	( iPG1_RB_OpType_HeapViewer.Checked )
			{
				iEngine.OperationType = HeapWizardEngine.TOperationType.EOperationTypeAnalyseAndView;
                aEventArgs.SuggestedNewPage = iPG_SourceData_Log;
			}
            else if ( iPG1_RB_OpType_CompareHeapDump.Checked )
            {
                iEngine.OperationType = HeapWizardEngine.TOperationType.EOperationTypeCompareHeapDumps;
                aEventArgs.SuggestedNewPage =  iPG_SourceData_CompareHeapData;
            }
            else if ( iPG1_RB_OpType_CompareCSV.Checked )
			{
				iEngine.OperationType = HeapWizardEngine.TOperationType.EOperationTypeCompareHeapCSV;
                aEventArgs.SuggestedNewPage = iPG_SourceData_CompareCSV;
            }

            Setup_Output_File_Dynamic();
            Setup_Output_Directory_Dynamic();

            iSettings[ "Wizard", "OperationType" ] = iEngine.OperationType.ToString();
		}
		#endregion

		#region Page [SourceData - Log file name]
		private void Setup_SourceData_LogFileName()
		{
            iSettings.Load( "Wizard", iPG_SourceData_Log_FB );
		}

        private void iPG_SourceData_Log_CloseFromNext( SymWizardPageTransitionEvent aEventArgs )
		{
            string logFileName = iPG_SourceData_Log_FB.EntityName;

            if ( !iPG_SourceData_Log_FB.IsValid )
            {
                aEventArgs.SuggestedNewPage = iPG_SourceData_Log;
            }
            else
            {
                iSettings.Save( "Wizard", iPG_SourceData_Log_FB );
                //
                iEngine.HeapDataOptions = new Options();
                //
                DataSourceAnalyser analyser = HeapReconstructorDataSourceAnalyserDialog.Analyse( logFileName );
                SeedAnalysisFiltersAfterDataSourceScan( analyser.DataSources, iPG302_Combo_Filter );
			
                // Only allowed to continue if we found a valid source
                if ( iPG302_Combo_Filter.Items.Count > 0 )
                {
                    aEventArgs.SuggestedNewPage = iPG_Cmn_Symbolics;
                }
                else
                {
                    aEventArgs.SuggestedNewPage = aEventArgs.CurrentPage;
                }
			}
		}
		#endregion

        #region Page [SourceData - Heap data comparison source files]
        private void Setup_SourceData_HeapDataComparison()
        {
            iSettings.Load( "Wizard", iPG202_TB_LogFile1 );
            iSettings.Load( "Wizard", iPG202_TB_LogFile2 );

            // Start off with the combo's disabled
            iPG202_Combo_ThreadName1.Enabled = false;
            iPG202_Combo_ThreadName2.Enabled = false;

            // We queue these up so that the scan occurs only after the page is actually displayed.
            this.iPG202_TB_LogFile1.FileSelectionChanged += new SymbianUtilsUi.Controls.SymbianFileControl.FileSelectionChangedHandler( this.iPG202_TB_LogFile1_FileSelectionChanged );
            this.iPG202_TB_LogFile2.FileSelectionChanged += new SymbianUtilsUi.Controls.SymbianFileControl.FileSelectionChangedHandler( this.iPG202_TB_LogFile2_FileSelectionChanged );
        }

        private void iPG202_TB_LogFile1_FileSelectionChanged( SymbianUtilsUi.Controls.SymbianFileControl aSelf, string aFileName )
        {
            DataSourceAnalyser analyser = HeapReconstructorDataSourceAnalyserDialog.Analyse( aFileName );
            SeedAnalysisFiltersAfterDataSourceScan( analyser.DataSources, iPG202_Combo_ThreadName1 );

            iPG_SourceData_CompareHeapData_GP_Log2.Enabled = ( iPG202_Combo_ThreadName1.Items.Count > 0 );
        }

        private void iPG202_TB_LogFile2_FileSelectionChanged( SymbianUtilsUi.Controls.SymbianFileControl aSelf, string aFileName )
        {
            DataSourceAnalyser analyser = HeapReconstructorDataSourceAnalyserDialog.Analyse( aFileName );

            // Get the master thread name
            string threadName = ThreadNameFromFilterCombo( iPG202_Combo_ThreadName1 );
            
            if ( threadName != string.Empty )
            {
            }
            else
            {
                analyser.DataSources.Clear();
            }

            // Seed combobox with filter options
            SeedAnalysisFiltersAfterDataSourceScan( analyser.DataSources, iPG202_Combo_ThreadName2 );
        }

        private void iPG_SourceData_CompareHeapData_PageShownFromButtonNext( SymWizardPage aSender )
        {
            if ( iPG202_TB_LogFile1.EntityName != string.Empty && File.Exists( iPG202_TB_LogFile1.EntityName ) )
            {
                iPG202_TB_LogFile1_FileSelectionChanged( iPG202_TB_LogFile1, iPG202_TB_LogFile1.EntityName );
            }
            if ( iPG202_TB_LogFile2.EntityName != string.Empty && File.Exists( iPG202_TB_LogFile2.EntityName ) )
            {
                iPG202_TB_LogFile2_FileSelectionChanged( iPG202_TB_LogFile2, iPG202_TB_LogFile2.EntityName );
            }
        }

        private void iPG202_SourceData_Comparison_CloseFromNext( SymWizardPageTransitionEvent aEventArgs )
        {
            iEngine.ComparisonEngineData.DataSource1 = DataSourceFromFilterCombo( iPG202_Combo_ThreadName1 );
            iEngine.ComparisonEngineData.DataSource2 = DataSourceFromFilterCombo( iPG202_Combo_ThreadName2 );
            //
            if ( !( iPG202_TB_LogFile1.IsValid && iPG202_TB_LogFile2.IsValid ) )
            {
                aEventArgs.SuggestedNewPage =  iPG_SourceData_CompareHeapData;
            }
            else if ( iEngine.ComparisonEngineData.DataSource1 == null )
            {
                iPG202_TB_LogFile1.SetError( "Select a valid MemSpy heap data log" );
                aEventArgs.SuggestedNewPage =  iPG_SourceData_CompareHeapData;
            }
            else if ( iEngine.ComparisonEngineData.DataSource2 == null )
            {
                iPG202_TB_LogFile2.SetError( "Select a valid MemSpy heap data log" );
                aEventArgs.SuggestedNewPage =  iPG_SourceData_CompareHeapData;
            }
            else
            {
                // Get both data sources and check thread names are common
                DataSource ds1 = (DataSource ) iPG202_Combo_ThreadName1.SelectedItem;
                DataSource ds2 = (DataSource) iPG202_Combo_ThreadName2.SelectedItem;
                //
                if ( ds1.ThreadName.ToLower() != ds2.ThreadName.ToLower() )
                {
                    aEventArgs.SuggestedNewPage = iPG_SourceData_CompareHeapData;
                    iErrorProvider.SetError( iPG202_Combo_ThreadName2, "Thread names differ" );
                }
                else
                {
                    iSettings.Save( "Wizard", iPG202_TB_LogFile1 );
                    iSettings.Save( "Wizard", iPG202_TB_LogFile2 );

                    iErrorProvider.Clear();
                    aEventArgs.SuggestedNewPage = iPG_Cmn_Symbolics;
                }
            }
        }
        #endregion

        #region Page [SourceData - Heap CSV comparison source files]
        private void Setup_SourceData_HeapCSVComparison()
        {
            iSettings.Load( "PG_SourceData_CompareCSV_Files", iPG_SourceData_CompareCSV_Files );
        }

        private void iPG_SourceData_CompareCSV_PageClosedFromButtonNext( SymWizardPageTransitionEvent aEventArgs )
        {
            // Check we have at least one valid file.
            if ( iPG_SourceData_CompareCSV_Files.FileNames.Count == 0 )
            {
                aEventArgs.SuggestedNewPage = iPG_SourceData_CompareCSV;
            }
            else
            {
                iSettings.Save( "PG_SourceData_CompareCSV_Files", iPG_SourceData_CompareCSV_Files );
                iEngine.ComparisonEngineCSV.SourceFileNames = iPG_SourceData_CompareCSV_Files.FileNames;
                aEventArgs.SuggestedNewPage = iPG_OutputToDirectory;
            }
        }
        #endregion

        #region Page [Cmn - Symbolics]
        private void Setup_Cmn_Symbolics()
		{
            iPG301_DebugControl.Engine = iEngine.DebugEngine;
		}

        private void iPG301_AnalysisSymbolics_CloseFromNext( SymWizardPageTransitionEvent aEventArgs )
		{
            string errorText = string.Empty;
            if ( iPG301_DebugControl.IsReadyToPrime( out errorText ) )
            {
                iPG301_DebugControl.Prime();

                if ( iEngine.OperationType == HeapWizardEngine.TOperationType.EOperationTypeCompareHeapDumps )
                {
                    aEventArgs.SuggestedNewPage = iPG_OutputToFile;
                }
                else
                {
                    // If there is only one thread available, then there's no point
                    // asking the user to pick it...
                    int number = 0;
                    bool okayToProceed = SetDataSourceFromFirstAvailableThread( out number );
                    if ( okayToProceed && number == 1 )
                    {
                        aEventArgs.SuggestedNewPage = iPG_Final;
                    }
                    else
                    {
                        aEventArgs.SuggestedNewPage = iPG_Cmn_Filters;
                    }
                }

                // Also save debug engine configuration
                iPG301_DebugControl.XmlSettingsSave();
            }
            else
            {
                MessageBox.Show( errorText, "Error" );
                aEventArgs.SuggestedNewPage = iPG_Cmn_Symbolics;
            }
		}
		#endregion

        #region Page [Cmn - Heap thread filter]
        private void Setup_Cmn_Filters()
		{
		}

        private void iPG302_Cmn_Filters_CloseFromNext( SymWizardPageTransitionEvent aEventArgs )
		{
            if ( SetDataSourceFromFirstAvailableThread() )
            {
                // Clear any error
                iErrorProvider.SetError( iPG302_Combo_Filter, string.Empty );

                // Decide where to go next...
                aEventArgs.SuggestedNewPage = iPG_Final;
            }
            else
            {
                iErrorProvider.SetError( iPG302_Combo_Filter, "No thread's were detected. Is the log corrupt?" );
                aEventArgs.SuggestedNewPage = iPG_Cmn_Filters;
            }
		}
		#endregion

		#region Page [Output - Directory]
        private void Setup_Output_Directory()
		{
            iSettings.Load( "Wizard", iPG_OutputToDirectory_FB );
		}

        private void Setup_Output_Directory_Dynamic()
        {
            iHeader_OutputToDirectory.Title = "Save CSV Comparsion Reports";
            iHeader_OutputToDirectory.Description += "Microsoft Excel comparison reports";
        }

        private void iPG_OutputToDirectory_CloseFromNext( SymWizardPageTransitionEvent aEventArgs )
		{
            if ( !iPG_OutputToDirectory_FB.IsValid )
            {
                aEventArgs.SuggestedNewPage = iPG_OutputToDirectory;
            }
            else
            {
                string dir = iPG_OutputToDirectory_FB.EntityName;
                iEngine.ComparisonEngineCSV.OutputDirectory = dir;
                iSettings.Save( "Wizard", iPG_OutputToDirectory_FB );
                aEventArgs.SuggestedNewPage = iPG_Final;
            }
		}
		#endregion

        #region Page [Output - File]
        private void Setup_Output_File()
        {
            iSettings.Load( "Wizard", iPG_OutputToFile_FB );
        }

        private void Setup_Output_File_Dynamic()
        {
            if ( iEngine.OperationType == HeapWizardEngine.TOperationType.EOperationTypeCompareHeapDumps )
            {
                iHeader_OutputToFile.Title = "Save Heap Dump Comparison to Microsoft Excel";
                iHeader_OutputToFile.Description += "Microsoft Excel comparison report";
            }
        }

        private void iPG500_Comparison_Output_CloseFromNext( SymWizardPageTransitionEvent aEventArgs )
        {
            if ( iPG_OutputToFile_FB.IsValid )
            {
                iSettings.Save( "Wizard", iPG_OutputToFile_FB );
                //
                if ( iEngine.OperationType == HeapWizardEngine.TOperationType.EOperationTypeCompareHeapDumps )
                {
                    iEngine.ComparisonEngineData.OutputFileName = iPG_OutputToFile_FB.EntityName;
                }
                //
                aEventArgs.SuggestedNewPage =  iPG_Final;
            }
            else
            {
                aEventArgs.SuggestedNewPage =  iPG_OutputToFile;
            }
        }
        #endregion

        #endregion

        #region Internal methods
        private bool SetDataSourceFromFirstAvailableThread()
        {
            int number;
            return SetDataSourceFromFirstAvailableThread( out number );
        }

        private bool SetDataSourceFromFirstAvailableThread( out int aNumberOfDataSources )
        {
            bool okayToProceed = false;

            // Must be at least one thread selected
            DataSource dataSource = (DataSource) iPG302_Combo_Filter.SelectedItem;
            if ( dataSource == null || iPG302_Combo_Filter.Items.Count == 0 )
            {
                // Can't do anything at this point... Let a later page
                // handle this scenario.
                aNumberOfDataSources = 0;
            }
            else
            {
                aNumberOfDataSources = iPG302_Combo_Filter.Items.Count;
                iEngine.AnalysisEngine.DataSource = dataSource;
                
                // Save setting for filter thread
                iSettings[ "Wizard", iPG302_Combo_Filter.Name ] = iPG302_Combo_Filter.Text;

                // Good to go
                okayToProceed = true;
            }

            return okayToProceed;
        }

        private void SeedAnalysisFiltersAfterDataSourceScan( DataSourceCollection aSources, ComboBox aCombo )
        {
            // Thread filtering - seed with detected threads
            aCombo.BeginUpdate();
            aCombo.Items.Clear();
            foreach ( DataSource source in aSources )
            {
                bool allowSource = true;
                bool containsErrors = CheckSourceForErrors( source, out allowSource );
                if ( !containsErrors || allowSource )
                {
                    aCombo.Items.Add( source );
                }
            }

            // Make sure something is selected
            if ( aCombo.Items.Count > 0 )
            {
                iErrorProvider.SetError( aCombo, string.Empty );

                int selectedThreadIndex = 0;

                // If the user has picked a thread previously, try to select the same one
                // again this time.
                string lastSelectedThread = iSettings[ "Wizard", aCombo.Name ];
                if ( lastSelectedThread.Length > 0 )
                {
                    int index = aSources.IndexOf( lastSelectedThread );
                    if ( index >= 0 )
                    {
                        selectedThreadIndex = index;
                    }
                }

                // Now pick the thread...
                aCombo.SelectedIndex = selectedThreadIndex;
            }
            else
            {
                iErrorProvider.SetError( aCombo, "No thread's were detected. Is the log corrupt?" );
            }

            aCombo.Enabled = ( aCombo.Items.Count > 1 );
            aCombo.EndUpdate();
        }

        private bool CheckSourceForErrors( DataSource aSource, out bool aAllowSourceAnyway )
        {
            aAllowSourceAnyway = false;
            string description = string.Empty;
            //
            bool errorsDetected = aSource.ErrorsDetected( out description );
            if ( errorsDetected )
            {
                StringBuilder msg = new StringBuilder();
                msg.Append( "File: " + aSource.FileName );
                msg.Append( System.Environment.NewLine );
                msg.Append( "Thread: " + aSource.ThreadName );
                msg.Append( System.Environment.NewLine );
                msg.Append( System.Environment.NewLine );
                msg.Append( description );
                msg.Append( System.Environment.NewLine );
                msg.Append( "You are recommended to save the heap data to zip and contact" );
                msg.Append( "your support provider." );
                msg.Append( System.Environment.NewLine );
                msg.Append( System.Environment.NewLine );
                msg.Append( "Do you want to allow this data anyway?" );
                //
                string title = string.Format( "Errors Detected - {0}", aSource.ThreadName );
                DialogResult result = MessageBox.Show( msg.ToString(), title, MessageBoxButtons.YesNo );
                aAllowSourceAnyway = ( result == DialogResult.Yes );
            }
            //
            return errorsDetected;
        }

        private static DataSource DataSourceFromFilterCombo( ComboBox aCombo )
        {
            DataSource ret = null;
            //
            int index = aCombo.SelectedIndex;
            if ( index >= 0 && index < aCombo.Items.Count )
            {
                object obj = aCombo.Items[ index ];
                if ( obj is DataSource )
                {
                    ret = (DataSource) obj;
                }
            }
            //
            return ret;
        }

        private static string ThreadNameFromFilterCombo( ComboBox aCombo )
        {
            string ret = string.Empty;
            //
            DataSource ds = DataSourceFromFilterCombo( aCombo );
            if ( ds != null )
            {
                ret = ds.ThreadName;
            }
            //
            return ret;
        }
        #endregion

        #region Data members
        private readonly HeapWizardEngine iEngine;
		private readonly XmlSettings iSettings;
		#endregion
    }
}