Error in Apple script for saving password-protected PDF - pdf

Can anyone please help me find a solution for the error I'm getting? MacOS is Monterrey and this script used to work in Big Sur.
It seems it is unable to find splitter group 3 (which would the page style). And the same happens when it tries to find "PDF" splitter and save as PDF.
I would appreciate any help/suggestions you can provide.
-- Don't change this
set FixedPassword to "somePW"
--Change the following for each Review accordingly
set exam to "2"
set session to "5"
set VarPassword to "barcelona"
set outpath to "/Users/user/Dropbox/Physics" & " - " & "Current/2023-1-Spring/UF/2." & " " & "Chapter" & " " & "Reviews/" & ¬
"Exam" & " " & exam & " " & "Session" & " " & session & "/E" & exam & "S" & session & ".pdf"
set SaveFolder to "/Users/user/Dropbox/Physics" & " - " & "Current/2023-1-Spring/UF/2." & " " & "Chapter" & " " & "Reviews/" & ¬
"Exam" & " " & exam & " " & "Session" & " " & session
set FileName to "E" & exam & "S" & session & " " & "(Password" & " - " & VarPassword & ").pdf"
--Saving PDF with password protection
tell application "Preview"
activate
open outpath
end tell
activate application "Preview"
tell application "System Events"
tell process "Preview"
keystroke "p" using command down
delay 0.5
tell front window
repeat until exists sheet 1
delay 1
end repeat
tell sheet 1
tell splitter group 3
click pop up button 3
click menu item "Review 216 by 279 mm" of menu 1 of pop up button 3
end tell
tell splitter group 3
click menu button "PDF"
repeat until exists menu 1 of menu button "PDF"
delay 3
end repeat
click menu item "Save as PDF" of menu 1 of menu button "PDF"
end tell
end tell
end tell
-- Make sure the save dialog is visible
repeat until exists sheet 1 of sheet 1 of front window
delay 5
end repeat
tell sheet 1 of sheet 1 of front window
click button "Security Options..."
end tell
tell window "PDF Security Options"
set selected to true
set focused to true
(* click the checkbox to on *)
-- NOTE: for some reason there is a delay of about 6 seconds here, I do not know why
tell checkbox "Require password to open document"
click
end tell
(* add the password and confirm *)
keystroke VarPassword
keystroke (ASCII character 9)
keystroke VarPassword
tell its checkbox "Require password to copy text, images and other content"
click
end tell
(* add the password and confirm *)
keystroke FixedPassword
keystroke (ASCII character 9)
keystroke FixedPassword
click button "OK"
end tell
repeat until exists sheet 1 of sheet 1 of front window
delay 0.2
end repeat
-- Press command+shift+g to show the "Go" drop down sheet
keystroke "g" using {command down, shift down}
repeat until exists sheet of sheet 1 of sheet 1 of front window
delay 0.2
end repeat
delay 0.5
keystroke SaveFolder
delay 0.5
click button "Go" of sheet of sheet 1 of sheet 1 of front window
-- Now that we are in our desired folder, set the file name and save
set value of text field 1 of sheet 1 of sheet 1 of front window to FileName
click button "Save" of sheet 1 of sheet 1 of front window
end tell
end tell
But it gives the following error:

For some reason I don't get that error anymore, but I managed to fix some other errors and make it work by increasing the delay and adding a keystroke to return (in previous OS versions it wasn't needed)
tell application "Preview"
activate
open outpath
end tell
activate application "Preview"
tell application "System Events"
tell process "Preview"
keystroke "p" using command down
delay 0.5
tell front window
repeat until exists sheet 1
delay 1
end repeat
tell sheet 1
tell splitter group 1
click pop up button 3
--click menu item "Review" of menu 1 of pop up button 3
click menu item "Review 216 by 279 mm" of menu 1 of pop up button 3
end tell
tell splitter group 1
click menu button "PDF"
repeat until exists menu 1 of menu button "PDF"
delay 0.02
end repeat
click menu item "Save as PDF" of menu 1 of menu button "PDF"
end tell
end tell
end tell
-- Make sure the save dialog is visible
repeat until exists sheet 1 of sheet 1 of front window
delay 5
end repeat
--return name of every button of sheet 1 of sheet 1 of front window
tell sheet 1 of sheet 1 of front window
click button "Security Options…"
end tell
tell window "PDF Security Options"
set selected to true
set focused to true
(* click the checkbox to on *)
-- NOTE: for some reason there is a delay of about 6 seconds here, I do not know why
tell checkbox "Require password to open document"
click
end tell
(* add the password and confirm *)
keystroke VarPassword
keystroke (ASCII character 9)
keystroke VarPassword
tell its checkbox "Require password to copy text, images and other content"
click
end tell
(* add the password and confirm *)
keystroke FixedPassword
keystroke (ASCII character 9)
keystroke FixedPassword
click button "OK"
end tell
repeat until exists sheet 1 of sheet 1 of front window
delay 0.2
end repeat
-- Press command+shift+g to show the "Go" drop down sheet
keystroke "g" using {command down, shift down}
repeat until exists sheet of sheet 1 of sheet 1 of front window
delay 0.2
end repeat
delay 0.5
keystroke SaveFolder
delay 0.5
--click button "Go" of sheet of sheet 1 of sheet 1 of front window
keystroke return
-- Now that we are in our desired folder, set the file name and save
set value of text field 1 of sheet 1 of sheet 1 of front window to FileName
click button "Save" of sheet 1 of sheet 1 of front window
end tell
end tell

