diff -r 8e12a575a9b5 -r 15296fd0af4a sysperfana/heapanalyser/UI/UIs/Graphical/Wizard/HASetupWizard.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sysperfana/heapanalyser/UI/UIs/Graphical/Wizard/HASetupWizard.cs Tue Jun 15 12:47:20 2010 +0300 @@ -0,0 +1,594 @@ +/* +* 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 + } +}