Friday, January 25, 2013

Catching Line Changes (Part 2)

There are a number of different keys that could change the position of the cursor that needs to check if the line before the movement was modified including Page Up, Page Down, Return (non-insert move to next line), Return (at end of line), Control+Return (insert new line), Left (if at beginning of the line), Right (if at end of the line), Control+Left (if at beginning of the line), Control+Right (if at end of the line), Control+Home (if not at the first line), Control+End (if not at the last line), and the list probably goes on (like simply clicking the mouse on another line).  In any case, a lot of keys to check and special conditions for many (line if at beginning of the line).

I realized there was a much easier way to catch these cursor movements by using the cursor position changed signal emitted by QTextEdit.  Therefore, this signal was connected to a new cursor moved slot in EditBox.  This slot checks if the current line has been modified (value not ‑1) and if this line number is different than the current line number of where the cursor was moved to, then the capture modified line function is called.

However, this conflicted with the current line reporting mechanism, which was previously called before the cursor was moved, but now was being called after the cursor had moved.  So instead of getting the current line (block) number from the text cursor, the current line (block) was found by calling the document's findBlockByNumber() function using the line modified variable value.

These changes work for most of the cursor movement commands, but there still some commands that are not handled properly like Undo, Redo, Control+A (Select All) after a modification, delete operations that combine lines (where the line below being joined needs to be treated as a delete line), and operations involving multiple line changes (like cutting a multiple line selection or pasting a block of lines).

[commit 2f0042faff]

Catching Line Changes (Part 1)

If this was a regular compiler, a plain text editor would be sufficient.  The program would be entered, the user would click run, the text would be compiled and then run.  However, this is an incremental compiler where each line as it is entered or modified needs to be compiled immediately.  Therefore, the edit needs to catch each line as it is entered or modified.

The document (QTextDocument) of the QTextEdit class provides two signals when it has changed, one when any change is made and one with the specific change made by position and number of characters removed or added.  Neither of these are sufficient as one has no detail and the other too much detail.  What is needed is when a line has been modified and when the cursor has moved away from this line.  It is not necessary to compile the line as each character is entered or deleted.

To accomplish this, a new member variable was added to EditBox that will hold the line number of the last line that was modified and will be initialized to ‑1 to indicate no line has been modified.  The document's contents changed signal is connected to a new document changed slot in EditBox.  Using this variable and slot, the steps for catching line changes are:
  1. In the new document changed slot, the current line number that the cursor is at is recorded in the new line modified member variable.
  2. If there is a request to move the cursor from the current line, the contents of the current line is obtained (which will eventually be compiled).
  3. The line modified variable will be reset to ‑1.
  4. The cursor is then moved.
To start only the up and down arrow keys are detected.  A new function for capturing the modified line was added to EditBox since there will be multiple situations that will move the cursor.  For testing, the number and the contents of the line are output to the console to verify that it is was working.  Eventually a signal will be emitted containing the line number and contents.

There was a minor problem that needed to be corrected.  The line modified variable was initialized to ‑1 in the constructor.  When a program was loaded, this triggered the contents of the document to changed and this signal was emitted causing it to record line 0 with a change.  To correct this, when the document modified flag is reset, the line modified variable was also reset, so a new EditBox function was added to do both of these operations.

Eventually upon loading a program, the entire program will need to be compiled line-by-line.  Now that the basic line detection mechanism is working, the detection of additional cursor movements can be implemented.

[commit 2e3e29c6fb]