Related

MS Word VBA Macro from validation

I'm trying to do what, I think, ought to be the simplest of things, but I can't get it to work. i have an MS Word document with a number of legacy drop-down and text fields:
The first option in each drop-down is "Select ...", and if a user tabs out of one of the drop-downs without choosing something other than the first "Select ...", I want a msgbox to appear to tell them to make a selection, which works. What doesn't work, is that after the user dismisses the msgbox, I want the insertion point to return to the drop-down that they didn't select.
I understand that VBA has "timing issues", and from what I've read, one way to address these timing issues is to call the "return" macro from the validation macro. So I've written two macros:
Sub Validate()
' Dim strBookmark As String
' strBookmark = Selection.Bookmarks(1).Name
10: If (bool_debug) Then MsgBox ("NotSelected() - 10: strBookmark = " & strBookmark)
With ActiveDocument
If (strBookmark = "Locality") Then
Call Salary_Step
ElseIf (strBookmark = "Series") Then
20: If (bool_debug) Then MsgBox ("NotSelected() - 20: .FormFields(strBookmark).Name = " _
& .FormFields(strBookmark).Name)
If ((Len(.FormFields(strBookmark).Result) <> 4) Or (Not IsNumeric(.FormFields(strBookmark).Result))) Then _
MsgBox ("Please enter a 4 digit number.")
Call GoBackToPrevious(.FormFields(strBookmark).Name)
ElseIf (.FormFields(strBookmark).DropDown.Value = 1) Then
MsgBox ("Please select a " & Replace(Selection.FormFields(strBookmark).Name, "_", " ") & ".")
Call GoBackToPrevious(.FormFields(strBookmark).Name)
End If
End With
End Sub
and
Sub GoBackToPrevious(strPreviousField)
10: If (bool_debug) Then MsgBox ("GoBacktoPrevious - 10: strPreviousField = " & strPreviousField)
ActiveDocument.Bookmarks(strPreviousField).Range.Fields(1).Result.Select
End Sub
But when I tab out of any of the form fields, the insertion point jumps to the next form field and not back to the one that I just tabbed out of.
I know from the debug code that GoBackToPrevious is being passed the name of the current form field, but MS Word advances to the next field regardless.
I'd really appreciate it if someone can tell me how make MS Word return to and select the drop-down the user did not select appropriately instead of jumping to and selecting the next form field in the document.
Thank you.
P James Norris
EDIT:
Based on #TimothyRylatt comments, I have modified my macro and when they're called.
I have edited Validate as above (commenting out the Dim the strBookmark assignment, and I call it "on entry" to the next form field.
strBookmark is Dimed on the module's declaration section:
Option Explicit
Const bool_debug As Boolean = True
Const str_password As String = "###" ' I have a different password
Public strBookmark As String
and "on exit" from the "current" form field, I attempt to store the "current" bookmark name:
Sub StoreBookmark()
strBookmark = Selection.Bookmarks(1).Name
10: If (bool_debug) Then MsgBox ("StoreBookmark() - 10: strBookmark = " & strBookmark)
End Sub
which I call from the current form field "on exit".
But when I tab out of the current form field to the next form field, the insertion point doesn't go back to the "current" but instead stays in the next form field.
Anyone have any other suggestions/insights?
Thanks,
P James Norris

Form closes but the written conditions therein not implemented

I have the following two codes on a button: The (first code) aims to submit value of option button into worksheet cell:
For Each FormControl In Me.Controls
'Check only OptionButtons
If TypeName(FormControl) = "OptionButton" Then
'Check the status of the OptionButton
If FormControl.Value = True Then
'Set a variable equal to the Caption of the selected OptionButton
OptionButtonValue = FormControl.Caption
'We found the selected OptionButton so exit the loop.
Exit For
End If
End If
Next
'Store input in the worksheet
Sheets("Answer Sheet").Range("E80").Value = OptionButtonValue
To ensure an option button is selected before proceeding to next form, i have
the 'following code (second code):
Dim cnt As Integer
For Each ctl In Me.Controls
If TypeName(ctl) = "OptionButton" Then
If ctl.Value = True Then cnt = cnt + 1
End If
Next ctl
If cnt = 0 Then MsgBox "Hello " & CStr(ThisWorkbook.Sheets("AccessReg").Range("D630").Value) & ", you
have not selected an answer! Please select an answer to proceed to next question. Thank you.",
vbInformation, "Please select an answer!" Else ScoreBoards.Show
Unload Me
MY CHALLENGES
Both codes above exists in my forms i.e. questions 1, 2, 3,...respectively, but can't seem to get the second code (that, which ensures an option button is selected before next form can be opened) to work by adding 'unload me' to the end of it, yet i want the form closed before proceeding to next. Adding 'unload me', pop-up the msgbox (which tells me to select an answer) but when i clicked okay on the msgbox, it closes the form (Question1) instead of returning me to same form to ensure an answer is clicked, then proceed to next form (Question2). However, when i remove the 'unload me', things work fine i.e. the msgbox popup when selection not made, returns to same form when okay on msgbox is clicked, and opens next form when selection made.
What i really want is: i want the second code above (which ensures an option button is selected before next form can be opened) to work as programmed and each form closed before proceeding to the next form.
Thank you in advance
PS:
The concept summary is:
On a userform (Question1), select an option button and submit the value to worksheet
Ensure an option button is selected:
if selected and button clicked, the next form(being Question2) should open
if not selected and button clicked, the msgbox (which tells me to select an answer), should popup
clicking okay on the msgbox, should return me to same form (Question1) so that i can select an option and proceed.
Try adapting your second code in the next way, please:
If cnt = 0 Then MsgBox "Hello " & _
CStr(ThisWorkbook.Sheets("AccessReg").Range("D630").Value) & ", you have not selected an answer! Please select an answer to proceed to next question. Thank you.", vbInformation, "Please select an answer!"
Exit For
Else
ScoreBoards.Show
Unload Me
End if

Is there a way to define a shortcut key (e.g. Ctrl-Y) to start a VBA sub/macro while the VBE window is active?

I'm trying to automate some development steps by using VBA code and want to start those macros with a shortcut key while the VBE window is active/on top. Is there a way to do this? The Macro dialog in VBE does not offer the Options button, which allows to define a shortcut key in Excel proper. I also have not found a way to solve my problem via the VBE toolbar customization.
The F5 key us the shortcut to run this. This can be viewed by hovering the pointer over the "continue" option in the toolbar so the dialog pop up displays.
You cannot define Keyboard shortcuts within the VBE.
As long as your Subroutine gets no parameter:
put the cursor inside the subroutine and press F5
put the cursor outside of any routine and press F5 - you will get a list of Subs that you can start
Enter the name of the sub in the immediate window (Ctrl+G) and press Enter
If your Subroutine expects some parameter (even if it is only optional), only the method with the immediate window works. But you can write a short wrapper routine that calls the subroutine you want to call.
Thanks for the replies on my question. I was aware of the options presented there. As it seems that no real shortcut capabilities are available in VBE, I finally used a custom menu to access the VBA code I want to start during VBE sessions. I now have access to all of them (distributed over several modules and partially with long, description like names) via one macro (I call DM = short for DeveloperMenu) I (still) need to start via the immediate window.
Code below. Of course the specific menu items are custom for my environment and need to be adapted.
Sub Dm(Optional dummy As Boolean)
Call CreateAndDisplayDevelopmentPopUpMenu
End Sub
Sub CreateAndDisplayDevelopmentPopUpMenu(Optional dummy As Boolean)
Dim menuName As String
menuName = "Development"
'Delete PopUp menu if it exist
On Error Resume Next
Application.CommandBars(menuName).Delete
On Error GoTo 0
'Create the PopUpmenu
Call DevelopmentPopUpMenu(menuName)
'Show the PopUp menu
On Error Resume Next
Application.CommandBars(menuName).ShowPopup
On Error GoTo 0
End Sub
Sub DevelopmentPopUpMenu(menuName As String)
Dim MenuItem As CommandBarPopup
'Add PopUp menu
With Application.CommandBars.Add(name:=menuName, position:=msoBarPopup, _
MenuBar:=False, Temporary:=True)
'First add buttons
With .Controls.Add(type:=msoControlButton)
.caption = "&RebuildDefs"
' .faceId = 71
.OnAction = "'" & ThisWorkbook.name & "'!" & "'RebuildAllDefs ""True""'"
End With
With .Controls.Add(type:=msoControlButton)
.caption = "&ToggleAddIn"
' .faceId = 71
.OnAction = "'" & ThisWorkbook.name & "'!" & "ToggleAddIn"
End With
'Second menues
Set MenuItem = .Controls.Add(type:=msoControlPopup)
With MenuItem
.caption = "&Watch"
With .Controls.Add(type:=msoControlButton)
.caption = "&Start watch"
' .faceId = 71
.OnAction = "'" & ThisWorkbook.name & "'!" & "startWatch"
End With
With .Controls.Add(type:=msoControlButton)
.caption = "&End watch"
' .faceId = 72
.OnAction = "'" & ThisWorkbook.name & "'!" & "DeleteAllwatches"
End With
End With
Set MenuItem = .Controls.Add(type:=msoControlPopup)
With MenuItem
.caption = "&HeartBeat"
With .Controls.Add(type:=msoControlButton)
.caption = "&Start HeartBeat"
' .faceId = 71
.OnAction = "'" & ThisWorkbook.name & "'!" & "heartBeat"
End With
With .Controls.Add(type:=msoControlButton)
.caption = "St&op HeartBeat"
' .faceId = 72
.OnAction = "'" & ThisWorkbook.name & "'!" & "stopHeartBeat"
End With
End With
End With
End Sub
TL;DR - You need to change the tools name and add an & in front of the letter you want to be the hotkey. The shortcut will now be Alt + <first letter following &>.
The above method is the only custom shortcut (a.k.a. Accelerator Key) method that is native to the VBE (if I'm not mistaken). I know this question is old, but it ranks much higher than the actual answer, so I thought I'd leave my results for the next person (which will probably be me again next year).
If you customize the VBE toolbar, you should be able to find a button labeled "Modify Selection" (you might need to click the "Rearrange Commands" button first from the Commands tab for a pop-up window with a working "Modify Selection" button if the button on the Commands tab is grayed out). On the drop-down context menu you'll see a textbox for the tool's name. This is the textbox where you add the & in front of the letter in the name that you want to use as the shortcut key. For effectively the same answer but slightly different procedure/implementation, see this answer: https://stackoverflow.com/a/23954017

"ActiveWindow.ScrollIntoView Selection.Range, True" does not work

I need VBA (Word) to scroll to a certain location in the document before a messagebox (msgbox) in the macro is displayed.
I have tried:
ActiveWindow.ScrollIntoView Selection.Range, True
I have added DoEvents before the Msgbox call. Didn't work.
I have added a bookmark and then selected the bookmark before the Msgbox
I have added a sleeptimer, and other delays, before the Msgbox. Didn't work.
I have tried Application.Screenrefresh
Nothing works. Msgbox always displays with the cursor in the location it was located before the macro ran.
HOWEVER, if I step through the code in the VBA editor, all works fine. It's only when I am running the code 'straight through' that it never observes the ScrollIntoView command before showing the msgbox.
(Start at top of document)
(Search for text on, let's say page 3; if found . . .)
ActiveWindow.ScrollIntoView Selection.Range, True
DoEvents
Application.ScreenRefresh
Selection.Bookmarks.Add "Prompt"
Selection.Bookmarks("Prompt").Select
DoEvents
Selection.Range.Select
MsgBox " TASK: " & PromptIs & String(2, 13) & " Click OK below and perform the stated task."
The cursor should be at the found text and the text should be 'in view' before the message box is displayed. It's not.

Applescript how to display a dialog with text and a variable

I need to display a applescript dialog with text and a number by which i mean the text that it displays would be text and a varible like this display dialog "Enter spelling" and repeatnum buttons{"done"} This is the code I have`isplay dialog "How many spellings are there" buttons {"That amount"} default answer ""
set amount to text returned of result
set repeatdone to 0
repeat amount times
repeatdone = repeatdone + 1
display dialog "enter spelling " and repeatdone buttons {"Ok"} default answer ""
end repeat
When I try this it gives me the error cannot make enter spelling into type boolean, Is there anyway to make a applescript dialog display text and a varible
Try:
display dialog "How many spellings are there" buttons {"That amount"} default answer ""
set amount to text returned of result
set repeatdone to 0
repeat amount times
set repeatdone to repeatdone + 1
display dialog "enter spelling " & repeatdone buttons {"Ok"} default answer ""
end repeat