Using VBA in Word 2013.
In the Word object model, Document.Revisions gives you a collection of revision objects (tracked changes), and you can accept or reject them programmatically. Plus, the collection itself has a Count property.
I did not find any feature in the object model that exposes the Undo/Redo count or history. To clarify, I am looking for a way to determine how many user changes are in the Undo stack and the Redo stack at a given time (because I am not editing the document contents via macro). It would be a bonus to be able to see the individual changes that are available to undo or redo, but I'm okay without that.
I know I can use the Document.Undo and Document.Redo methods, but I don't see a way to get a count of changes that can be undone or a count of undone changes that can be redone.
I suppose I could just iterate through the stack, so to speak, by invoking Document.Undo or .Redo and checking the return value to see whether there was anything there, then reversing what I had just undone/redone. I was hoping for something akin to Document.Revisions.Count.
EDIT: I need to access the Redo stack. It begins to look as though the object model does not expose that object. An old (2013) question recorded here suggests that there is no such object/collection (search for "redorecord").
Any ideas?
Thanks!
You could create & deploy a custom UndoRecord, so you can roll back all your actions in one go at the end, via code like 'ActiveDocument.Undo', without the need to keep track of all the intervening edits. See: https://learn.microsoft.com/en-us/office/vba/word/Concepts/Working-with-Word/working-with-the-undorecord-object
To deploy this for end-user actions in the document itself, simply use:
Option Explicit
Dim objUndo As UndoRecord
Sub CreateUndoRecord()
Set objUndo = Application.UndoRecord
objUndo.StartCustomRecord
End Sub
to create the Custom Record then, when you're finished, clear the lot with:
Sub ClearUndoRecord()
objUndo.EndCustomRecord
ActiveDocument.Undo
End Sub
Related
I have a macro to process my inbox which has 7000 emails (I know, I know) and it takes a while. Naturally, I made a user form to show the progress by settling a label with remaining email count.
During execution however, I noticed that the form would stop updating at random time, probably as outlook goes into non responsive due to the macro execution.
Yesterday I accidentally dragged the now not-updating form aside which revealed another instance of the form beneath it, and that one is being updated correctly!
What is the mechanism behind this? My macro only created one instance of the form.
Edits:
The code is to delete emails with the same subject as the selected email. It was like the following. I added the commented out lines (pb.hide and pb.show) which somewhat solved the problem, although the flicker from hide/show is visually noticeable.
j = myitems.Count \ 20
l = 0
For i = myitems.Count To 1 Step -1
If l < j Then
l = l + 1
Else
l = 0
'pb.Hide
pb.Caption = "Emails to be processed: " & i
'pb.Show
End If
If TypeOf myitems(i) Is Outlook.MailItem Then
If myitems(i).ConversationID = selectedConversationID Then
myitems(i).Move deletedItemsFolder
ElseIf myitems(i).subject = selectedSubject Then
myitems(i).Move deletedItemsFolder
End If
End If
Next i
I have since switched to the Restrict method to get emails with same subject (as well as the GetConversation mehod) which takes seconds so the form is useless now. But they are not foolproof. There are times the selected email itself is not returned. Anyway, no biggie.
VBA is a single-threaded environment not designed for running secondary threads. If you consider creating a COM add-in you could use a low-level code such as Extended MAPI (or any other third-party wrappers around that api such as Redemption) which allows running secondary threads and deal with a store. So, you could move your loop on a secondary thread releasing the UI one (the main thread). Also it makes sense to consider using proper OOM methods and properties that can help to speed up the process of searching for specific items in Outlook. For example, you may consider using the Find/FindNext or Restrict methods of the Items class. They allow getting only items that correspond to the search criteria. Read more about these methods in the following articles:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder`
The AdvancedSearch method of the Application class can be helpful as well. The key benefits of using the AdvancedSearch method in Outlook are:
The search is performed in another thread. You don’t need to run another thread manually since the AdvancedSearch method runs it automatically in the background.
Possibility to search for any item types: mail, appointment, calendar, notes etc. in any location, i.e. beyond the scope of a certain folder. The Restrict and Find/FindNext methods can be applied to a particular Items collection (see the Items property of the Folder class in Outlook).
Full support for DASL queries (custom properties can be used for searching too). To improve the search performance, Instant Search keywords can be used if Instant Search is enabled for the store (see the IsInstantSearchEnabled property of the Store class).
You can stop the search process at any moment using the Stop method of the Search class.
This is about an API handling the validation during saving an object. Which means that the front-end client sends a request to the API to a specific end point, then on the back-end the API creates a new object if the right conditions are meet.
Right now the regular method that we use is that the models has a ruleset for each fields and then the validation is invoked when the save function is invoked, but technically the validation is done right before the object is saved into the database.
Then during today's code review I came across a solution which I wasn't sure if it's a good practice or not. And it was about that the front-end must send a specific parameter to the API every time. This is because other APIs are using our API as well, and we needed to know if the request was sent as and API request or a browser request. If this parameter is present then we want to execute an extra validation function on a specific field.
(1)If I would have to implement it, then I would check the incoming parameter in the service handler or in the controller level, and if I got one, I would invoke the validation right away, and if it fails I would throw an error.
(2)The implementation I saw however adds an extra variable to the model, and sets the model variable when there is an incoming parameter, then validates only when the save function is invoked on the object(which first validates the ruleset defined on the object fields, then saves the object into the database)
So my problem with (2) is that the object now grown bigger with an extra variable that is only related to a specific event. So I would say it's better to implement (1). But (2) also has an advantage, and that is when you create the object on different end point by parsing the parameters, then the validation will work there as well, even if the developer forget to update the code there.
Now this may seems like a silly question because, why would I care about just 1 extra variable, but this is like a bedrock of something good or bad. So if I say this is ok, then from now on the models will start growing with extra variables that are only related to specific events, which I think should be handled on the controller/service handler level. On the other hand the code would be more reliable if it's not the developer who should remember all the 6712537 functionalities and keep them in mind when makes some changes somewhere. Let's say all the devs will get heart attack tomorrow from the excitement of an amazing discovery, and a new developer has to work on the project while he doesn't know about these small details, and then he has to change something on the code that is related to this functionality - so that new feature should be supported by this old one as well.
So my question is if is there any good practice on this, and what do you think what would be the best approach?
So I spent some time on thinking on the solution, and I think the best is to have an array of acceptable trigger variables in the model class. Then when the parameters are passed to the model on the controller level, then the loader function can be modified that it takes the trigger variables from the parameters and save it in the model's associative array variable that stores the trigger variables.
By default this array is empty, and it doesn't matter how much new variables are needed to be created, it will only contain the necessary ones when those are used.
Then of course the loader function needs to be modified in a way that it can filter out the non trigger variables as well as it is done for the regular fields, and there can be even a rule set of validation on the trigger variables if necessary.
So this solves the problem with overgrowing the object with unnecessary variables and the centralized validation part, because now the validation can be always done in the model instead of the controller.
And since the loader function is modified to store the trigger variables in the model's trigger variables array variable, the developer never has to remember that this functionality was created. Which is good, because in the future when he creates a new related function or end point that should handle object creation, he will not miss it to validate it against the old functionality, because the the loader function that he modified in the past like this will handle it for him.
It needs to be noted tho, that since the loader function doesn't differentiate between the parameters, and where to load them other then checking the names of the parameters with the filter functions, these parameter names should be identical from each other, otherwise a buggy functionality can be created accidentally. Like if you forget that a model attribute with the same name was used, then you can accidentally trigger an event that was programmed to be triggered if the trigger variable with the same name is present. However this can be solved by prefixing the trigger variables for example.
I need to do certain processing when a Scintilla editor first becomes 'dirty' before the document actually changes.
The SCN_SAVEPOINTLEFT notification seems like the obvious candidate, but unfortunately this is fired after the change that made the document dirty has occurred.
Looking through the other available notifications, SCN_MODIFIED also is fired after the change has happened (and the same is true of SCEN_CHANGE of course).
The best I can think of is to start macro recording in response to SCN_SAVEPOINTREACHED (i.e. when the document is saved or all changes are undone). Then when I detect the first change with SCN_MODIFIED, I stop recording, undo all changes until I get back to the save point, perform my custom processing (which happens to be modifying a date field in the document), then replay the recorded macros to restore the undone changes.
This seems horribly convoluted. Is there an easier way? (Maybe it would be simpler to create my own custom version of Scintilla with a SCN_BEFORECHANGE notification, but I'd prefer to avoid creating a fork. And a cursory glance through the source suggests that there are a great many points from where this notification would have to be sent, making it easy to miss some.)
Update: The real requirement was that when the user executes 'Undo' after first modifying the document, the 'automatic' edit and the user's first edit are not in the wrong order in the undo buffer. The simplest solution turned out to be, not to force the automatic update to be first, but to coalesce these two actions into a single undo action using SCI_BEGINUNDOACTION/SCI_ENDUNDOACTION. See my comment below on how I did this.
The SCN_MODIFIED notification does seem to fit your spec. The modificationType field provides information about what has been done, including:
SC_MOD_BEFOREINSERT 0x400 Text is about to be inserted into the document.
SC_MOD_BEFOREDELETE 0x800 Text is about to be deleted from the document.
I am trying to build an object to represent a ridiculously large form for a project I am working on. http://www.flickr.com/photos/namtax/5351091239/
I didnt want to build all the fields into one large object as I didnt think this was a good way to do things, so I have structured the model as so -
One contact object.
One work object - linked to the contact one to one.
One travel object - linked to the contact one to one.
One address object - linked to the contact one to many.
One emergency contact object - linked to the contact one to many.
Here is the sample code for one of these relationships - written in CF9 ORM
property name="work"
fieldtype="one-to-one"
cfc="work"
mappedby="contact";
The issue here is that it causes the saveContact function in my controller to be large and code smelly due to all the possible options you can choose in the form. Here is a rough translation of the code
VARIABLES.contact = contactService.getContact(form.iContactId);
contactService.set(contact:contact,argumentCollection:form);
contact = contactService.save(contact);
if(_emergencyContactService.userIsSubmittingAnEmergencyContact(form)){
VARIABLES.emergencyContact = _emergencyContactService.getEmergencyContact(contact);
emergencyContactService.setEmergencyContact(emergencyContact,form);
if(! contact.hasEmergencyContact()){
contact.setEmergencyContact(emergencyContact);
emergencyContact.addarrContacts(contact);
}
_emergencyContactService.save(emergencyContact);
}
// Repeat this logic to check if work object, travel object or address object have been selected in the form also, get and set accordingly.
I then repeat the if statement shown above for emergency contact, to check whether the work object, travel object or address object have been selected in the form also. If so, get and set the object, then link the contact object where necessary.
This doesnt seem efficient to me, especially as I need to repeat all this logic on another controller method as well. Is there a better way to structure my objects, or a better way to handle my controller code?
Thanks.
My initial thoughts are to move any repeating logic from your controller to a service object that you can call from many places.
Bringing that along: you could break up the form into sub-forms - each represented by a 'sub-form' object. Each of these objects should be able to deal with information related to it's part of the form, and it should know what to save to the database. You could compose these form objects into a service object that you call from your controller.
One other thing I noticed is the way you actually pass your entire FORM scope into some functions. I tend to avoid this as you really are not describing what the function needs to do the job, and of course this scope can change when you don't expect it. I would suggest you specify the arguments required by each sub-form object and pass them to the service.
Example psuedocode:
// Controller code
travelSubFrm = new TravelForm(name, dob, address ...); // etc
workSubFrm = new WorkForm(position, dept ...); // etc
// Create service and save details - the service knows the logic
contactFormService.setTravelSubFrm(travelSubFrm);
contactFormService.setWorkSubFrm(workSubFrm);
contactFormService.process();
Just some quick thoughts.
Hope that helps!
EDIT: If you want to start looking into how to architect object-orientated code then I suggest you check out Head First Design Patterns. It's a great introduction to the topic and will help you organise code problem like the one you posted.
I am working on a VB.NET batch PDF exporting program for CAD drawings. The programs runs fine, but the architecture is a mess. Basically, one big function takes the entire process from start to finish. I would like to make a separate class, or several, to do the exporting work.
Here's the problem:
Sometimes the pdf file which will be created by my program already exists. In this case, I would like to ask the user if he/she would like to overwrite existing PDFs. I only want to do this if there is actually something which will be overwritten and I only want to do this once. In other words, "yes" = "yes to all." It seems wrong to have the form (which will be calling this new PDF exporting class) figure out what the PDF files will be called and whether there will be any overwrites. In fact, it would be best to have the names for the PDF files determined as the individual CAD drawings are processed (because I might want to use information which will only become available after loading the files in the CAD program in the background).
Here's the question:
How should I handle the process of prompting the user? I would like to keep all GUI logic (even something as simple as a dialog box) out of my PDF exporting class. I need a way for the PDF exporting class to say, "Hey, I need to know if I should overwrite or skip this file," and the form class (or any other class) to say, "Um, ok, I'll ask the user and get back to you."
It seems there ought to be some pattern to handle this situation. What is it?
Follow-ups:
Events: It seems like this is a good way to go. Is this about what the code should look like in the PDF exporting class?
Dim e As New FileExistsEventArgs(PDFFile)
RaiseEvent FileExists(Me, e)
If e.Overwrite Then
'Do stuff here
End If
A crazy idea: What about passing delegate functions to the export method of the PDF exporting class to handle the overwrite case?
You could use an Event, create a custom event argument class with a property on it that the application can call. Then when your app is handling the event prompt the user and then tell the exporter what to do. I'm a c# guy so let me give you a sample in there first:
void form_Load(object sender,EventArgs e)
{
//We are subscribing to the event here. In VB this is done differently
pdfExporter.FileExists+=new FileExistsEventHandler(pdfExporter_fileExists)
}
void pdfExporter_fileExists(object sender, FileExistsEventArgs e)
{
//prompUser takes the file and asks the user
if (promptUser(e.FileName))
{
}
}
Your PDF making class should raise an event. This event should have an eventargs object, which can have a boolean property called "Overwrite" which the GUI sets in whatever fashion you want. When the event returns in your PDF class you'll have the user's decision and can overwrite or not as needed. The Gui can handle the event anyway it likes.
Also, I commend you for working to keep the two seperate!
So the appropriate method on your class needs an optional parameter of
[OverwriteExisting as Boolean = False]
However your form will need to handle the logic of establishing whether or not a file exists. It seems to me that this would not be a function that you would want encapsulated within your PDF export class anyway. Assuming that your form or other function/class ascertains that an overwrite is required then the export methos is called passing True as a Boolean to your export class.
You could do a two phase commit type of thing.
The class has two interfaces, one for prepping the filenames and filesystem, and another for doing the actual work.
So the first phase, the GUI calls the initialization interface, and gets a quick answer as to whether or not anything needs over-writing. Possibly even a comprehensive list of the files that will get over-written. User answers, the boolean variable in the other responses is known, and then the exporter gets to the real work, and the user can go do something else.
There would be some duplication of computation, but it's probably worth it to get the user's part of the operation over with as soon as possible.
You can't keep the GUI stuff out of the PDF Exporting Code. but you can precisely define the minimum needed and not be tied to whatever framework you are using.
How I do it is that I have a Status class, and a Progress class. The two exist because Status is design to update a status message, and the Progress Bar is designed to work with a indicator of progress.
Both of them work with a object that has a class type of IStatusDisplay and IPrograssDisplay respectfully.
My GUI defines a object implementing IStatusDisplay (or IProgressDisplay) and registers as the current display with the DLL having Status and Progress. The DLL with Status and Progress also have two singleton called NullStatus and NullProgress that can be used when there is no UI feedback wanted.
With this scheme I can pepper my code with as many Status or Progress updates I want and I only worry about the implementations at the GUI Layer. If I want a silent process I can just use the Null objects. Also if I completely change my GUI Framework all the new GUI has to do is make the new object that implements the IStatusDisplay, IProgressDisplay.
A alternative is to raise events but I find that confusing and complicated to handle at the GUI level. Especially if you have multiple screen the user could switch between. By using a Interface you make the connection clearer and more maintainable in the longe.
EDIT
You can create a Prompt Class and a IPromptDisplay to handle situation like asking whether you want to overwrite files.
For example
Dim P as New Prompt(MyPromptDisplay,PromptEnum.YesNo)
'MyPromptDisplay is of IPromptDisplay and was registered by the GUI when the application was initialized
If PromptYesNo.Ask("Do you wish to overwrite files")= PromptReply.Yes Then
'Do stuff here
End If