'modified by Rob Pinion to show new and former values, some other slight formatting modifications that you can undo if desired --- just search for Rob Pinion Option Declare 'ClassHistory: 'ClassHistory: '////////////////////////////////////////////////////////////////////////////////////// Class History \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ %REM ================================== ABOUT THIS CLASS ======================================== --------------------------------------------------------------------------------------------------------------------------------------------------------------- PURPOSE --------------------------------------------------------------------------------------------------------------------------------------------------------------- This history class observes changes of a UI document and writes these changes into a history field. (item name: see constants, default is 'History') In addition, you can use this class to add an entry in the backend (e.g. if you change the status of a document) or to empty the history field. The history field itself must be of type "text", allow multiple values, computed when composed, display separate values with 'New Line'. The 'columns' are separated via tabulator (chr(9)); so put the field below a table or a text (separated by tabs) with the following header: Date | User | Actions --------------------------------------------------------------------------------------------------------------------------------------------------------------- TERMS AND CONDITIONS --------------------------------------------------------------------------------------------------------------------------------------------------------------- You can redistribute and/or modify this class under the terms of the SOFTWARE GUIDE LICENSE. This history class is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the SOFTWARE GUIDE LICENSE (http://www.sw-guide.de/projekte/lotus-notes-projekte/lotusscript-history/) for more details. --------------------------------------------------------------------------------------------------------------------------------------------------------------- NOTES VERSIONS --------------------------------------------------------------------------------------------------------------------------------------------------------------- I've successfully tested this class with R5.0.8, R5.0.11, ND6.5.1, ND6.5.2, ND6.5.3 and ND6.5.4. I did not consider R4, so I do not know if this class works also in R4. At least some modifications would be necessary, because the PostSave - event did not exist in R4, but is neccessary since we observe also richtext-items, and these changes are only available after the saving of a document. --------------------------------------------------------------------------------------------------------------------------------------------------------------- CREATION --------------------------------------------------------------------------------------------------------------------------------------------------------------- Dim variableName As New History("HistoryItemName") OR Dim variableName As History Set variableName = New History("HistoryItemName") "HistoryItemName" is the item name of the history field. --------------------------------------------------------------------------------------------------------------------------------------------------------------- METHODS --------------------------------------------------------------------------------------------------------------------------------------------------------------- Method: PostopenStartObservation Syntax: Call PostopenObserve(NotesUIDocument, Variant-Array of Itemnames, Variant-Array of Itemnames being displayed, Variant Array of max. length) Description: Starts the observation of a document, which means that this method observes every (via Variant-Array of Itemnames provided) field. The PostSave and the Querymodechange-Events are also observed by this method. If changes in a document occured, the history will be updated (in the PostSave-event). Usage: *exclusively* in the Postopen-Event of a form ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Method: AddEntry Syntax: Call history.AddEntry (NotesDocument, StringToAdd$) Description: Adds a new entry to the history field (using current date/time and session.Username) Usage: Use this backend-method if you want to add a new entry, e.g. if you change the status of a document programmatically, you can add a new line with the text "Changed status to pending." Remarks: This method does *not* save the NotesDocument. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Method: AddEntry2 Syntax: Call history.AddEntry2 (NotesDocument, StringToAdd$, Username$, DateTime$) Description: Adds a new entry to the history field -- using Strings Username$ and DateTime$. Is similar to AddEntry, but does *not* use the current date/time and session.Username Usage: Usually you won't need this, since AddEntry uses the current date and username, but just in case if you want to use another date/time and/or username. Remarks: This method does *not* save the NotesDocument. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Method: Empty Syntax: Call history.Empty(NotesDocument) Description: Remove the content of the history field. Usage: Use this backend-method if you want to empty the history field. Remarks: This method does *not* save the NotesDocument. --------------------------------------------------------------------------------------------------------------------------------------------------------------- PROPERTIES --------------------------------------------------------------------------------------------------------------------------------------------------------------- Property: MaxEntries Type: SET Syntax: history.MaxEntries = intMaxEntries Description: Maximum entries in the history field. Default = 20 (see constant "HIST_MAXENTRIES%"). Usage: Use this set property if you want to change the max entry amount. Expected datatype: Integer --------------------------------------------------------------------------------------------------------------------------------------------------------------- VERSION HISTORY AND CHANGELOG --------------------------------------------------------------------------------------------------------------------------------------------------------------- Version 1.5 (2005-03-16) Version History and Changelog see http://www.sw-guide.de/projekte/lotus-notes-projekte/lotusscript-history/ --------------------------------------------------------------------------------------------------------------------------------------------------------------- SOURCE --------------------------------------------------------------------------------------------------------------------------------------------------------------- http://www.sw-guide.de/projekte/lotus-notes-projekte/lotusscript-history/ =========================================================================================== %END REM '--------------------------------------------------------------------------------------------------------------------------------------------------------------- ' CONSTANTS '--------------------------------------------------------------------------------------------------------------------------------------------------------------- Const HIST_DATE_FORMAT$ = "dd.mmm.yyyy - hh:mm" 'Date format of History Const HIST_MAXENTRIES% = 20 'Maximum entries in the history. You can change this value via the Property MaxChanges Const HIST_MAX_SIZE_CHARS& = 60000 'maximum size of characters in the history field (limit for computed text fields = 64,363 characters) Const HIST_NEW_DOC_TEXT$ = "Document created." Const HIST_TEXT_FOR_EMPTY_FIELD$ = "(empty)" 'Rob Pinion changed 'Const HIST_TEXT_FOR_EMPTY_FIELD$ = "n/a" Const HIST_CONVERT_NAMES_FIELDS% = True Const HIST_NAME_ENTRY_TYPE$ = "COMMON" 'Format of the username being displayed in the history ("changed by"). 'Empty or "COMMON" means: common username format 'ABBREVIATE means: abbreviate username format 'Internal constants Const HIST_PREFIX_RTITEMS$ = "RTI~~" 'Prefix which indicates if it is a richtext item content or not Const HIST_SEP_NAME_ITM_CONTENT$ = "; " 'Separator for names (only applicable if HIST_CONVERT_NAMES_FIELDS = True) Const HIST_ERRMSG_UIDB_ISNOTHING$ = "The provided NotesUIDocument is nothing!" Const HIST_ERRMSG_DB_ISNOTHING$ = "The provided NotesDocument is nothing!" Const MY_LSI_THREAD_CALLPROC% = 10 '////////////////////////////////////////////////////////////////////////////////////// Class History \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Public Class History Private m_doc As NotesDocument Private m_uidoc As NotesUIDocument Private m_vItemNamesArray As Variant 'array of strings which contains the item names to be observed Private m_vItemNamesDspArray As Variant 'array of strings containing the item names to be displayed in history. 'If it is not an array and/or elements are missing, then the real item names '(m_vItemNamesArray) will be displayed Private m_strHistoryItemName As String Private m_vInitialValuesArray As Variant 'set when first observation started --> all item contents (in an array) Private m_vInitialItemValue As Variant 'set when first observation started --> the content of the item 'History' Private m_vNewValuesArray As Variant Private m_vMaxEntryLenArray As Variant 'max number of chars to be displayed as 'former value' in history field Private m_strNewEntryTextFormatted As String Private m_vNewHistoryValue As Variant Private m_strTextForNewDoc As String Private m_bIsNewDoc As Integer Private m_intMaxEntries As Integer Private m_intHistoryChangedInBackend As Integer 'Indicates whether the history has been changed by a 'backend routine or not. Used for 'Save' Method Public Sub new(strHistoryItemName As String) '====================================================================================== 'Purpose: 'Constructor of this class. '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Parameters: Description: 'strHistoryItemName Item name of the history. '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Used subs/functions: ' - ProcessPostSave ' - ProcessQuerymodeChange '====================================================================================== On Error Goto ErrorHandler '// Set member variables m_strHistoryItemName = strHistoryItemName m_intHistoryChangedInBackend = False GoOut: Exit Sub ErrorHandler: xErrorMsg Resume GoOut End Sub '***************************************************************************************************************** 'Part 1: The observation of changes in a UI document, initiator is code in the postopen-event of a form '***************************************************************************************************************** Public Sub PostopenStartObservation(_ uidoc As NotesUIDocument, vItemNames As Variant, vItemNamesDspArray As Variant, vMaxEntryLenArray As Variant) '====================================================================================== 'Purpose: 'Starts observation from postopen-event. '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Parameters: Description: 'uidoc NotesUIDocument 'vItemNames Array of strings. Item names being observed 'vItemNamesDspArray Array of strings. Item names for displaying in history. ' Provide an empty array or the same array as vItemNames if you want to use the vItemNames ' as text being displayed in the history. 'vMaxEntryLenArray Array of integers. The max len of each value being displayed. ' Provide an empty array if you do not want to limit this. '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Used subs/functions: ' - ProcessPostSave ' - ProcessQuerymodeChange '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Called by: 'n/a -- call this Sub via Postopen-Event ! '====================================================================================== On Error Goto ErrorHandler '// Check input values If (uidoc Is Nothing) Then Error 1003, HIST_ERRMSG_UIDB_ISNOTHING If Isempty (vItemNames) Then Error 1001, "Your provided variable for item names is empty" If Isscalar (vItemNames) Then Error 1002, "Your provided variable for item names is scalar, but must be an array" ' vItemNamesDspArray -> will be checked later '// Set values Set m_uidoc = uidoc Set m_doc = uidoc.Document m_vItemNamesArray = vItemNames m_vMaxEntryLenArray = vMaxEntryLenArray m_vItemNamesDspArray = vItemNamesDspArray '// Form Events On Event PostSave From m_uidoc Call ProcessPostSave On Event Querymodechange From m_uidoc Call ProcessQuerymodeChange '// Start recording if doc is in edit mode If m_uidoc.EditMode = True Then Call Record End If GoOut: Exit Sub ErrorHandler: xErrorMsg Resume GoOut End Sub '---------------------------------------------------------------------------------------- 'Querymodechange Event '---------------------------------------------------------------------------------------- Private Sub ProcessQuerymodeChange(Source As NotesUIDocument, Continue As Variant) '====================================================================================== 'Purpose: 'Starts the recording if UIdocument changes from read mode to the edit mode '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Parameters: Description: 'Source NotesUIDocument. 'Continue Standard Continue variable from standard Notes procedures for events '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Used subs/functions: ' - Record '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Called by: ' - PostopenStartObservation '====================================================================================== On Error Goto ErrorHandler '// Check values If (Source Is Nothing) Then Error 1001, HIST_ERRMSG_UIDB_ISNOTHING '// Exit if doc did NOT change from the read mode to the edit mode If Source.EditMode = True Then Exit Sub '// Start the recording Call Record GoOut: Exit Sub ErrorHandler: xErrorMsg Resume GoOut End Sub '---------------------------------------------------------------------------------------- 'PostSave Event '---------------------------------------------------------------------------------------- Private Sub ProcessPostSave(Source As NotesUIDocument) '====================================================================================== 'Purpose: 'Write the differences to the history item if the doc has been saved '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Parameters: Description: 'Source NotesUIDocument '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Used subs/functions: ' - GetItemTextContentInArray ' - ReplaceHistory ' - xRemoveLinebrakes ' - StructureNewHistoryEntry '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Called by: ' - PostopenStartObservation '====================================================================================== On Error Goto ErrorHandler Dim i As Integer Dim j As Integer Dim intCount As Integer Dim vResult() As Variant Dim strResult As String Dim strIniValue As String Dim strNewValue As String 'added by Rob Pinion to hold new value which will be gathered from the new value array Dim strItemName As String '// Check values If (Source Is Nothing) Then Error 1001, HIST_ERRMSG_UIDB_ISNOTHING If Not m_bIsNewDoc Then m_vNewValuesArray = GetItemTextContentInArray '////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 'START: Get differences between inital item values and new item values. '////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// intCount = -1 For i = 0 To Ubound(m_vItemNamesArray) If Not m_vInitialValuesArray(i) = m_vNewValuesArray(i) Then intCount = intCount + 1 Redim Preserve vResult(intCount) If Left$(m_vInitialValuesArray(i), Len(HIST_PREFIX_RTITEMS)) = HIST_PREFIX_RTITEMS Then 'Is it a rich text field? vResult(intCount) = "Changed richtext-field '" & m_vItemNamesArray(i) & "'" Else '// Prepare history text strIniValue = m_vInitialValuesArray(i) strIniValue = xRemoveLinebrakes(strIniValue, "/") 'New value - added by Rob Pinion strNewValue = m_vNewValuesArray(i) 'Truncate entry if it is limited for this item If ( Not Isempty (m_vMaxEntryLenArray) ) And ( Isarray(m_vMaxEntryLenArray) ) Then 'only continue if this variant is not empty and an array If ( Isnumeric (m_vMaxEntryLenArray(i)) ) And ( m_vMaxEntryLenArray(i) > 0 ) Then If Len(strIniValue) > m_vMaxEntryLenArray(i) Then strIniValue = Left$(strIniValue, m_vMaxEntryLenArray(i)) & "..." End If 'do the same for new values - Rob Pinion added If Len(strNewValue) > m_vMaxEntryLenArray(i) Then strNewValue = Left$(strNewValue, m_vMaxEntryLenArray(i)) & "..." End If End If End If If strIniValue = "" Then strIniValue = HIST_TEXT_FOR_EMPTY_FIELD 'shows up as n/a or whatever the constant is set to '// Prepare Item Name strItemName = m_vItemNamesArray(i) 'Default value for displaying the item name. If ( Not Isempty (m_vItemNamesDspArray) ) And ( Isarray(m_vItemNamesDspArray) ) Then 'only continue if this variant is not empty and an array If Isscalar(m_vItemNamesDspArray(i)) Then If Cstr(m_vItemNamesDspArray(i)) <> "" Then 'It is a valid value for displaying the item name strItemName = Cstr(m_vItemNamesDspArray(i)) End If End If End If '// Write result in array - Rob Pinion modified to add strNewValue vResult(intCount) = "CHANGED [ " & strItemName & " ] FROM [ " & strIniValue & " ] TO [ " & strNewValue & " ] " End If End If Next i If intCount = -1 Then m_strNewEntryTextFormatted = "" Else For j = 0 To intCount If j=0 Then strResult = StructureNewHistoryEntry( Cstr(vResult(j)), True, "", "" ) Else strResult = strResult & Chr(13) + Chr(10) & Chr(9) & " " & Chr(9) & vResult(j) End If Next j m_strNewEntryTextFormatted = strResult End If '////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 'END: Get differences between inital item values and new item values. '////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// End If If Not m_strNewEntryTextFormatted = "" Then 'Let's replace only if doc is not new because we set the history already if the doc was new If Not m_bIsNewDoc Then Call ReplaceHistory End If Call m_doc.Save(True,True) If m_bIsNewDoc Then '// Set new initial values m_vInitialValuesArray = GetItemTextContentInArray '// Set new Content of the history item in variable ("Donald Duck 01/30/2008 Document created." Dim vTemp(0) As Variant vTemp(0) = m_strNewEntryTextFormatted m_vInitialItemValue = vTemp '// It is not a new document anymore m_bIsNewDoc = False End If End If GoOut: Exit Sub ErrorHandler: xErrorMsg Resume GoOut End Sub '***************************************************************************************************************** 'Part 2: Backend actions for setting history '***************************************************************************************************************** 'Remarks: You need to save the changes manually ! ( via NotesDocument.Save(...) ) after using these methods '---------------------------------------------------------------------------------------- '## AddEntry '---------------------------------------------------------------------------------------- Public Sub AddEntry(doc As NotesDocument, strEntry As String) '====================================================================================== 'Purpose: 'Adds a new entry to the history field (using current date/time and session.Username) 'Uses the current user and current date/time. '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Parameters: Description: 'doc NotesDocument 'strEntry The text (String) you want to add to the history. '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Used subs/functions: ' - AddEntryX '====================================================================================== '// Check input values ' --> will be checked later '// Set member variable Set m_doc = doc '// Call the procedure Call AddEntryX(strEntry, True, "", "") '// Set the flag m_intHistoryChangedInBackend = True End Sub Public Sub AddEntry2(doc As NotesDocument, strEntry As String, strUsername As String, strDateTime As String) '====================================================================================== 'Purpose: 'Adds a new entry to the history field (using current date/time and session.Username). 'This Sub is similar to AddEntry, but you can define which Username and DateTime will be entered. '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Parameters: Description: 'doc NotesDocument 'strEntry The text (String) you want to add to the history. 'strUsername String. The username being used for the new entry 'strDateTime String. The date/time being used fdor the new entry '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Used subs/functions: ' - AddEntryX '====================================================================================== '// Check input values ' --> doc & strEntry will be checked later If Not Isscalar(strUsername) Then Error 1001, "The provided string (Username) is not a scalar value !" If Not Isscalar(strDateTime) Then Error 1002, "The provided string (DateTime) is not a scalar value !" '// Set member variable Set m_doc = doc '// Call the procedure Call AddEntryX(strEntry, False, strUsername , strDateTime) '// Set the flag m_intHistoryChangedInBackend = True End Sub Public Sub Empty(doc As NotesDocument) '====================================================================================== 'Purpose: 'Clears all history entries '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Parameters: Description: 'doc NotesDocument '====================================================================================== On Error Goto ErrorHandler '// Check input values If (doc Is Nothing) Then Error 1001, HIST_ERRMSG_DB_ISNOTHING '// Clear the entries Call doc.ReplaceItemValue(m_strHistoryItemName, "") '// Set the flag m_intHistoryChangedInBackend = True GoOut: Exit Sub ErrorHandler: xErrorMsg Resume GoOut End Sub Public Function Save() As Integer '====================================================================================== 'Purpose: 'Saves the changes of the document '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Parameters: Description: 'doc NotesDocument '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Return: 'Integer True/False. ' - True indicates that the document was successfully saved OR a saving was not necessary. ' - False indicates that the document was not saved due to an error ! '====================================================================================== On Error Goto ErrorHandler '// Default (error) return value Save = False '// Check values If (m_doc Is Nothing) Then Error 1001, "There is no document initiated in the history object." '// Perform the saving Select Case m_intHistoryChangedInBackend Case True: Save = m_doc.Save(False, False, False) m_intHistoryChangedInBackend = False 'reset flag Case False: Save = True End Select GoOut: Exit Function ErrorHandler: xErrorMsg Resume GoOut End Function '***************************************************************************************************************** 'Part 3: Usefull for both backend and/or frontend actions '***************************************************************************************************************** Public Property Set MaxEntries As Integer '====================================================================================== 'Purpose: 'Maximum entries in the history field. Default value: see constant HIST_MAXENTRIES 'Use this set property if you want to change the max entry amount. '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Parameters: Description: 'MaxEntries Integer. The max. allowed entries in history. '====================================================================================== On Error Goto ErrorHandler If Not Isnumeric ( MaxEntries ) Then Error 1001, "The provided Set variable is not numeric !" If (MaxEntries > 1) Then m_intMaxEntries = MaxEntries End If GoOut: Exit Property ErrorHandler: xErrorMsg Resume GoOut End Property '***************************************************************************************************************** 'Part 4: Auxiliary functions/subs '***************************************************************************************************************** Private Sub Record() '====================================================================================== 'Purpose: 'We start the recording if ' a) document is in read mode and user switches to edit mode ' b) document has been opened in edit mode (e.g. via Ctrl+E on a document from a view) '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Used subs/functions: ' - StructureNewHistoryEntry ' - GetItemTextContentInArray '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Called by: ' - PostopenStartObservatio ' - ProcessQuerymodeChange '====================================================================================== On Error Goto ErrorHandler If m_doc.IsNewNote Then '// It is a new document m_bIsNewDoc = True 'Set the text for "new document created..." m_strNewEntryTextFormatted = StructureNewHistoryEntry(HIST_NEW_DOC_TEXT, True, "", "") Call m_doc.ReplaceItemValue(m_strHistoryItemName, m_strNewEntryTextFormatted) Else '// It's NOT a new document m_bIsNewDoc = False m_vInitialValuesArray = GetItemTextContentInArray m_vInitialItemValue = m_doc.GetItemValue(m_strHistoryItemName) End If GoOut: Exit Sub ErrorHandler: xErrorMsg Resume GoOut End Sub Private Sub ReplaceHistory '====================================================================================== 'Purpose: 'Replaces all the contents (the complete item) of the history '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Called by: ' - ProcessPostSave ' - AddEntry '====================================================================================== On Error Goto ErrorHandler Dim i As Integer Dim j As Integer Dim intLastPosition As Integer Dim intEntryAmount As Integer Dim lngSize As Long Dim intStartNew As Integer Dim vNewValuesArray() As Variant Dim vTargetArray As Variant '////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 'START: Build new item content for history '////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// vTargetArray = m_vInitialItemValue '// If source is scalar or empty If (Isscalar(vTargetArray) ) Or (Isempty(vTargetArray)) Then '( vTargetArray(Lbound(vTargetArray)) = "" ) ---> was Type mismatch Redim vNewValuesArray(0) vNewValuesArray(0) = m_strNewEntryTextFormatted m_vNewHistoryValue = vNewValuesArray Else '// Check if m_intMaxEntries = 0 (which means this history object property has not been set) If m_intMaxEntries = 0 Then m_intMaxEntries = HIST_MAXENTRIES End If '// Add new entry to the source intLastPosition = Ubound(vTargetArray) + 1 Redim Preserve vTargetArray(intLastPosition) vTargetArray(intLastPosition) = m_strNewEntryTextFormatted '// Check the max possible amount of history entries acc. to characters (MAX_SIZE_CHARS) intEntryAmount = 0 For i = intLastPosition To 0 Step -1 lngSize = lngSize + (Lenb(vTargetArray(i)) / 2) If lngSize > HIST_MAX_SIZE_CHARS Then Exit For 'maximum size exceeded Else intEntryAmount = intEntryAmount + 1 End If Next '// Check the max possible amount of history entries acc. to entries (m_intMaxEntries) If intEntryAmount > m_intMaxEntries Then intEntryAmount = m_intMaxEntries End If '// Create target array Redim vNewValuesArray(intEntryAmount-1) For j = 0 To intEntryAmount-1 'If the ubound of the history array is less than the max. allowed amount - 1, then we start with 0. 'else we start with the difference {history-array-ubound minus max-allowed-amount + 1} If (intLastPosition <= intEntryAmount -1 ) Then intStartNew = 0 Else intStartNew = intLastPosition - intEntryAmount + 1 End If vNewValuesArray(j) = vTargetArray(intStartNew + j) Next 'm_vNewHistoryValue = Fulltrim(vNewValuesArray) m_vNewHistoryValue = vNewValuesArray End If '////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 'START: Build new item content for history '////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '// Set history Call m_doc.ReplaceItemValue(m_strHistoryItemName, m_vNewHistoryValue) GoOut: Exit Sub ErrorHandler: xErrorMsg Resume GoOut End Sub Private Function GetItemTextContentInArray As Variant '====================================================================================== 'Purpose: 'Gets the content of each observed item into an array. '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Return: 'Variant array of strings containing the value of each item. '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Used subs/functions: ' - xxNamesItemToString '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Called by: ' - ProcessPostSave ' - Record '====================================================================================== On Error Goto ErrorHandler Dim vItemvaluesArray As Variant Dim intItems As Integer Dim item As NotesItem Dim strTemp As String Dim intLoop As Integer Dim vNames As Variant Dim strPersonNames As String Dim nn As NotesName Dim intCount As Integer Dim strSepTemp As String Set item = Nothing intItems = Ubound(m_vItemNamesArray) Redim vItemvaluesArray(intItems) For intLoop = 0 To intItems Set item = m_doc.GetFirstItem(m_vItemNamesArray(intLoop)) If Not (item Is Nothing) Then If item.Type = RICHTEXT Then 'item.LastModified is buggy, so we use item.ValueLength in combination with item.Text vItemvaluesArray(intLoop) = HIST_PREFIX_RTITEMS & Cstr(item.ValueLength) & "~~" & item.Text Else 'item.Type = RICHTEXT Then 'Process non rt-items. Convert names if desired Select Case HIST_CONVERT_NAMES_FIELDS Case True: If ( item.IsNames Or item.IsAuthors Or item.IsReaders ) Then Forall loop_nam In item.Values If Not loop_nam = "" Then If intCount = 0 Then strSepTemp = "" Else strSepTemp = HIST_SEP_NAME_ITM_CONTENT End If Set nn = New NotesName(loop_nam) strPersonNames = strPersonNames & strSepTemp & nn.Abbreviated intCount = intCount + 1 End If End Forall vItemvaluesArray(intLoop) = strPersonNames Else 'Item does not contain names vItemvaluesArray(intLoop) = item.Text End If Case Else: vItemvaluesArray(intLoop) = item.Text End Select End If 'item.Type = RICHTEXT Then End If 'Not (item Is Nothing) Then Next intLoop '// Return the Result GetItemTextContentInArray = vItemvaluesArray GoOut: Exit Function ErrorHandler: xErrorMsg Resume GoOut End Function Private Function StructureNewHistoryEntry(strText As String, intUseCurrentUserAndDate As Integer, _ strUsername As String, strDateTime As String) As String '====================================================================================== 'Purpose: 'Structures a new history entry. '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Parameters: Description: 'strText String. The text being included. 'intUseCurrentUserAndDate Boolean. If true (default): Uses the session.Username and Now as entry, ' if false: uses the provided username and date/time 'strUsername Only necessary if intUseCurrentUserAndDate = FALSE. ' String. The username being used for the new entry 'strDateTime Only necessary if intUseCurrentUserAndDate = FALSE. ' String. The date/time being used fdor the new entry '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Return: 'Formatted string. E.g.: '01/01/1990 09:17 Donald Duck text text text text text '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Called by: ' - ProcessPostSave ' - AddNewEntry ' - Record '====================================================================================== On Error Goto ErrorHandler Dim session As New NotesSession Dim strName As String Dim strDate As String Dim nn As NotesName Dim strNewEntry As String '// Check input value If Not Isscalar(strText) Then Error 1001, "The provided string (new entry) is not a scalar value !" strNewEntry = Cstr(strText) If (intUseCurrentUserAndDate = True) Then '// Prepare name Set nn = New NotesName(session.Username) Select Case Ucase$(HIST_NAME_ENTRY_TYPE) Case "ABBREVIATE", "ABBREVIATED": strName = nn.Abbreviated Case Else: strName = nn.Common End Select '// Prepare date/time strDate = Format$(Now, HIST_DATE_FORMAT) Else If Not Isscalar(strUsername) Then Error 1002, "The provided string (username) is not a scalar value !" If Not Isscalar(strDateTime) Then Error 1003, "The provided string (date/time) is not a scalar value !" strName = Cstr(strUsername) strDate = Cstr(strDateTime) End If '// Return result StructureNewHistoryEntry = strDate & Chr(9) & strName & Chr(9) & strNewEntry GoOut: Exit Function ErrorHandler: xErrorMsg Resume GoOut End Function Private Sub AddEntryX (strEntry As String, intUseCurrentUserAndDate As Integer, _ strUsername As String, strDateTime As String) '====================================================================================== 'Purpose: 'Adds a new entry to the history field (using current date/time and session.Username) '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Parameters: Description: 'strEntry The text (String) you want to add to the history. 'intUseCurrentUserAndDate Boolean. If true (default): Uses the session.Username and Now as entry, ' if false: uses the provided username and date/time 'strUsername Only necessary if intUseCurrentUserAndDate = FALSE. ' String. The username being used for the new entry 'strDateTime Only necessary if intUseCurrentUserAndDate = FALSE. ' String. The date/time being used fdor the new entry '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Called by: ' - AddEntry ' - AddEntry2 '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Used subs/functions: ' - StructureNewHistoryEntry ' - ReplaceHistory '====================================================================================== On Error Goto ErrorHandler Dim strNewEntry As String '// Check input values If Not Isscalar(strEntry) Then Error 1002, "The provided string is not a scalar value !" strNewEntry = Cstr(strEntry) ' --> strUsername and strDateTime will be checked later '// build new entry for the history m_strNewEntryTextFormatted = StructureNewHistoryEntry(strNewEntry, intUseCurrentUserAndDate, strUsername, strDateTime) '// get the current history item content m_vInitialItemValue = m_doc.GetItemValue(m_strHistoryItemName) '// perform the replacement Call ReplaceHistory '// needed if this method is used in a form where also 'PostopenStartObservation' is active to update the initial value ' of the history item m_vInitialItemValue = m_vNewHistoryValue GoOut: Exit Sub ErrorHandler: xErrorMsg Resume GoOut End Sub Private Sub xErrorMsg() '====================================================================================== 'Purpose: 'Error Routine. Displays an error message incl. the procedure name '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Called by: ' - every procedure :-) '====================================================================================== Dim session As New NotesSession Dim dbThis As NotesDatabase Dim vProcedure As Variant Dim strTitleClient As String Dim strMsgClient As String Dim strMsgServer As String Set dbThis = session.CurrentDatabase '// Get procedure name vProcedure = Getthreadinfo(MY_LSI_THREAD_CALLPROC) '// Setup client text strTitleClient = "Unexpected error - " & dbThis.Title strMsgClient = _ "Error #" & Err & Chr(10) _ & Error$ & Chr(10) _ & "Line #" & Erl & " in procedure : <" & vProcedure & ">" '// Setup server text strMsgServer = _ "Run-time error --- procedure: <" & vProcedure & ">" & ", error #" & Err & " (" & Error$ & "), line #" & Erl If session.UserName <> dbThis.Server Then 'Client-side processing... Msgbox strMsgClient, 48, strTitleClient Else 'Server-side processing... Print strMsgServer End If End Sub Private Function xRemoveLinebrakes(strSource As String, strSeparator As String) As String '====================================================================================== 'Purpose: 'Removes word-wrap chars '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Parameters: Description: 'strSource Source string to be cleared 'strSeparator A string which will be inserted. '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Return: 'A cleared string without any word-wrap chars '------------------------------------------------------------------------------------------------------------------------------------------------------ 'Called by: ' - ProcessPostSave '====================================================================================== On Error Goto ErrorHandler '// Check input values If Not Isscalar(strSource) Then Error 1001, "The provided string (Source) is not a scalar value !" If Not Isscalar(strSeparator) Then Error 1002, "The provided string (Separator) is not a scalar value !" strSource = Cstr(strSource) strSeparator = Cstr(strSeparator) Dim strReplacer As String Dim strBreaks(1) As String strBreaks(0) = Chr(10) strBreaks(1) = Chr(13) Forall br In strBreaks 'This While/Wend is here due to Notes R5 compatibility, in ND6 we can use the Replace function ! While Instr ( strSource, br ) > 0 strSource = Left$(strSource, Instr ( strSource,br ) - 1) & strSeparator & Right$(strSource, Len(strSource) - Instr ( strSource, br )) Wend xRemoveLinebrakes = strSource End Forall GoOut: Exit Function ErrorHandler: xErrorMsg Resume GoOut End Function End Class