'MacroName:CopyFields 'MacroDescription:Copies several fields without requiring the cursor to be placed in ' any certain position. ' ' This macro was written by Walter F. Nickeson, ' University of Rochester, Rochester, NY ' wnickeson@library.rochester.edu ' ' Last updated: 22 April 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: This macro copies contiguous variable fields from a record in the Client ' without your having to worry about precise cursor placement. First, have a ' bibliographic or authority record open ready to paste into. (The target record doesn't ' have to be on top, or visible. You can also paste fields into the same record from ' which you copied them, although if you want to simply copy one field--e.g., to copy the ' 100 to make into a 600--my "DuplicateField" macro is better. Furthermore, you can have ' as many open records or lists as you need--the macro ignores list displays.) In the ' record from which you are copying, click anywhere in the first field to copy, and ' extend the selection by dragging straight down across all the fields you wish to ' include in the copy, ending anywhere in the cell containing the last field to be ' copied. (You can also select by dragging backward, or up.) You don't have to click at ' the beginning of the tag in the first field, and end the selection with the last ' character in the last field, or vice-versa. The macro copies the whole of the fields in ' which the selection begins and ends (even though they may be only partially ' highlighted), and all fields in between, and then shows all the other open records of ' the same kind for you to choose in which one to paste. If you select only part of a ' single field, the whole field will be copied. ' ' The macro looks at the text that has been selected, figures out how many fields it ' spans, gets those fields, and stores them in an array. It uses the "GetField" command ' in order to include text not selected in the lines at the beginning and end of the ' selection block. Since special characters acquired with that command are lost by the ' Windows clipboard, the "AddField" command is used instead to paste the copied data. ' Finally, the macro displays, one at a time, all the appropriate records (unless they ' are tiled; but the macro still lets you know which record is the target) until ' instructed to stop at one and add the copied fields. '**************************************************************************************** Option Explicit Declare Function AddCancel( Id$, Action%, SValue& ) Sub Main Dim CS As Object Set CS = CreateObject("Connex.Client") Dim CopySelection$ : CopySelection$ = "" Dim EndOfField$ : EndOfField$ = Chr$( 013 ) & Chr$( 010 ) Dim FieldRetrieved$ Dim Fields$ Dim FirstTag$ Dim OCLCNumberFrom$ Dim OCLCNumberTo$ Dim RecordKind$ Dim ReplacedFrom$ Dim ReplacedTo$ Dim SelectedText$ Dim WindowTitle$ Dim Answer% Dim BeginningRow% Dim CountOfWindows% : CountOfWindows% = 0 Dim CountRecs% : CountRecs% = 0 Dim CurrentRow% Dim Difference% Dim EndOfFieldCount% : EndOfFieldCount% = 0 Dim EndOfFieldFound% : EndOfFieldFound% = 0 Dim PosFF% Dim Start% : Start% = 1 Dim TypeOfWindow% Dim WindowId% Dim WindowOrigin% Dim a, b, c, d, e, f, g : b = 0 Dim SameRec : SameRec = FALSE Dim SelectedUp : SelectedUp = FALSE Dim FieldsCopied$() Dim SelectRecs() ' First, check to see that some text has been selected! If CS.GetSelectedText( SelectedText$ ) = FALSE Then MsgBox "Please select some fields to copy!", 64, "Macro needs a selection to copy" GoTo Done: End If ' If the selection has been made by dragging upward, the last characters will be the end- ' of-field marker (ASCII characters 013 + 010). In this case we must do some calculations ' to figure out in which row is the end of the selection If Right$( SelectedText$, 2 ) = EndOfField$ Then SelectedUp = TRUE ' Get the OCLC number of the source record; this will be used later to aid in choosing ' the correct record in which to paste the copied field(s). Also get the date from the ' fixed field element "Replaced," used to break a tie when the window titles are the same CurrentRow% = CS.CursorRow Clipboard.Clear CS.CopyControlNumber OCLCNumberFrom$ = Clipboard.GetText() PosFF% = CS.FixedFieldPosition If PosFF% <> 1 Then CS.FixedFieldPosition = 1 If CS.GetFixedField( "Replaced", ReplacedFrom$ ) = FALSE Then ReplacedFrom$ = "" CS.FixedFieldPosition = PosFF% ' Determine whether this is a bibliographic or authority record, so the same sort of ' record will be displayed to paste into; it's unlikely that several fields would be ' copied into a record of a different kind WindowOrigin% = CS.ItemType Select Case WindowOrigin% Case 0 To 2, 17, 19 RecordKind$ = "B" Case 3 To 4, 14, 18, 20 RecordKind$ = "A" Case Else MsgBox "This macro only works in bibliographic and authority records! Exiting.", 64, "Macro finished" GoTo Done: End Select ' Then find the end-of-field markers within the selection to count how many fields have ' been included. The macro will also work with a selection made in a single field; in ' that case, it will copy the whole field Do EndOfFieldFound% = InStr( Start%, SelectedText$, EndOfField$ ) If EndOfFieldFound% > 0 Then Start% = EndOfFieldFound% + 1 EndOfFieldCount% = EndOfFieldCount% + 1 End If Loop Until EndOfFieldFound% = 0 If EndOfFieldCount% = 0 Then Fields$ = "field" Else Fields$ = "fields" End If ' The Client can tell where the end of the selection is by the cursor position, so by ' knowing how many end-of-field markers there are we can work backwards to find the row ' where the selection begins If SelectedUp = TRUE Then CurrentRow% = CurrentRow% + EndOfFieldCount% Difference% = CurrentRow% - EndOfFieldCount% BeginningRow% = Difference% ' Get each field within the selection and store it in an array. Although appending each ' field to a string variable and then sending that whole string to the Windows clipboard ' for pasting would be a simpler solution, that method can't handle special characters ReDim Preserve FieldsCopied$( EndOfFieldCount% ) For a = 0 To ( EndOfFieldCount% ) If CS.GetFieldLineUnicode( BeginningRow%, FieldRetrieved$) = FALSE Then MsgBox "Sorry, the macro failed to get a field.", 16, "Macro failed" GoTo Done: Else FieldsCopied$( a ) = FieldRetrieved$ End If BeginningRow% = BeginningRow% + 1 Next a ' Find a record to paste into. Cycle through all the open windows to find bibliographic ' or authority records, whichever matches the kind of record from which the fields were ' copied. Store their identification numbers in an array so they can be brought to the ' top, one by one, if necessary, to find the one in which to paste the copied field(s) CountOfWindows% = CS.WindowCount Do Until b = CountOfWindows% CS.SetTopWindow( b ) TypeOfWindow% = CS.ItemType Select Case TypeOfWindow% Case 0 To 2, 17, 19 If RecordKind$ = "B" Then ReDim Preserve SelectRecs( CountRecs% ) SelectRecs( CountRecs% ) = b CountRecs% = CountRecs% + 1 End If Case 3 To 4, 14, 18, 20 If RecordKind$ = "A" Then ReDim Preserve SelectRecs( CountRecs% ) SelectRecs( CountRecs% ) = b CountRecs% = CountRecs% + 1 End If End Select b = b + 1 Loop ' If no suitable record window is open, exit the macro If CountRecs% = 0 Then CS.SetTopWindow( CountOfWindows% ) MsgBox "No suitable record was found!", 48, "No record available" GoTo Done: End If ' Display the record(s) for consideration. First, capture the window title, and the OCLC ' control number, if any, to display in the dialog box that asks if the record displayed ' is the correct one into which to paste the field(s). This information is especially ' useful when the windows are tiled, as it's hard then to tell which record has the ' focus, or when working with two records for the same title. If all the data is the ' same, as when copying fields from one NEW record to another one, the macro uses the ' date in "Replaced" in the fixed field to distinguish records For c = 0 To CountRecs% - 1 CS.SetTopWindow( SelectRecs( c ) ) TypeOfWindow% = CS.ItemType If CS.GetWindowTitle ( -1, WindowTitle$ ) = TRUE Then ' If only one record is displayed, verify that the copied fields are really intended to ' be pasted back into it If CountRecs% = 1 Then Begin Dialog PasteHere 227, 65, "Source record displayed", .AddCancel Text 14, 10, 196, 10, "This is the only available record! Paste copied " & Fields$ & " back into it?" ButtonGroup .choice PushButton 44, 30, 58, 18, "&Yes" PushButton 125, 30, 58, 18, "&No, exit macro" CancelButton 1, 1, 1, 1 'Dummy button End Dialog Dim SourceRecord as PasteHere On Error Resume Next Dialog SourceRecord If Err = 102 Then GoTo Done: Select Case SourceRecord.choice Case 0 GoTo Paste: Case Else GoTo Done: End Select End If PosFF% = CS.FixedFieldPosition If PosFF% <> 1 Then CS.FixedFieldPosition = 1 If CS.GetFixedField( "Replaced", ReplacedTo$ ) = FALSE Then ReplacedTo$ = "" CS.FixedFieldPosition = PosFF% Clipboard.Clear CS.CopyControlNumber OCLCNumberTo$ = Clipboard.GetText() If ReplacedTo$ = ReplacedFrom$ Then SameRec = TRUE Else SameRec = FALSE End If If OCLCNumberTo$ = "NEW" Then OCLCNumberTo$ = Chr$( 034 ) & "NEW" & Chr$( 034 ) Else OCLCNumberTo$ = "#" & OCLCNumberTo$ End If ' Remove the words "Pinned" or "Workform" from the window title f = InStr( WindowTitle$, "(Pinned)" ) If f > 0 Then WindowTitle$ = Trim$( Mid$( WindowTitle$, 9 ) ) g = InStr( WindowTitle$, "Workform:" ) If g > 0 Then WindowTitle$ = Trim$( Mid$( WindowTitle$, 1, g + 7 ) ) Else Select Case TypeOfWindow% Case 0 'Online bibliographic record (WorldCat) WindowTitle$ = Trim$( Mid$( WindowTitle$, 17 ) ) Case 1 'Online bibliographic save file record WindowTitle$ = Trim$( Mid$( WindowTitle$, 33 ) ) Case 2 'Online bibliographic constant data record WindowTitle$ = Trim$( Mid$( WindowTitle$, 37 ) ) Case 3 'Online authority record (LC authority file) WindowTitle$ = Trim$( Mid$( WindowTitle$, 27 ) ) Case 4 'Online authority save file record WindowTitle$ = Trim$( Mid$( WindowTitle$, 29 ) ) Case 14 'Online authority constant data record WindowTitle$ = Trim$( Mid$( WindowTitle$, 33 ) ) Case 17 'Local bibliographic save file record WindowTitle$ = Trim$( Mid$( WindowTitle$, 51 ) ) Case 18 'Local authority save file record WindowTitle$ = Trim$( Mid$( WindowTitle$, 50 ) ) Case 19 'Local bibliographic constant data record WindowTitle$ = Trim$( Mid$( WindowTitle$, 60 ) ) Case 20 'Local authority constant data record WindowTitle$ = Trim$( Mid$( WindowTitle$, 58 ) ) End Select End If Else MsgBox "Sorry, an inexplicable error occurred.", 48, "Macro failed" GoTo Done: End If ' Shorten the title somewhat if it's too long If Len( WindowTitle$ ) > 80 Then WindowTitle$ = Left$( WindowTitle$, 80 ) & "..." If SameRec = TRUE Then WindowTitle$ = "Paste copied " & Fields$ & " back into the same record?" Else WindowTitle$ = "Paste copied " & Fields$ & " in this record (" & OCLCNumberTo$ & ", " & WindowTitle$ & ")?" End If Begin Dialog ChooseRecord 236, 88, "Select record for pasting " & Fields$, .AddCancel Text 28, 14, 182, 24, WindowTitle$ ButtonGroup .choice PushButton 22, 52, 58, 18, "&Yes" PushButton 88, 52, 58, 18, "&No, next record" PushButton 154, 52, 58, 18, "&Cancel" CancelButton 1, 1, 1, 1 'Dummy button End Dialog Dim RecordChoice as ChooseRecord On Error Resume Next Dialog RecordChoice If Err = 102 Then GoTo Done: Select Case RecordChoice.choice Case 0 Paste: For e = 0 to EndOfFieldCount% If CS.AddField( 9, FieldsCopied$( e ) ) = FALSE Then MsgBox "Sorry, could not add a field.", 16, "Macro failed" GoTo Done: End If BeginningRow% = BeginningRow% + 1 Next e GoTo Done: Case 1 If c = CountRecs% - 1 Then If RecordKind$ = "B" Then MsgBox "No more bibliographic records! Exiting macro.", 64, "Macro finished" ElseIf RecordKind$ = "A" Then MsgBox "No more authority records! Exiting macro.", 64, "Macro finished" End If GoTo Done: End If Case 2 GoTo Done: End Select Next c Done: End Sub '**************************************************************************************** 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