//************************************************************************* // Method: PopulateEdgesTable() // /// <summary> /// Populates the edge table with participant pairs. /// </summary> /// /// <param name="aoEmailParticipantPairs"> /// Analysis results. /// </param> /// /// <remarks> /// Note: This method modifies <paramref name="aoEmailParticipantPairs" /> /// by converting each participant string to one formatted for the edge /// worksheet. /// </remarks> //************************************************************************* protected void PopulateEdgesTable( EmailParticipantPair [] aoEmailParticipantPairs ) { Debug.Assert(aoEmailParticipantPairs != null); Debug.Assert(m_oEdgeTable != null); AssertValid(); Int32 iEmailParticipantPairs = aoEmailParticipantPairs.Length; if (iEmailParticipantPairs == 0) { return; } // Create and populate an array of edge weights. Object [,] aoEdgeWeights = new Object [iEmailParticipantPairs, 1]; for (Int32 i = 0; i < iEmailParticipantPairs; i++) { EmailParticipantPair oEmailParticipantPair = aoEmailParticipantPairs[i]; // Modify the pariticpant strings. oEmailParticipantPair.Participant1 = AnalyzerToParticipant(oEmailParticipantPair.Participant1); oEmailParticipantPair.Participant2 = AnalyzerToParticipant(oEmailParticipantPair.Participant2); aoEdgeWeights[i, 0] = oEmailParticipantPair.EdgeWeight.ToString(); } Int32 iRowOffsetToWriteTo = 0; if (!m_bClearTablesFirst) { iRowOffsetToWriteTo = ExcelUtil.GetOffsetOfFirstEmptyTableRow( m_oEdgeTable); } // Write the arrays to the edge table. NodeXLWorkbookUtil.PopulateEdgeTableWithParticipantPairs( m_oEdgeTable, aoEmailParticipantPairs, iRowOffsetToWriteTo); SetEdgeWeightValues(aoEdgeWeights, iRowOffsetToWriteTo); ExcelUtil.ActivateWorksheet(m_oEdgeTable); }
//************************************************************************* // Method: AnalyzeEmailNetworkInternal() // /// <summary> /// Analyzes a user's email social network. /// </summary> /// /// <param name="oDataReader"> /// An <see cref="OleDbDataReader" /> object for reading email items. /// </param> /// /// <param name="bUseCcForEdgeWeights"> /// See the synchronous AnalyzeEmailNetwork() method. /// </param> /// /// <param name="bUseBccForEdgeWeights"> /// See the synchronous AnalyzeEmailNetwork() method. /// </param> /// /// <param name="oBackgroundWorker"> /// A BackgroundWorker object if this method is being called /// asynchronously, or null if it is being called synchronously. /// </param> /// /// <param name="oDoWorkEventArgs"> /// A DoWorkEventArgs object if this method is being called /// asynchronously, or null if it is being called synchronously. /// </param> /// /// <returns> /// An array of zero or more <see cref="EmailParticipantPair" /> objects, /// one for each pair of participants in the set of email items. The /// return value is never null. /// </returns> //************************************************************************* protected EmailParticipantPair[] AnalyzeEmailNetworkInternal( OleDbDataReader oDataReader, Boolean bUseCcForEdgeWeights, Boolean bUseBccForEdgeWeights, BackgroundWorker oBackgroundWorker, DoWorkEventArgs oDoWorkEventArgs ) { Debug.Assert(oDataReader != null); Debug.Assert(oBackgroundWorker == null || oDoWorkEventArgs != null); AssertValid(); // Create a dictionary to keep track of participant pairs. The key is // the pair of participants in the format used by ParticipantsToKey() // and the value is the edge weight between the participants. The // contents of this aggregated dictionary get returned by this method. Dictionary<String, Int32> oAggregatedDictionary = new Dictionary<String, Int32>(); // Loop through the email items. Int64 iRecords = 0; while ( oDataReader.Read() ) { try { Object oFromField = oDataReader["System.Message.FromAddress"]; Object oToField = oDataReader["System.Message.ToAddress"]; Object oCcField = oDataReader["System.Message.CcAddress"]; Object oBccField = oDataReader["System.Message.BccAddress"]; AnalyzeOneEmail(oFromField, oToField, oCcField, oBccField, bUseCcForEdgeWeights, bUseBccForEdgeWeights, oAggregatedDictionary); } catch (OleDbException) { // In June 2009, a NodeXL team member got a repeatable // OleDbException while attempting to analyze his email for a // certain date range. Unfortunately, the team member was on // the other side of the country and the exception had no inner // exceptions to provide more details. (OleDbException uses a // custom Errors collection instead of inner exceptions, and // that collection doesn't get displayed by NodeXL's generic // error-handling scheme). Therefore, the exact cause of the // error couldn't be determined. // // However, the error went away when the date range was // altered, leading me to believe that an email with an invalid // field was encountered. Although the DataReader.Item[] and // AnalyzeOneEmail() calls shouldn't throw an exception on a // bad field, there may be some invalid field condition I'm // overlooking. // // Workaround: Skip emails that throw such an exception. } if (oBackgroundWorker != null) { // Check whether a cancellation has been requested. if (iRecords % AsyncCancelInterval == 0 && oBackgroundWorker.CancellationPending) { // Cancel the analysis. Debug.Assert(oDoWorkEventArgs != null); oDoWorkEventArgs.Cancel = true; return ( new EmailParticipantPair[0] ); } } iRecords++; } // Convert the aggregated results to an array of EmailParticipantPair // objects. EmailParticipantPair [] aoEmailParticipantPairs = new EmailParticipantPair[oAggregatedDictionary.Count]; Int32 i = 0; foreach (KeyValuePair<String, Int32> oKeyValuePair in oAggregatedDictionary) { String sParticipant1, sParticipant2; KeyToParticipants(oKeyValuePair.Key, out sParticipant1, out sParticipant2); aoEmailParticipantPairs[i] = new EmailParticipantPair( sParticipant1, sParticipant2, oKeyValuePair.Value); i++; } return (aoEmailParticipantPairs); }