is it possible to put a password on a single word inside a word document?
What I want is to write a system documentation from our IT structure. I want to put the passwords in the document as well. Now I want that you have to enter a "MASTER" password in order to unlock to passwords inside the document. If you do not enter the password, the passwords inside the document should be invisible or something like that.
Is that possible?
Yes, this is possible. To make this work we have to use a combination of Word's inherent document protection, its hidden text attribute, and a couple of VBA tricks.
First, format all the passwords in the document as hidden text. (For those who are unfamiliar, hidden text is only visible when the Show/Hide function is set to true.)
Then add code to make sure that the hidden text will not display and also to protect the document from being edited whenever the document is opened:
Private Sub Document_Open()
AddProtection
End Sub
Sub AddProtection()
With ActiveDocument
.ActiveWindow.View.ShowAll = False
.ActiveWindow.View.ShowHiddenText = False
.Application.Options.PrintHiddenText = False
.Protect Type:=wdAllowOnlyReading, NoReset:=True, Password:="DesiredPassword"
End With
End Sub
Because Word users can normally display hidden text at any given time, we also need to take control of this function. Most menu and Ribbon commands can be intercepted by creating a module containing subroutines named for the intercepted commands. Naming a Sub ShowAll will allow us to control this function and only display hidden text when a password is entered:
Sub ShowAll()
If ActiveDocument.ProtectionType = wdAllowOnlyReading Then
'Do nothing
Else 'restore the Ribbon's toggle function
If ActiveDocument.ActiveWindow.View.ShowAll = True Then
ActiveDocument.ActiveWindow.View.ShowAll = False
Else
ActiveDocument.ActiveWindow.View.ShowAll = True
End If
End If
End Sub
Finally, we add some code to prompt the user for a password and, if entered correctly, display the text that was formerly hidden:
Sub RemoveProtection()
Dim strPassword As String
strPassword = InputBox("Enter document password.")
ActiveDocument.Unprotect Password:=strPassword
If ActiveDocument.ProtectionType = wdNoProtection Then
ActiveDocument.ActiveWindow.View.ShowHiddenText = True
End If
End Sub
Once all the VBA code is entered, right-click on the module in the IDE, select Project Properties, and assign a separate password on the Protection tab. This will stop power users from getting to the embedded password or changing the code.
All that's left to do is create a QAT button in Word (that is only visible for this document) and assign the RemoveProtection sub to it. Whenever the document is opened the passwords will be hidden and protected from editing, but can then be revealed by clicking on the QAT button and entering the correct password.
EDIT
When I first answered this question, I failed to consider that Word has a hidden text option that can be turned on separateley from the Show All option. Additionally, hidden text can be printed via a printing option. I have added code in AddProtection above to turn off these settings.
Further testing also revealed that a user in Word 2007 could manually go into Office Orb|Options|Display to reveal the hidden text by changing the Show all formatting marks or Hidden text options manually. To avoid this, a Ribbon customization would need to be created and loaded with the document.
Finally, it is worth noting that although it is great fun to bend Word to one's will in order to make it accomplish tasks like this, the level of protection is not as good as encrypting the passwords separately and then unecrypting before revealing the contents or even using Word's document password feature to encrypt the document's entire contents.
Related
I have a Word document that has fields where information is populated by the user manually. There are couple of other documents with same fields and the user would like to populate those automatically, based on information in first document. How to achieve that? Documents are in .doc format.
I've tried looking around before coming here, but every site I've managed to find (that has title of "Filling fill-in forms in Word" and similar) actually describes how to prepare a document for such action, not how to insert the data in from other document. I'm maybe missing something very obvious, but can't figure it out.
All documents have "Allow only this type of editing in the document:" ticket and "Filling in forms" selected under "2. Editing restrictions" in Restrict Editing menu.
This is a borderline question, as it technically falls in the end-user area. But it could also be an interesting question for developers as there is no direct way to achieve what is required using the object model, except by following the steps below (i.e. inserting IncludeText fields).
In the source document, it's necessary to use content controls for text input (form field dropdowns work fine) and bookmark them. The content of a legacy form field textbox will not come through.
In Word, in the target document, go to Insert->Object->Text from file
in the dialog box click the Range button, type in the bookmark name
select the option to "Insert as Link"
This creates an IncludeText field in the document that references the file path to the source document and the bookmark content:
{ INCLUDETEXT "C:\\Test\\TestFormsProtection.docx" Text1 }
Note that there is no reliable (sometimes it might work, but other times not) way to use relative file paths with Word field codes.
The relevant VBA code to generate this field at the end of the active document:
Dim doc as Word.Document
Dim rng as Word.Range
Set doc = ActiveDocument
Set rng = rng.Content
rng.Collapse wdCollapseEnd
doc.Fields.Add rng, , "IncludeText " & Chr(34) & "C:\\Test\\TestFormsProtection.docx" & Chr(34) _
& " Text2", false
I have an SSRS report that has Spanish and English text boxes. If the dataset row is a Spanish speaking person, an expression in each Spanish textbox shows that and hides the English textbox. These textboxes are exactly placed over each other.
My boss wants me to use SSRS to generate an Excel spreadsheet from the dataset(this is not hard) and use Word template for a mail merge. However, I am having trouble trying to figure out if I can hide all English when row is a Spanish row and vice versa. These are health clients of Spanish and English nationality.
I can do mail merges attached to a Recordset, I can do one in English, one in Spanish. I am trying to avoid this and have it all in one Mail Merge.
Areas marked in red will change to Spanish translation and/or date format. The dates are a no-brainer I can use a conditional IIF, however the formatted body I have no solution for, based on value in Field "CL_Language" which is either "Spanish" or "English".
====================================
The merge fields for dates and greeting are easy. There is no merge field for the text. And yes, only option might be for 2 separate reports with different Recordsets.
It's not clear what the actual issue is but...
Instead of hiding textboxes, which could cause problems when exporting etc., why not set a single textbox to the correct language text using an expression?
Something along the lines of
=IIF(Fields!Language.Value = "English", Fields!MyEnglishText.Value, FieldsMySpanishText.Value)
I found a solution. But it could be very difficult for the client to create. It involves hitting Ctrl + F9 which will create curly brackets {}.
Inside those curly brackets an IF statement is placed and I just pasted the whole Spanish formatted body in the true area, and the whole English body in the false area.
{IF "CL_Language" = "Spanish" "spanish body text here" "english body text here"}
Very strange syntax and you need to right click on the area to see choices like "Toggle Field Codes" (IF statement get's hidden), "Edit Field", and "Update Field". With Edit Field and Update Field you get a popup with the fields in your recordset.
If you saw the examples in my question, you can see that is some big clunky text AND . . .inside of it is a merge field that works! The Excel recordset comes already with the month name in correct language for each row.
Since it is not smart to include links that might expire, I am including the Google text I used to find this solution. Then I took a chance on a huge formatted chunk of text with a merge field inside of it.
Google this: "If Merge Field then"
Now is this a viable solution for the client versus just having a Word template for each language?
I think this is too difficult and I even duck when running it. Also, once it's working, if I look at the toggled code, the Conditional field no longer says the field name, but the value in the field, go figure.
{IF "Spanish" = "Spanish" or {IF "English" = "Spanish" instead of {IF "CL_Language" = "Spanish" or {IF "CL_Language" = "English"
Here is how to access the fields using right click. (remember, your curly brackets HAVE to be created with Control + F9).
I am developing an OpenOffice Writer template that can be used to fill in reports for a child-care centre.
There are some standard outcomes, comprising long sentences, and I want the user to be able to select the appropriate sentence from a combo box. I have entered the sentences into a table in Openoffice Base database, which is then connected to a series of combo boxes in a Writer template. However, when the user choose an option that contains a very long sentence, only the text up to the length of the combo box is visible.
What I want to do is have the selected value of the combo-box wrap over several lines when selected so that all the (very long) text appears in the selected box when the user chooses a long sentence from the combo.
I have been looking through the properties of the combo box control, but have yet to identify one that will allow the selected value in the combo box to word-wrap (so that I could make the combo-box several lines in height such that the entire sentence would fit into the box).
Any pointers on how I could do this would be much appreciated.
thanks,
David.
Thanks Jim K, that was helpful. In the end, what I wound up doing was creating a textbox which I named "selectedOutcomeATextBox" immediately below my combo box which was named "OutcomeCombo".
I then attached the following macro code to the textModified event associated with the "selectedOutcomeATextBox":
Sub UpdateOutcomeA
Dim Doc As Object
Dim Form As Object
Dim Ctl As Object
Dim newCtl as Object
Doc = ThisComponent
Form = Doc.DrawPage.Forms.GetByIndex(0)
Ctl = Form.getByName("OutcomeCombo")
newCtl = Form.getByName("selectedOutcomeATextBox")
newCtl.Text = Ctl.Text
End Sub
I also set the "Printable" property of the "OutcomeCombo" to "No", so that when the document prints, the combo box itself does not appear on the printed page, but the "selectedOutcomeATextBox" textbox which has had its value set by the macro when I choose a value from the combo box does appear with the desired text. I also set the "TextType" property of the selectedOutcomeATextBox" text box to "Multi-Line", so that extra long text will wrap to the next line, thereby showing the very long strings that are stored there.
Thanks heaps Jim K.
cheers,
David Buddrige
Apparently combo boxes do not have the MultiLine attribute. The question was asked a few years ago here but was not solved.
One alternative that requires some macro programming is to use a single multi-line text field and then make a scroll bar button that changes the choice. Instead of a scroll bar, two buttons could be used to change the choice (Previous / Next), or even a list box control. Using a list box control in this way would have the advantage that they could see all the choices at once, like a combo box.
Another approach is to break up each sentence and display the parts across several lines of a list box. Then when one line is clicked, all the lines of a sentence are selected at once, using an event listener for the list box. This could be shown in addition to an ordinary editable multi-line text box, in case none of the answers in the list are wanted.
One more idea: Radio buttons can have multiple lines, so dynamically show radio buttons, one for each sentence. A dialog window could be displayed to hold the radio buttons. The result of the dialog would be used to fill the multi-line text field.
Or you could just live with the truncated sentences. Maybe it would help to make the control a little wider, or abbreviate the sentences.
First let me start by saying that I have no idea what I'm doing. Well, some idea, but mostly I'm just winging it. I've been working on an Excel macro to run a Word mail merge from Excel for a couple of weeks and I've pieced together different codes to encompass everything I need it to do. My problem is that it works the first time but it gets stuck each subsequent time if I do not reset the macro.
The sheet I made is designed so the macro can pull all of the information it needs from the sheet (code contains no hard coded locations). This is because a folder containing the Excel form, the letter templates and the finished letters will be sent to multiple users and will therefore be saved in a different location on each user's computer. The user enters details into the Excel form which will ultimately create a formatted disciplinary letter in a Word document to send out to the player being reviewed. There may need to be multiple infractions included in the letter so the Excel form provides that option, whereas a Word form would have a bunch of unnecessary empty fields. (I initially tried setting up the letter in Word as a form but I couldn't get all of the factors that I needed to work together) A Word form also doesn't have the ability to hide fields and can't support the dependent drop down lists or the amount of text in each drop down that I require. Anyway...
The process:
User opens the Excel file and enters information into a nicely laid out, user friendly form which contains dependent drop down lists, etc as well as buttons that hide and show fields (in case the user needs to include multiple infractions being reviewed).
When the user is finished entering their information, they click a command button to run the mail merge ("Create Disciplinary Letter").
The information they select in the form is linked to another worksheet (same workbook) called "Data Sheet" that contains the columns that the merge will pull from.
The workbook also contains a "Control Sheet" worksheet which provides the location of the files and folders that the macro is to pull from.
The macro should:
Open Word merge template (it chooses the correct template based on a choice that the user makes in the form)
Run the merge
Send merged product to a new document
Close the original merge template without saving changes
Save the new document with a specific file name (based on choices the user made in the original Excel form)
Save it to a "Final Documents" folder which is located in the original folder that I send out to the user(s).
The newly saved document/letter stays open for further editing (if necessary)
New doc contains a button that will save the finished letter as a .pdf (also to a specific location) but that macro is in Word so it is not part of my problem.
The Excel form would likely be closed and reopened before a user needs to use it again, and in that case, the macro would run fine. There is a good possibility though, that the user will see the finished letter in Word, realize that they forgot the include an infraction, go back to the open Excel form to add the infraction, and click the macro button again. If this happens, the macro will get stuck at macro process #4 onward (from list above). I don't know what is in the code (or missing) that is causing this but I've been fighting with it for days and I can't find anything out there that I can apply to my issue. Or maybe I have, but I'm unaware because I'm seriously just winging it.
Sub RunMerge()
Dim bCreatedWordInstance As Boolean
Dim wdapp As Word.Application
Dim wddoc As Word.Document
Dim rng1 As Range
Dim wb As Workbook
Dim wsControl As Worksheet
Dim wsData As Worksheet
Dim strWorkbookName As String
Dim strTemplateFolder As String
Dim strTemplateName As String
Dim lngTemplateNameColumn As Long
Dim strFinalDocumentFolder As String
Dim strFinalDocumentName As String
Dim lngDocumentNameColumn As Long
Dim lngRecordKount As Long ' not used but retained for future use
Set wb = ThisWorkbook
Set wsControl = wb.Worksheets("Control Sheet")
wsControl.Activate
strTemplateFolder = wsControl.[Template_Folder].Value
strFinalDocumentFolder = wsControl.[Document_Folder].Value
Set wsData = wb.Worksheets(wsControl.[Data_Sheet].Value)
wsData.Activate
lngTemplateNameColumn = wsData.[Template_Name].Column
lngDocumentNameColumn = wsData.[Document_Name].Column
Set rng1 = wsData.Range("B1:B8")
strTemplateName = strTemplateFolder & "\" & wsData.Cells(2, lngTemplateNameColumn) & ".doc"
strFinalDocumentName = strFinalDocumentFolder & "\" & wsData.Cells(2, lngDocumentNameColumn)
strWorkbookName = ThisWorkbook.Path & "\" & ThisWorkbook.Name\
On Error Resume Next
' Create a Word Application instance
bCreatedWordInstance = False
Set wdapp = GetObject(, "Word.application")
If wdapp Is Nothing Then
Err.Clear
Set wdapp = CreateObject("Word.Application")
bCreatedWordInstance = True
End If
If wdapp Is Nothing Then
MsgBox "Could not start Word"
Err.Clear
On Error GoTo 0
Exit Sub
End If
' Let Word trap the errors
On Error GoTo 0
' Set to True if you want to see the Word Doc flash past during construction
wdapp.Visible = True
' check that template exists
If Dir(strTemplateName) = "" Then
MsgBox strTemplateName & " not found"
End If
Set wddoc = wdapp.Documents.Open(strTemplateName)
If wddoc Is Nothing Then Set wddoc = wdapp.Documents.Open(strTemplateName)
wddoc.Activate
With wddoc
.MailMerge.OpenDataSource Name:=strWorkbookName, SQLStatement:="SELECT * FROM `Data Sheet$`"
With wddoc.MailMerge 'With ActiveDocument.MailMerge
.Destination = wdSendToNewDocument
.SuppressBlankLines = True
.Execute Pause:=False
End With
End With
' Save new file
ActiveDocument.SaveAs strFinalDocumentName
' Close the New Mail Merged Document
If bCreatedWordInstance Then
wddoc.Close savechanges:=wdDoNotSaveChanges
Set wddoc = Nothing
End If
0:
Set wdapp = Nothing
Set rng1 = Nothing
Set wsData = Nothing
Set wsControl = Nothing
Set wb = Nothing
End Sub
It gets stuck the second time around on:
' Save new file
ActiveDocument.SaveAs strFinalDocumentName
I have an mdb file made by ms access. It got a form inside and inside the form there are one large textbox.
The intention of making this textbox is to show the progress of some work by adding messages inside the textbox:
txtStatus.value = txtStatus.value & "Doing something..." & vbCrLf
txtStatus.value = txtStatus.value & "Done." & vbCrLf
But the problem is, when the height of the text > height of the textbox, the new message is not displayed automatically. The textbox has a scroll bar, but I have to scroll it manually. I would like to auto scroll to the bottom whenever new text pop up.
I tried to add this code(copied from internet) in the On Change property, but the code failed, it does nothing:
Private Sub txtStatus_Change()
txtStatus.SelStart = Len(txt) - 1
End Sub
I wish there would be some simple and beautiful way to achieve this. I don't want to add some code which only work on some computers due to its dependence on the windows platform's kernel/etc.
You can do it via a call to a sub;
AppendText "Bla de bla bla."
.
.
sub AppendText(strText As String)
with txtStatus
.setfocus '//required
.value = .value & strText & vbNewLine
.selstart = len(.Value)
end with
end sub
There is a workaround to the design flaw mentioned by steve lewy in his comment on the original post. It is possible to have a text box that appears to do both of the following:
When the contents are too large for the box, and the box does not
have the focus, the box displays the last part of its contents,
rather than the first part of it.
When the box has the focus, it can scroll to any part of the text,
but it initially shows only the last part of the text, with the
cursor at the end of the text.
This is accomplished by actually having two identically-sized, overlaid text boxes, where one is visible only when the focus is elsewhere, while the other is visible only when it has the focus.
Here’s an example of how to do it in Access 2010.
Create a new Access database, and create a memo field named LongNote in its only table. Fill LongNote with some examples of long text. Create a form for editing that table.
Create a text box called BackBox with the desired size and font, too small to completely show a typical value of its data source, LongNote. (Instead of creating this box, you can rename the default text box created on the form.)
Make an exact copy of that box called FrontBox. Set the data source of FrontBox to be either the entire contents of BackBox or the last part of the contents, as shown below. The size of the last part, measured in characters, depends on the size of the box and its font, as well as on the kind of text to be displayed. It needs to be chosen by trial and error to reliably allow that many characters to be displayed in the box. For instance, here’s the formula for a box that can reasonably hold only 250 characters:
=iif(Len([BackBox])>=250,"... " & Right([BackBox],246),[BackBox])
If the whole value is too large to be shown, three dots precede the part that is shown to indicate that it’s incomplete.
Create another text box called OtherBox, just to have somewhere you can click besides the two boxes already mentioned, so neither of them has the focus. Also create a tiny (0.0097 x 0.0097) text box called FocusTrap, which is used to avoid selecting the entire contents of whatever text box gets the focus when the form is displayed (because text selected that way is hard to read).
Enter the following event-handling VBA code:
' Prevent all text boxes from being focused when a new record becomes
' current, because the focus will select the whole text and make it ugly
Private Sub Form_Current()
FocusTrap.SetFocus
End Sub
Private Sub Form_Open(Cancel As Integer)
FocusTrap.SetFocus
End Sub
' When FrontBox receives focus, switch the focus to BackBox,
' which can display the entire text
Private Sub FrontBox_GotFocus()
BackBox.SetFocus
FrontBox.Visible = False
End Sub
' When BackBox receives the focus, set the selection to
' the end of the text
Private Sub BackBox_GotFocus()
BackBox.SelStart = Len([LongNote])
BackBox.SelLength = 0
End Sub
' When BackBox loses focus, re-display FrontBox – if the text in
' BackBox has changed, then FrontBox will follow the change
Private Sub BackBox_LostFocus()
FrontBox.Visible = True
End Sub
Test the form. When you click on FrontBox, it should disappear, letting you work on BackBox. When you click in OtherBox to remove the focus from BackBox, FrontBox should reappear. Any edits made in BackBox should be reflected in FrontBox.
Back in design mode, move FrontBox so it exactly covers BackBox, and click Position | Bring to Front to ensure that it covers BackBox. Now test the form again. It should appear that a single text box switches between display-the-last-few-lines mode and edit-the-entire-contents mode.
Simply put the following code after linefeed or on Change event txtStatus
txtStatus.SelStart = Len(txtStatus) - 1