'MacroName:CalcTimes 'MacroDescription:Adds and converts times. ' ' This macro was written by Walter F. Nickeson, ' University of Rochester, Rochester, NY ' wnickeson@library.rochester.edu ' ' Thanks to Harvey Hahn for help with clearing the input box. Thanks to Terry Simpkins ' for some great ideas. All responsibility for this macro's appearance and functionality ' are mine alone. ' ' Last updated: 4 May 2009. ' Check for the latest versions of this and my other macros at ' http://docushare.lib.rochester.edu/docushare/dsweb/View/Collection-2556 ' Please e-mail me with bug reports or to suggest improvements. ' ' Works in Connexion client 2.10. ' '**************************************************************************************** ' How it works. To add times (as in durations of pieces of music or video): Type two or ' more times in the input box, or paste in a string containing times, or run the macro ' with the cursor in a contents field (tag 505) that contains times. The macro adds up ' the times input, or found in the string or field, and outputs the result in the format ' hours:minutes:seconds. ' ' Enter a single time, and the macro will convert it between punctuated and non- ' punctuated format (details below). ' ' The result of the calculation is displayed in a dialog box and also put on the Windows ' clipboard for pasting. The dialog box also allows for return to the input window to ' review the entries for correction, if necessary, or to input new data. The original ' string of times, whether entered manually or derived from a contents field, can then ' be inserted as a properly formatted 306 field and as a 500 "Duration:" note. ' ' When manually entering times to add, make sure the time entries are separated by ' spaces or periods (full stops or decimals). Alphabetic and other characters are ' ignored as input data. Entries can be up to six digits in length (99 hours, 59 ' minutes, and 59 seconds is the maximum individual duration). Colons may be omitted or ' included. Include trailing zeroes as placeholders, so enter six hours as 60000 (or ' 6:00:00); but six seconds can be input simply as 6. ' ' If the macro is run with the cursor in a 505 field, it will consider only numbers ' within parentheses as times, and only if those sets of numbers also include colons. ' Times that have been entered without being enclosed within parentheses will be ' ignored. ' ' Converting times: A simple number will be treated as seconds and converted to a mixed ' number in the format minutes:seconds. Add "m" at the end of the number to indicate ' minutes, and the macro will convert it to hours:minutes. A mixed number (hours: ' minutes:seconds or minutes:seconds) will be converted to the format minutes:seconds or ' just to seconds. Again, adding "m" at the end indicates that the last unit is minutes, ' rather than seconds. The macro will offer to convert some sums. ' ' Examples of manual data entry: ' ' Enter Macro output ' 337.407.610.739 21:33 ' 337 407 610 739 21:33 ' 3:37.4:07.6:10.7:39 21:33 ' 3:37 4:07 6:10 7:39 21:33 ' 143 02:23 ' 143m 2:23:00 ' 1:43 103 [seconds] ' 1:43m 103 [minutes] ' 1:43:38 103:38 ' ' Example of portion of contents note used as input or pasted in: ' ' $t All summer long $g (2:09) -- $t Catch a wave $g (2:09) -- $t Hawaii $g (2:00) -- $t ' Little Honda $g (1:54) -- $t 409 $g (2:00) -- $t It's OK $g (2:12) -- $t You're so ' good to me $g (2:16) -- $t Then I kissed her $g (2:17). ' ' Macro output, as a sum of times: 21:06 ' ' and as a 306 field: ' ' 306 000209 $a 000200 $a 000154 $a 000212 $a 000216 $a 000217 ' ' and as a 500 note (which in this example would not be added because of the presence of ' the 505 field): ' ' 500 Durations: 2:09; 2:09; 2:00; 1:54; 2:00; 2:12; 2:16; 2:17 '**************************************************************************************** Option Explicit Global EntriesToAdd$, RawString$, Totality$ Global Convert% Global CalcDone, Contents Declare Function AddCancel( Id$, Action%, SValue& ) Declare Function SetConclusionDialog( Id$, Action%, SValue& ) Declare Function SetInputDialog( Id$, Action%, SValue& ) Declare Function FormatField( InsertString$, Switch% ) As String Sub Main Dim CS As Object Set CS = CreateObject("Connex.Client") Dim Candidate$ Dim Entries$ Dim Field306$ Dim Field500$ Dim FieldData$ : FieldData$ = "" Dim HoursDisplay$ Dim Instructions1$, Instructions2$, Instructions3$ Dim JustLooking$ Dim MinutesDisplay$ Dim Operation$ Dim Quote$ : Quote$ = Chr$( 034 ) Dim ResultsMessage$ Dim SecondsDisplay$ Dim Tag$ Dim TempEntry$ : TempEntry$ = "" Dim TestChar$ Dim Answer% Dim ColonCount% Dim ColonEntry% : ColonEntry% = 0 Dim Count% Dim CountTimes% Dim Hours% Dim Minutes% Dim Row% Dim RunningTotal& Dim Seconds% Dim TempMinutes% Dim a, b, c, d, e, f As Integer Const MaxConvert& = 999999 Const MaxEntry% = 999 Dim Enhanced : Enhanced = FALSE Dim FieldInput : FieldInput = FALSE Dim Ignore : Ignore = FALSE Dim MinutesFlag : MinutesFlag = FALSE Dim Rejected : Rejected = FALSE Dim Review : Review = FALSE Dim Rounding : Rounding = TRUE EntriesToAdd$ = "" RawString$ = "" CalcDone = FALSE Contents = FALSE ' First, if the cursor is in a contents field (505), ask if the macro should take the ' data in the field as the input. If the cursor is in another field, or if the answer is ' "no," display the input box for manual data entry; otherwise get the data from the ' field, skip the input dialog box, and begin processing. But also check to see if there ' is a contents field, because if there is, we don't want to add a 500 "Duration:" note Row% = CS.CursorRow If CS.GetFieldLine( Row%, FieldData$ ) = TRUE Then Tag$ = Left$( FieldData$, 3 ) If Tag$ = "505" Then If Mid$( FieldData$, 5, 1 ) = "0" Then Enhanced = TRUE Begin Dialog InField 244, 56, "Choose input", .AddCancel Text 74, 8, 96, 8, "Add times in this contents field?" ButtonGroup .Choice PushButton 16, 28, 60, 16, "&Yes" PushButton 92, 28, 60, 16, "&No, manual input" PushButton 168, 28, 60, 16, "&Cancel" CancelButton 1, 1, 1, 1, .Cancel End Dialog Dim WhatToDo as InField On Error Resume Next Dialog WhatToDo If Err = 102 Then GoTo Done: Select Case WhatToDo.Choice Case 0 FieldInput = TRUE Contents = TRUE RawString$ = Mid$( FieldData$, 6 ) If RawString$ <> "" Then Rounding = FALSE GoTo Rewind: End If Case 1 FieldInput = FALSE Enhanced = FALSE Case 2, 3 GoTo Done: End Select Else If CS.GetField ( "505", 1, JustLooking$ ) = TRUE Then Contents = TRUE End If End If Recycle: ColonCount% = 0 Count% = 0 Entries$ = "" Hours% = 0 RunningTotal& = 0 TempEntry$ = "" ' The dialog box for data input Instructions1$ = "To add times, separate multiple entries with a space or a period. " Instructions1$ = Instructions1$ & "Colons may be omitted or included. Include zeroes. " Instructions1$ = Instructions1$ & "Or, paste in a string containing times (but take out " Instructions1$ = Instructions1$ & "other numbers)." Instructions2$ = "A single entry of hours:minutes:seconds will be converted to " Instructions2$ = Instructions2$ & "minutes:seconds. Otherwise it will be converted to " Instructions2$ = Instructions2$ & "seconds unless " & Quote$ & "m" & Quote$ & " is " Instructions2$ = Instructions2$ & "added to the end." Instructions3$ = "A single entry without punctuation will be converted to minutes:seconds. " Instructions3$ = Instructions3$ & "Add " & Chr$( 034 ) & "m" & Chr$( 034 ) & " at the " Instructions3$ = Instructions3$ & "end to convert to hours:minutes." Begin Dialog InputDialog 378, 172, "Enter times to add", .SetInputDialog Text 228, 8, 42, 10, "Sample input" Text 312, 8, 44, 10, "Macro result" Text 16, 18, 200, 24, Instructions1$ Text 228, 18, 72, 10, "725.601.1300.059.230" Text 312, 18, 44, 10, "29:55" Text 228, 26, 72, 10, "4:47 12:00 9:18 :59 3:22" Text 312, 26, 44, 10, "26:05" Text 16, 46, 200, 24, Instructions2$ Text 228, 46, 40, 10, "1:43:38" Text 312, 46, 44, 10, "60:38" Text 228, 54, 40, 10, "1:43" Text 312, 54, 44, 10, "103 seconds" Text 228, 62, 40, 10, "1:43m" Text 312, 62, 44, 10, "103 minutes" Text 16, 76, 200, 24, Instructions3$ Text 228, 76, 40, 10, "143" Text 312, 76, 44, 10, "02:23" Text 228, 84, 40, 10, "143m" Text 312, 84, 44, 10, "2:23:00" TextBox 16, 104, 346, 12, .EntryBox ButtonGroup .Result PushButton 72, 130, 62, 16, "&Go, add times!", .Go1 PushButton 32, 130, 62, 16, "&Go, add times!", .Go2 CheckBox 72, 150, 72, 12, "&Round up seconds", .RoundUp1 CheckBox 32, 150, 72, 12, "&Round up seconds", .RoundUp2 PushButton 158, 130, 62, 16, "&Erase entry", .ClearBox1 PushButton 116, 130, 62, 16, "&Erase entry", .ClearBox2 PushButton 200, 130, 62, 16, "&Insert as 306", .Insert PushButton 244, 130, 62, 16, "&Cancel", .Cancel1 PushButton 284, 130, 62, 16, "&Cancel", .Cancel2 CheckBox 204, 150, 58, 12, "Also add &500", .DurationList CancelButton 1, 1, 1, 1, .Cancel End Dialog Dim DataEntry as InputDialog On Error Resume Next Dialog DataEntry If Err = 102 Then GoTo Done: Select Case DataEntry.Result Case 2, 3, 5 To 7 GoTo Done: Case 4 ' The option to insert fields containing times--a 306 field containing specially ' formatted times, or a 500 field with entries in standard readable form--is available ' only after the macro has gone through the entry string once and performed its ' calculations. These fields are generated by the function "FormatField" operating on the ' previously manipulated string. After the 306 field is added, the macro ends, unless a ' corresponding 500 field is also added Field306$ = "306 " & FormatField( Field306$, 0 ) If CountTimes% > 6 Then Answer% = MsgBox( "There are " & CStr( CountTimes% ) & " times in this field! Do you want to proceed to add a 306 field anyway?", 20, "Entry guidelines exceeded" ) If Answer% = 7 Then GoTo Done: End If If CS.AddField( 99, Field306$ ) = FALSE Then MsgBox "Sorry, could not add 306 field.", 48, "Macro failure" GoTo Done: End If ' If the durations are to be entered as a 500 field, add that note as the macro's last ' action If DataEntry.DurationList = 1 And Contents = FALSE Then Field500$ = "500 Durations: " & FormatField( Field500$, 1 ) & "." If CS.AddField( 3, Field500$ ) = FALSE Then MsgBox "Sorry, could not add 500 field.", 48, "Macro failure" End If GoTo Done: End Select If DataEntry.RoundUp1 = 0 Or DataEntry.RoundUp2 = 0 Then Rounding = FALSE Else Rounding = TRUE End If RawString$ = Trim$( DataEntry.EntryBox ) ' If nothing has been entered, prompt to try again If RawString$ = "" Then MsgBox "Please enter some times to add or convert!", 64, "No data entered" EntriesToAdd$ = "" GoTo Recycle: End If Rewind: TempEntry$ = "" ' Edit the input string. If the input is a contents field, discard all characters not ' enclosed by parentheses. Check that all remaining strings are composed only of digits, ' and that they contain at least one colon (a test to eliminate dates or other non-time ' numbers) If FieldInput = TRUE Then a = 1 Do b = InStr( a, RawString$, "(" ) If b <> 0 Then c = InStr( a + 1, RawString$, ")" ) If c <> 0 Then Candidate$ = Mid$( RawString$, b + 1, c - b - 1 ) If Len( Candidate$ ) > 1 and Len( Candidate$ ) < 9 Then For d = 1 To Len( Candidate$ ) TestChar$ = Mid$( Candidate$, d, 1 ) If TestChar$ = ":" Then ColonEntry% = ColonEntry% + 1 ElseIf TestChar$ Like "[!0-9]" Then Rejected = TRUE GoTo Increment: End If Next d Else Rejected = TRUE End If Else MsgBox "There may be a problem with mismatched parentheses!", 64, "Invalid data entry" GoTo Recycle: End If If ColonEntry% = 0 Then Rejected = TRUE Else ColonCount% = ColonCount% + 1 End If If Rejected = FALSE Then Entries$ = Entries$ & " " & Candidate$ ColonEntry% = 0 Increment: Rejected = FALSE a = c + 1 Else c = InStr( a + 1, RawString$, ")" ) If c <> 0 Then MsgBox "There may be a problem with mismatched parentheses!", 64, "Invalid data entry" End If Loop Until b = 0 ' If the input string is entered manually, check that it consists only of numbers, ' spaces, decimal points (periods), colons, and the letter "m" (which at the end of an ' entry forces the entry to be considered as minutes rather than seconds). If any other ' character is found, omit it. Otherwise, substitute spaces for period separators. Count ' the colons in order to direct conversion Else Entries$ = RawString$ For a = 1 To Len( Entries$ ) TestChar$ = Mid$( Entries$, a, 1 ) If TestChar$ Like "[0-9: ]" Then TempEntry$ = TempEntry$ & TestChar$ If TestChar$ = ":" Then ColonCount% = ColonCount% + 1 ElseIf TestChar$ = "." Then TempEntry$ = TempEntry$ & " " ElseIf ( TestChar$ = "M" Or TestChar$ = "m" ) And a = Len( Entries$ ) Then MinutesFlag = TRUE End If Next a Entries$ = Trim$( TempEntry$ ) TempEntry$ = "" Do b = InStr( Entries$, " " ) If b <> 0 Then Entries$ = Left$( Entries, b ) & Mid$( Entries$, b + 2 ) Loop Until b = 0 RawString$ = Trim$( Entries$ ) End If Entries$ = Trim$( Entries$ ) If FieldInput = TRUE And Entries$ = "" Then MsgBox "There appear to be no times in this field! Please input times manually.", 64, "Invalid data entry" FieldInput = FALSE RawString$ = "" GoTo Recycle: End If ' If a single entry is valid but less than 60, there is nothing for the macro to do-- ' conversion applies only to entries greater than 60, and a single entry can't be added. ' Ask if the intent was to enter more data If Entries$ <> "" And Val( Entries$ ) < 60 And ColonCount = 0 Then Begin Dialog NothingToDo 200, 72, "Insufficient data?", .AddCancel Text 24, 12, 152, 24, _ "The number entered is too short for conversion. Did you mean to enter more data?" ButtonGroup .Choice PushButton 16, 40, 76, 16, "&Yes, show input box" PushButton 108, 40, 76, 16, "&No, cancel macro" CancelButton 1, 1, 1, 1, .Cancel End Dialog Dim MoreOrStop as NothingToDo On Error Resume Next Dialog MoreOrStop If Err = 102 Or MoreOrStop.Choice = 1 Then GoTo Done: Else FieldInput = FALSE RawString$ = Entries$ GoTo Recycle: End If End If Convert: Convert% = InStr( Entries$, " " ) If Convert% = 0 Then ' If there are no spaces in the string, then the string contains a single entry, and so ' it will be converted rather than added. The number of colons determines the conversion. ' Two colons means conversion from hours:minutes:seconds to minutes:seconds. One colon ' ordinarily means conversion from minutes:seconds to seconds, but a terminal "m" will ' force the conversion to hours:minutes. The number in the first group of digits entered ' must be less than 999, and there must be a pair of digits following each colon, of ' value less than 60. The result string shows the original entry and the converted ' number, along with a term to make clear how the input was considered by the macro ' (e.g., if "2:17m" was entered, display "2:17 [hours:minutes] to show that the macro ' knew not to convert 2 minutes and 17 seconds) Select Case ColonCount% Case 3 To 99 MsgBox "Please check the placement of the colons.", 64, "Invalid data entry" GoTo Recycle: Case 2 If Right$( Entries$, 6 ) Like ":##:##" Then Hours% = Val( Left$( Entries$, Len( Entries$ ) - 6 ) ) If Hours% > MaxEntry% Then MsgBox "The entry is too long! Please input fewer than 999 hours.", 64, "Invalid data entry" GoTo Recycle: ElseIf Val( Mid$( Entries$, Len( Entries$ ) - 4, 2 ) ) >= 60 Then MsgBox "The number of minutes entered is too big.", 64, "Invalid data entry" GoTo Recycle: ElseIf Val( Right$( Entries$, 2 ) ) >= 60 Then MsgBox "The number of seconds entered is too big.", 64, "Invalid data entry" GoTo Recycle: Else Minutes% = ( Hours% * 60 ) + Val( Mid$( Entries$, Len( Entries$ ) - 4, 2 ) ) Totality$ = CStr( Minutes% ) & ":" & Right$ ( Entries$, 2 ) ResultsMessage$ = Entries$ & " = " & Totality$ & " [minutes:seconds]." GoTo Display: End If Else MsgBox "Something seems to be wrong with the form of the entry! Please check it.", 64, "Invalid data entry" GoTo Recycle: End If Case 1 If Right$( Entries$, 3 ) Like ":##" Then If MinutesFlag = TRUE Then Hours% = Val( Left$( Entries$, Len( Entries$ ) - 3 ) ) If Hours% > MaxEntry% Then MsgBox "The entry is too long! Please input fewer than 999 hours.", 64, "Invalid data entry" GoTo Recycle: ElseIf Val( Right$( Entries$, 2 ) ) >= 60 Then MsgBox "The number of minutes entered (" & Right$( Entries$, 2 ) & _ ") is too big.", 64, "Invalid data entry" GoTo Recycle: Else Minutes% = ( Hours% * 60 ) + Val( Right$( Entries$, 2 ) ) Totality$ = CStr( Minutes% ) ResultsMessage$ = Entries$ & " [hours:minutes] = " & Totality$ & " [minutes]." GoTo Display: End If Else Minutes% = Val( Left$( Entries$, Len( Entries$ ) - 3 ) ) If Minutes% > MaxEntry% Then MsgBox "The entry is too long! Please input fewer than 999 minutes.", 64, "Invalid data entry" GoTo Recycle: ElseIf Val( Right$( Entries$, 2 ) ) >= 60 Then MsgBox "The number of seconds entered (" & Right$( Entries$, 2 ) & _ ")is too big.", 64, "Invalid data entry" GoTo Recycle: Else Seconds% = ( Minutes% * 60 ) + Val( Right$( Entries$, 2 ) ) Totality$ = CStr( Seconds% ) ResultsMessage$ = Entries$ & " [minutes:seconds] = " & Totality$ & " [seconds]." GoTo Display: End If End If Else MsgBox "Please check the number of seconds in the entry!", 64, "Invalid data entry" GoTo Recycle: End If End Select ' If no colon is present, the macro will convert a number to colon format. This number ' has to be smaller than 999,999 for the math to work. The result string shows the ' original entry and the converted number, with the unit at the end for clarity If Val( Entries$ ) > MaxConvert& Then MsgBox "Sorry, the macro can't handle a number that big.", 64, "Invalid data entry" GoTo Recycle: End If If MinutesFlag = TRUE Then RunningTotal& = Val( Entries$ ) * 60 Entries$ = Entries$ & " [minutes]" Else RunningTotal& = Val( Entries$ ) Entries$ = Entries$ & " [seconds]" End If GoTo Calculate: End If ' At this point in the macro the input string is composed only of time values to be ' added. (Single entries to be converted have been processed and results prepared for ' display in the preceding section, and bypass these lines.) Save the manipulated, ' formatted string for placement in the input box if the macro's results are to be ' reviewed, according to the final dialog box EntriesToAdd$ = Entries$ ' Begin the adding process by looping through the input string to remove colons, so that ' the code for addition deals with no characters other than numbers Do e = InStr( 1, Entries$, ":" ) If e <> 0 Then Entries$ = Left$( Entries$, e - 1 ) & Mid$( Entries$, e + 1 ) Loop Until e = 0 ' The cleaned string is the basis for adding the specially formatted 306 and 500 fields Field306$ = Entries$ Field500$ = Entries$ ' Add the entries. Each time the macro loops, remove the first entry (the part before the ' first space) for processing. Keep track of the number of entries in the string; this ' number will be displayed with the result, as a way of checking data entry Do f = InStr( Entries$, " " ) If f <> 0 Then TempEntry$ = Trim$( Mid$( Entries$, 1, f - 1 ) ) Entries$ = Trim$( Mid$( Entries$, f + 1 ) ) Else TempEntry$ = Trim$( Entries$ ) End If Count% = Count% + 1 ' Consider each entry, from right to left, converting minutes and hours to seconds, and ' cumulating the totals. If the first digit of a unit is greater than 6 but there are ' digits to the left, consider the entry invalid; e.g., an entry of "3:73" is rejected, ' but an entry of "73:33" or "85" is valid Select Case Len( Trim$( TempEntry$ ) ) Case 1 To 2 'Seconds only RunningTotal& = RunningTotal& + Val( TempEntry$ ) Case 3 'One digit of minutes, plus seconds If Val( Mid$( TempEntry$, 2, 1 ) ) > 6 Then MsgBox "Invalid input! Please check the number of seconds in the entry " & Quote$ & TempEntry & Quote$ & ".", 64, "Invalid data entry" GoTo Recycle: End If RunningTotal& = RunningTotal& + Val( Right$( TempEntry$, 2 ) ) RunningTotal& = RunningTotal& + ( 60 * Val( Left$( TempEntry$, 1 ) ) ) Case 4 'Two digits of minutes, plus seconds If Val( Mid$( TempEntry$, 3, 1 ) ) > 6 Then MsgBox "Invalid input! Please check the number of seconds in the entry " & Quote$ & TempEntry & Quote$ & ".", 64, "Invalid data entry" GoTo Recycle: End If RunningTotal& = RunningTotal& + Val( Right$( TempEntry$, 2 ) ) RunningTotal& = RunningTotal& + ( 60 * Val( Left$( TempEntry$, 2 ) ) ) Case 5 'One digit of hours, plus minutes and seconds If Val( Mid$( TempEntry$, 4, 1 ) ) > 6 Then MsgBox "Invalid input! Please check the number of seconds in the entry " & Quote$ & TempEntry & Quote$ & ".", 64, "Invalid data entry" GoTo Recycle: End If If Val( Mid$( TempEntry$, 2, 1 ) ) > 6 Then MsgBox "Invalid input! Please check the number of minutes in the entry " & Quote$ & TempEntry & Quote$ & ".", 64, "Invalid data entry" GoTo Recycle: End If RunningTotal& = RunningTotal& + Val( Right$( TempEntry$, 2 ) ) RunningTotal& = RunningTotal& + ( 60 * Val( Mid$( TempEntry$, 3, 2 ) ) ) RunningTotal& = RunningTotal& + ( 3600 * Val( Left$( TempEntry$, 1 ) ) ) Case 6 'Two digits of hours, plus minutes and seconds If Val( Mid$( TempEntry$, 5, 1 ) ) > 6 Then MsgBox "Invalid input! Please check the number of seconds in the entry " & Quote$ & TempEntry & Quote$ & ".", 64, "Invalid data entry" GoTo Recycle: End If If Val( Mid$( TempEntry$, 3, 1 ) ) > 6 Then MsgBox "Invalid input! Please check the number of minutes in the entry " & Quote$ & TempEntry & Quote$ & ".", 64, "Invalid data entry" GoTo Recycle: End If RunningTotal& = RunningTotal& + Val( Right$( TempEntry$, 2 ) ) RunningTotal& = RunningTotal& + ( 60 * Val( Mid$( TempEntry$, 3, 2 ) ) ) RunningTotal& = RunningTotal& + ( 3600 * Val( Left$( TempEntry$, 2 ) ) ) Case Else MsgBox "One of the values entered is too long! Please enter a time of six digits or fewer.", _ 64, "Invalid data entry" GoTo Recycle: End Select Loop Until f = 0 CountTimes% = Count% Calculate: ' Now calculate hours and minutes from the total number of seconds If RunningTotal& >= 3600 Then Hours% = Fix( RunningTotal& / 3600 ) TempMinutes% = RunningTotal& Mod 3600 Minutes% = Fix( TempMinutes% / 60 ) Seconds% = TempMinutes% Mod 60 ElseIf RunningTotal& >= 60 Then Minutes% = Fix( RunningTotal& / 60 ) Seconds% = RunningTotal& Mod 60 Else Seconds% = RunningTotal& End If ' Format the display. Don't show hours if there are none, but always show minutes, and ' pad minutes and seconds with zeroes if necessary If Seconds% > 0 And Rounding = TRUE Then Minutes% = Minutes% + 1 SecondsDisplay$ = "00" ElseIf Seconds% < 10 Then SecondsDisplay$ = "0" & CStr( Seconds% ) Else SecondsDisplay$ = CStr( Seconds% ) End If If Minutes% < 10 Then MinutesDisplay$ = "0" & CStr( Minutes% ) Else MinutesDisplay$ = CStr( Minutes% ) End If If Hours% = 0 Then HoursDisplay$ = "" Else HoursDisplay$ = CStr( Hours% ) & ":" End If Totality$ = HoursDisplay$ & MinutesDisplay$ & ":" & SecondsDisplay$ ' If multiple entries were added, give the count If Convert% = 0 Then ResultsMessage$ = Entries$ & " = " & Totality$ & "." Else If Rounding = TRUE Then ResultsMessage$ = "The " & CStr( Count% ) & " times entered add up to (rounded): " & Totality$ & "." Else ResultsMessage$ = "The " & CStr( Count% ) & " times entered add up to: " & Totality$ & "." End If End If Display: ' Put the string (without text) on the clipboard for pasting into a record (or elsewhere) ' if desired Clipboard.Clear Clipboard.SetText Totality$ ' Display the result. When the macro has added times, the number of entries is shown as ' well as the sum; when the macro has converted times, the original time entered is ' shown. The "Review" button jumps the macro back to the first dialog box to display the ' list of times entered for checking, if data entry errors are suspected or insertion of ' a 306 or 500 field is desired, or for input of more or new numbers. The "Convert" ' button converts the result of addition if the result is over an hour If Convert% = 0 Then Operation$ = "Result of conversion" Else Operation$ = "Result of addition" End If Begin Dialog Present 216, 136, Operation$, .SetConclusionDialog Text 24, 12, 168, 10, ResultsMessage$ Text 24, 22, 96, 10, "Result also copied to clipboard." ButtonGroup .Finish PushButton 24, 44, 168, 16, "&OK, macro finished" PushButton 24, 72, 168, 16, "&Review, New input, or Insert as 306 field" PushButton 24, 100, 168, 16, "&Convert result", .ConvertResult CancelButton 1, 1, 1, 1, .Cancel End Dialog Dim Conclusion as Present On Error Resume Next Dialog Conclusion If Err = 102 Then GoTo Done: Entries$ = "" ColonCount% = 0 FieldInput = FALSE Ignore = FALSE CalcDone = TRUE Select Case Conclusion.Finish Case 1 Review = TRUE GoTo Recycle: Case 2 RawString$ = Trim$( Totality$ ) GoTo Rewind: End Select Done: End Sub '**************************************************************************************** ' FUNCTIONS '**************************************************************************************** Function AddCancel( Id$, Action%, SValue& ) ' This function makes the pixel-square "CancelButton" in the dialog boxes invisible, so ' they can be closed with the [ESC] key or the X-close box in the corner while still ' retaining the hotkey enabled custom cancel button If Action% = 1 Then DlgVisible "Cancel", 0 End Function '**************************************************************************************** Function SetInputDialog( Id$, Action%, SValue& ) ' If the macro is working on data pulled from a 505 rather than entered in the input box, ' there will be nothing to go back to for review after the macro has added the times it ' found. This function populates the input box with the times the macro extracted from ' the field (that is, after it processed the string, discarding extra characters, testing ' for parentheses, etc.). Otherwise, the input box retains the original values entered ' manually. This function also manipulates the appearance of the input box. The option to ' insert a 306 or 500 field only appears after the macro has performed its calculations, ' so the "Insert" button and "Add 500" checkbox are hidden until the calculation has been ' done. If the record contains a contents note, the "Add 500" checkbox remains hidden. ' For esthetic reasons, there are two sets of buttons, one with three (the initial ' appearance of the dialog box) and one with four. Each set is hidden when the other is ' displayed. Finally, this function takes care of clearing the input box for new entry if ' the "Erase entry" button is selected (Case 2 in "Select Case Action%"). The crucial ' code here is the line setting the value of the function to -1 (although any non-zero ' value may also work) to keep the dialog box open after the input box is erased by ' placing an empty string into it Dim ReviewString$ Select Case Action% Case 1 If EntriesToAdd$ = "" Then ReviewString$ = RawString$ Else ReviewString$ = EntriesToAdd$ End If DlgText "EntryBox", ReviewString$ DlgValue "RoundUp1", 1 DlgValue "RoundUp2", 1 If CalcDone = FALSE Then DlgVisible "Go1", 1 DlgVisible "Go2", 0 DlgVisible "RoundUp1", 1 DlgVisible "RoundUp2", 0 DlgVisible "ClearBox1", 1 DlgVisible "ClearBox2", 0 DlgVisible "Insert", 0 DlgVisible "DurationList", 0 DlgValue "DurationList", 0 DlgVisible "Cancel1", 1 DlgVisible "Cancel2", 0 Else DlgVisible "Go1", 0 DlgVisible "Go2", 1 DlgVisible "RoundUp1", 0 DlgVisible "RoundUp2", 1 DlgVisible "ClearBox1", 0 DlgVisible "ClearBox2", 1 DlgVisible "Insert", 1 If Contents = TRUE Then DlgVisible "DurationList", 0 Else DlgVisible "DurationList", 1 End If DlgValue "DurationList", 1 DlgVisible "Cancel1", 0 DlgVisible "Cancel2", 1 DlgFocus "Insert" End If DlgVisible "Cancel", 0 Case 2 If Id$ = "ClearBox1" Or Id$ = "ClearBox2" Then ReviewString$ = "" DlgText "EntryBox", "" DlgFocus "EntryBox" SetInputDialog = - 1 End If Case 3 If Id$ = "EntryBox" Then CalcDone = FALSE If DlgVisible( "Insert" ) <> 0 Then DlgEnable "Insert", 0 If DlgVisible( "DurationList" ) <> 0 Then DlgVisible "DurationList", 0 End If End Select End Function '**************************************************************************************** Function SetConclusionDialog( Id$, Action%, SValue& ) ' If multiple times are added, such as the tracks on a music CD, the answer may be ' greater than one hour. If the answer is preferred to be in the form of minutes, the ' macro can convert it: Thus, after adding times to get 1:05:14, a click of the mouse ' will convert it to 65:14, without having to re-enter the data. ' ' This function controls whether the button that sends the result back for the macro to ' convert is visible. It should appear only when the result is a figure able to be ' converted (i.e., it contains hours) If Action% = 1 Then If Len( Totality$ ) < 6 Then DlgVisible "ConvertResult", 0 Else DlgVisible "ConvertResult", 1 End If End If End Function '**************************************************************************************** Function FormatField( InsertString$, Switch% ) ' This function takes the times in a string and formats them for insertion into the ' bibliographic record as either a 306 or a 500 field ("Duration:"), depending on the ' value of "Switch%": "0" formats the string for a 306 field, by padding each time with ' leading zeroes to form six-digit chunks, and checking for uniqueness of durations, so ' identical times are excluded; "1" formats the string for a 500 field, restoring colons ' and separating times by semicolons. In either case, times are converted (i.e., minutes ' or seconds over 60 are reduced and hours or minutes are increased) Dim Duration$ : Duration$ = "" Dim Hours2Display$ Dim Minutes2Display$ Dim Seconds2Display$ Dim TempString$ : TempString$ = "" Dim TempTime$ Dim Hours2% Dim Minutes2% Dim Seconds2% Dim g, h, i : h = 1 Do ' First, break the input string up into chunks at spaces g = InStr( h, InsertString$, " " ) If g <> 0 Then Duration$ = Mid$( InsertString$, h, g - h ) Else If h = 1 Then Duration$ = InsertString$ Else Duration$ = Mid$( InsertString$, h ) End If End If ' Separate each individual time into pairs of numbers--seconds, minutes, and hours, ' converting them if necessary, recombining the pairs, and formatting the whole for ' display by adding leading zeroes or semicolons Select Case Len( Duration$ ) Case 1 To 2 Hours2% = 0 Minutes2% = 0 Seconds2% = Val( Duration$ ) Case 3 To 4 Hours2% = 0 Minutes2% = Val( Left$( Duration$, Len( Duration$ ) - 2 ) ) Seconds2% = Val( Right$( Duration$, 2 ) ) Case 5 To 6 Hours2% = Val( Left$( Duration$, Len( Duration$ ) - 4 ) ) Minutes2% = Val( Mid$( Duration$, Len( Duration$ ) - 3, 2 ) ) Seconds2% = Val( Right$( Duration$, 2 ) ) End Select If Seconds2% >= 60 Then Seconds2% = Seconds2% - 60 Minutes2% = Minutes2% + 1 End If If Seconds2% < 10 Then Seconds2Display$ = "0" & CStr( Seconds2% ) Else Seconds2Display$ = CStr( Seconds2% ) End If If Minutes2% >= 60 Then Minutes2% = Minutes2% - 60 Hours2% = Hours2% + 1 End If If Minutes2% < 10 Then Minutes2Display$ = "0" & CStr( Minutes2% ) Else Minutes2Display$ = CStr( Minutes2% ) End If If Switch% = 0 Then If Hours2% < 10 Then Hours2Display$ = "0" & CStr( Hours2% ) TempTime$ = Hours2Display$ & Minutes2Display$ & Seconds2Display$ End If Else If Hours2% = 0 Then If Minutes2% = 0 Then Minutes2Display$ = "0:" TempTime$ = Minutes2Display$ & Seconds2Display$ Else If Minutes2% < 10 Then Minutes2Display$ = CStr( Minutes2% ) TempTime$ = Minutes2Display$ & ":" & Seconds2Display$ End If Else TempTime$ = CStr( Hours2% ) & ":" & Minutes2Display$ & ":" & Seconds2Display$ End If End If If Switch% = 0 Then i = InStr( TempString$, Duration$ ) If i = 0 Then TempString$ = TempString$ & TempTime$ & " " & Chr$( 223 ) & "a " Else TempString$ = TempString$ & TempTime$ & "; " End If h = g + 1 Loop Until g = 0 ' Remove the leftover stuff from the loop If Switch% = 0 Then FormatField = Left$( TempString$, Len( TempString$ ) - 4 ) Else FormatField = Left$( TempString$, Len( TempString$ ) - 2 ) End If End Function