We need the ability to enforce restriction of editing specific sections only in an MS Word Document - while allowing users to Accept Reject changes
We are currently using the aspose Words method document.protect() with ProtectionType as "ALLOW_ONLY_FORM_FIELDS", the document gets protected, and we are able to lock/restrict the sections for editing. Howevr, this also results in the Accept/Reject buttons for Tracking changes in "Review" tab of MS Word getting disabled - This restricts users from accepting/rejecting changes even in the section which allows editing. As per business functionality, we need these options (accept/reject) to enabled for our functionality.
Can anyone please suggest if there is any way to achieve the above? (To summarize: The need is to have the Accept/Reject button enabled while allowing editing only in specific sections/paragraphs in the document )
The Word application simply does not support this in a protected document. Protecting as a form locks out all the Reviewing capability; protecting for editing (wdAllowOnlyReading) lets the user move between changes, but doesn't allow accepting/rejecting.
The only way to make this possible is to include code attached to the Ribbon and/or a keyboard shortcut that checks whether the current selection contains a revision. If yes, the document is unprotected, the revision accepted (or rejected), then the document is reprotected. The following sample code illustrates the approach.
I can't tell you how or whether a Ribbon, keyboard shortcuts or VBA code can be included when working with Aspose. If Aspose can create a new document from an existing file (template, either dotm or docm) then these could be included there.
Sub AcceptRevisionInLockedDoc()
Dim doc As Word.Document
Dim rng As Word.Range
Set doc = ActiveDocument
Set rng = Selection.Range
If rng.Revisions.Count > 0 Then
If doc.ProtectionType = wdAllowOnlyFormFields Then 'wdAllowOnlyReading Then '
doc.Unprotect
rng.Revisions(1).Accept
doc.Protect wdAllowOnlyFormFields, True ' wdAllowOnlyReading
End If
End If
End Sub
Please note that Aspose.Words mimics the behavior of MS Word and MS Word application does not support it when document is protected.
I work with Aspose as Developer Evangelist.
Related
I've set up a word form with different sections, each section to be completed by a separate person.
Each section of the form includes a combination of dropdown lists or free text fields set up using named Content controls.
At the end of each section there is field for the staff member to record their name, the date (calendar icon), and a command button with an associated macro to save the form and protect the data once that section has been completed.
While this enables the data to be protected it does not prevent person A from completing the form and entering person B's name. Note, this would not be expected, but traceability is required for regulatory purposes.
I would like to update the macro to protect the sections, save the file (currently working), and then immediately after saving, have the macro populate another field directly under the manually entered name and date with the Microsoft advanced properties of Last Saved By and the date and time. This would confirm the user.
My macro below (InsertMSSavedDetails()) will extract the Microsoft required data, but only if I manually click on the form and run the macro, and then it saves wherever I click on the form and won't save to the named ContentControl box. I'd like to automate this last step so that it is not reliant upon the user and the data is associated with particular section.
My form includes the following code:
Module
Sub ProtectFieldsSections2()
' protects Sections 1 and 2
If MsgBox("Do you want to Lock and Protect this section from further editing?", vbYesNo) = vbNo
Then Exit Sub
Dim sec As Section
Dim cc As ContentControl
Set sec = ActiveDocument.Sections(2)
For Each cc In sec.Range.ContentControls
cc.LockContents = True
Next cc
End Sub
This document:
Private Sub CommandButton2_Click()
ProtectFieldsSection1
ProtectFieldsSection2
ActiveDocument.Save
End Sub
Current code for Adding Microsoft data - which technically works, but not in the manner I need:
Sub InsertMSSavedDetails()
'
ActiveDocument.SelectContentControlsByTitle ("MSSavedDetails")
Selection.TypeText Text:="Check data: "
Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:= _
"LASTSAVEDBY ", PreserveFormatting:=True
Selection.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:= _
"SAVEDATE \# ""d/MM/yyyy h:mm:ss am/pm"" ", PreserveFormatting:=True
End Sub
Second issue with the above, is that it would only need to be added the once, when Sub CommandButton2_Click is first selected. If I were to update the Sub CommandButton2_Click, how would I stop if from repeating the cycle of save, insert Microsoft data, save, insert Microsoft data?
NOTE: Use of word vs PDF form. Presently, the form is used in word format, converted to PDF, and electronically signed, however this does not allow others to add their information to the remaining sections. Adobe LiveCycler has been used to design PDF forms but there were issues with maintaining images and graphs, and there were other issues experienced with the Adobe reader, so the option is to remain with word.
Thank you.
Not sure I have completely understood the problems, but
The problem with inserting the field codes LASTSAVEDBY and SAVEDATE is that unless you "lock" them, their values will always reflect the most recent save. Also, if you want the fields to go in a content control, you have to use a rich text content control.
Perhaps better to
save the document
get the underlying property values (the ones that LASTSAVEDBY and SAVEDATE display) and insert them
save the document
If you have content controls named (say)
Section1LastSavedBy
Section1SaveDate
Section2LastSavedBy
etc.
then
you know which commandbutton the user clicked so you know which section you are dealing with
your code can then look something like
Private Sub CommandButton2_Click()
ProtectFieldsSection1
ProtectFieldsSection2
With ActiveDocument
.Save
.SelectContentControlsByTitle("Section1LastSavedBy")(1).Range.Text = _
.BuiltinDocumentProperties("Last Author").Value
.SelectContentControlsByTitle("Section1SaveDate")(1).Range.Text = _
format(.BuiltinDocumentProperties("Last Save Time").Value,"D/MM/YYYY h:mm:ss am/pm")
.Save
End With
End Sub
If you want to construct the content control names programmatically based on Section number, you can.
If you want to lock the content controls against further editing, you can.
I am not sure what problem you are encountering here:
"Second issue with the above, is that it would only need to be added the once, when Sub CommandButton2_Click is first selected. If I were to update the Sub CommandButton2_Click, how would I stop if from repeating the cycle of save, insert Microsoft data, save, insert Microsoft data?"
unless you are using a Save event. If that's the problem we could revisit that part.
It's pretty difficult to stop people tampering with data in Word, but personally I would consider saving copies of these values in, e.g., a Custom XML Part (not mapped to the controls) or Document Variables - possibly also encrypt them - you can use Windows crypto APIs for that.
Incidentally, I suspect the problem you have with your existing code is that .SelectContentControlsBYTitle doesn't Select the controls in the normal Word sense. It just returns a collection of controls with that name.
i`m working at a mental illness medical facility.
For our documents we are using Word templates which contains the header and footer as an linked image.
The advantage of this is if we have to change something in the header, we have to change one image and all documents are getting these changes.
Now we have the problem that this image changes even if Word is in read-only mode or has been released.
This also affects documents that are sent to patients or doctors and then a copy is printed for the patient record. If the image changes at this point in time, the documents are different and document authenticity is no longer guaranteed.
Is it somehow possible to prevent Word from updating the image when it is in read-only mode?
EDIT:
Setting "Update links on Open" (File->Options->Advanced->General) is turned off
File>Options>Advanced and scroll down to the General section and uncheck the box for "Update automatic links at open."
Hope this helps...
Or You Can Try The Macro:
Sub AutoOpen()
With Options
.UpdateFieldsAtPrint = false
.UpdateLinksAtPrint = false
End With
ActiveDocument.Fields.Update
End Sub
I want to setup a word document which has several chapters. For a particular set of readers (eg my boss), I want to only print to pdf chap 1-5 and for another set of readers (eg my customers), I want to print to pdf out chap 6-10.
Is this possible with MS-word?
edit: elaboration.
First you will need a way to get who is the user and determine to which part of the document he has access (you can use the WNetGetUser API in the microsoft Mpr.dll), then you can show and hide the different sections of the document. For the second part the easiest way is to create bookmarks for the different chapters of your document and hide/show them using:
ActiveDocument.Bookmarks("bookmark01").Range.Font.Hidden = True 'to hide text
ActiveDocument.Bookmarks("bookmark01").Range.Font.Hidden = False 'to show text
I'm probably biting off more than I can chew with this particular problem, but I'll try to be as specific as possible in case it's within my scope. Disclaimer: I'm not terribly experienced with MS Word, beyond simple data entry/some formatting, and I have absolutely zero experience working with macros or VBasic. Unfortunately, I'm afraid the solution to my problem will come in the form of one of those last two.
THE GOAL:
What I want to do is to have placeholder text throughout my template document that will change content but not formatting when the first instance of it is changed. Basically, I'm writing a template for support manuals for a software suite. Each app has certain similar features like the menu bar, data entry screen, diagnostic log screen, transaction history, etc., so I am pre-writing those sections and using placeholders when I need to insert certain app specific properties.
I started off using the Insert->Quick Parts->Document Property->Subject tool which I used as a placeholder for the app name. I set the Property to [Subject] and then used Insert->Quick Parts->Field->Subject throughout the document, wherever I needed to include the app name. This worked fine in this case because the app name will always be capitalized. I simply change the text in the first [Subject] (which is content controlled) and update the fields throughout the document, and they all match nicely, easy-peasy, work done, go home and drink beer, right?
Not quite.
Our software handles part tracking via scanners and SQL Server, so while the interface and menu in the apps remains largely unchanged, the parts they track change from app to app. Because of this, I need to change the part name when I reference it within the text of the manuals; for example, if I'm working in ToiletPap.app and our TP is tracked by the roll, I need every mention of [Component] to be changed to roll. If I'm working in LightBulbs.app, I need [Component] to say bulb.
My first efforts went toward creating a custom doc property called Component using the Advanced tab under the Document Properties dropmenu. I then created a plaintext content control around my first [Component] titled Component and made my next [Component] a field with modified code: {COMPONENT * MERGEFORMAT}. This comes from copying what I can find when [Subject] works. This didn't work at all; updating the text in the first CC doesn't change the Content doc prop, and my fields return "!Undefined Bookmark, COMPONENT".
I got close to what I need by using the [Comments] doc property, set initially to [Component]. I used it just like [Subject], but (this is when I realized that capitalization was going to be an issue) when I mention my [component] in-text, as often as not, I need to to be lowercase instead of upper.
I've looked on MS's forums and a few others as well as here on SO, and I can't find anyone who's trying to do the same thing, much less an answer to how. Please keep in mind when answering, it would be a great help to me if you would include step-by-step instructions on how to enter/implement the code you provide because, as I mentioned, I have no idea how to go about editing macros/VBasic for MS Word.
To restate and summarize my overall question: How can I use a placeholder that displays the text "[Component]" so that, when I change the first instance of [Component] to something else, say "hopper", every subsequent instance of [Component] is updated to hopper but maintains its current capitalization and formatting scheme?
Apologies for the length of the request, but I wanted to make sure I explained the situation as accurately as possible. Thanks in advance for your consideration and responses.
I managed to solve this one after a couple extra hours of tinkering. I didn't need macros or VBasic, either.
On the first instance of [component] I created a plain-text content control to act as a container (not a necessity, but it makes it look nicer. Will likely cause a problem eventually, but for now, it's working as intended) and bookmarked it. Then, for all other instances of [container] I selected each and used Insert->Quick Parts->Field->Ref with the following field code:
REF Text1 \*Lower
Where "Text1" is my bookmark and "*Lower" indicates all lower case. The *Lower can be replaced with *Upper or *FirstCap to indicate all upper case or capitalize the first letter respectively. Now, each field reflects the text of the first with the capitalization appropriate to each field's location within the document. Just like using the doc prop with [Subject], ^a -> f9 is needed to update all fields within the document.
How to detect changes in particular section of a word document. There could be many changes in other part of the document which should be ignored. I need to see if the doc is changed in the particular section only. Is there any way of finding this out?
The object WordApplication has the property MODIFIED, so, you can to use:
if xxxx.Modified then showmessage( 'doc edited' )