Dreamstime

Wednesday 12 November 2014

RavenPlus: Spell-checking And The "Save" Button

The Spell-Check Dialog Box In Raven/RavenPlus

Here is another quirky behaviour in the editor window in Raven/RavenPlus. Similar to my previous post on "drag-and-drop", this problem will also only be apparent if the first thing that is done after opening an existing blog post for editing is a spell-check, or when we do a spell-check right after saving our blog post while editing. If one or more words were "replaced" via the "Spell Check" dialog box (by clicking on the "Replace" or "Replace All" button and thus modifying the blog post), the "Save" button on the toolbar remains disabled. To enable the "Save" button, what I used to do was to insert and then delete a blank space. But that can't be right, and it should not be happening in the first place.

Fixing The Problem

As humans, we tend to seek for answers that looks similar to our problems - Why reinvent the wheel? But unfortunately this did not help here. On first impression, this hiccup looks very similar to the "drag-and-drop" problem that I had previously, like I mentioned above. The most obvious solution then is to identify the event, and then add the "_fireContentModified()" function into the appropriate event handler so that the "Save" button will be enabled. Unfortunately, after much testing I have come to realise that no event is fired when words are replaced via the "Spell Check" dialog box. I went through the list of events, tested them out one by one but none of them worked.

Then I thought perhaps I could identify the class and function where the word replacement is actually done and then issue a "_fireContentModified()" function call in the file

zoundry\appframework\ui\widgets\controls\advanced\mshtml\mshtmlcontrol.py

just like what I did in the "drag-and-drop" problem. I am sure that I can get this to work (with much code massaging) but then I felt uneasy with this idea as I will then be tightly coupling this 2 separate classes together.

After giving much thought, a much better solution, I think, is to fire an event into the editor when a word is replaced, and luckily there is a way to do this via the FireEvent() method . Since I use a key-press to enable the "Save" button, as mentioned above, the most obvious event to fire then is an "onkeypress" event. Besides, the code for the "onkeypress" event handler is already in place.

(Note: The documentation in the Microsoft Developer Network spelt "FireEvent" as "fireEvent", but it did not work for me. I got a runtime error: "Object has no attribure 'fireEvent'".)

The Source Code

We only need to modify just this one file in order to fix this problem:

zoundry\appframework\ui\widgets\controls\advanced\mshtml\mshtmlspellcheckctx.py

There is only one class in this file, ZMshtmlEditControlSpellCheckContext. The code in RED below is the modifications that I made in this class.

====== BEGIN ======

    def __init__(self, mshtmlEditControl):
        ZBaseEditControlSpellCheckContext.__init__(self)
        self.mshtmlEditControl = mshtmlEditControl
        self.startRange = None
        self.endRange = None
        self.currRange = None
        self.ieWord = None
        self.ieSentence = None
        self.wordCount = 0

        # Make the variable "mshtmlBodyDispElement" local within this class -
        # we will need it at "_replaceWord" to fire a "onkeypress" event into
        # the MSHTML.Body element.
        # Chuah TC : 2014 Nov 2
        self.mshtmlBodyDispElement = None
    # end __init__()
    def _initialize(self):
        # Appended "self." to "mshtmlBodyDispElement" in this function.
        # Chuah TC : 2014 Nov 2
        doc = self.mshtmlEditControl._getMshtmlControl().getIHTMLDocument()
        self.mshtmlBodyDispElement = getDispElement(doc.body)
        self.startRange = self.mshtmlBodyDispElement.createTextRange()
        self.startRange.collapse(True)
        self.currRange = self.mshtmlBodyDispElement.createTextRange()
        self.currRange.collapse(True)
        self.endRange = self.mshtmlBodyDispElement.createTextRange()
        self.endRange.collapse(False)
        self._resetWordCount()
    # end _initialize()
    def _replaceWord(self, textRange, originalWord, replaceWord):
        if textRange and originalWord is not None and replaceWord is not None:
            # The text range where word found by IE may include the space (if any) following the word.
            if originalWord.endswith(u" "): #$NON-NLS-1$
                textRange.text = replaceWord + u" " #$NON-NLS-1$
            else:
                textRange.text = replaceWord

            # Chuah TC : 2014 Nov 2
            # Fire an "onkeypress" event to MSHTML.Body element
            # to enable the "Save" button that is on the editor's
            # toolbar.
            self.mshtmlBodyDispElement.FireEvent("onkeypress")
    # end  _replaceWord

====== END ======











2 comments:

  1. Are you going to issue a new compiled version with this fix?

    ReplyDelete
    Replies
    1. Hi! Vexillia. Nice to hear from you again. How is sunny England?

      I am thinking of doing a couple of fixes first before releasing, perhaps a 'patch' (still undecided on what's the best approach in order to save bandwidth). Also I need to document what I have done so that I do not forget, and I do forget after just a couple of days.

      A 'patch' because what needs to be updated is just 2 files in the 'bin' directory - 'library.zip' and 'ravenPlus.exe'. A 4.7MB Vs a 12MB download.

      Delete