Sunday, March 31, 2013

Program Model – Storing RPN Lists

The program model receives program line changes from the edit box, which up to now just stored the text of the program lines in a string list.  Eventually the program model will store the internal code of the BASIC program after the line is translated and encoded.  Since the encoder is not yet implemented, the output RPN lists from the translator will be stored so that more components of the GUI can be developed.

In order for the program model to store RPN lists, the program lines need to be translated, which means that the program model class needed a translator instance.  A translator instance member pointer was added, which is created by the constructor and deleted in the destructor.  To hold the RPN lists, a member was added for the list of RPN list pointers.

The update slot that receives the program lines from the edit box was modified to translate new lines and insert the resulting RPN list (which may contain an error); delete the RPN list for a deleted line; and delete the RPN list, translate a changed line and replace the RPN list pointer for the changed line.

The data function was modified to return the text of the RPN list for the requested line (if it doesn't have an error), or the column, length and message as a single string for a line with an error.  Eventually the error will need to be highlighted some how in the edit box.

All uses of the program line string list were replaced with the new translated line RPN list.  The string list member was left in and is still updated by the update slot, and it is also still used to detect line changes.  Shortly this list will be removed when the comparison is made using the RPN lists.

But first a small problem needs to be investigated.  During initial testing, an expected translator test file was loaded instead of the input data file and a segmentation fault occurred.  Loading any text file should just produce a bunch of errors (which is did when one of the other text files used for debugging the edit box was loaded).  Loading the desired translator test file and removing the comment lines produced the translated RPN lists in the program view as expected including lines with errors, which produced the expected error string.

[commit c77bdb9274]

RPN Output List – Including Errors

When a program line is sent from the edit box to the program model, it will be translated to an RPN list.  This RPN list will then be encoded into program code and stored.  For now, the RPN list will be stored.  However, a program line may contain an error.  Program line errors will need to be displayed in the edit box and temporarily in the program view widget.

Previously, the translator held the error token (that points to the error on the line) and the error message.  If there was a translation error, the RPN output list was cleared and the RPN list instance was deleted.  The caller would then obtain the error token and message instead of the retrieving the RPN list.  Since a program consists of many lines, several lines could contain errors.  There errors need to be kept with the program line and not in the translator instance (which only holds one error; the most recent).

Since the program model will be storing the RPN lists of the program lines, the error token and error message was moved from the Translator class to the RPN List class along with their accessor functions.  The RPN List instance is no longer deleted upon an error since it will be holding the error token and message, though the actual list is still cleared.

The translator's functions set input (given an input line, which was translated, and returned translation status) and output (returned the RPN output list upon successful translation) were replaced with a new translate function.  This function is essentially the set input function except it now returns the RPN output list (which may contain an error).  For safety, this function resets the RPN list output member pointer before returning - the caller takes possession of the RPN list instance.  A new has error function was added to the RPN List used by the caller to check the translation status.

[commit 27cd073e43]

Clear RPN List Issue Resolved

The next small incremental change implemented the RpnItem::text() and RpnList::text() member functions that return string representations of the RPN item (token with any operand tokens in square brackets) and of the RPN list respectively.  Previously the Tester::printOutput() function performed these tasks directly to the standard output stream.  A string is now necessary so that it can be output to the program view widget.

It was hoped that having these functions would resolve the segmentation faults that was occurring at the conclusion of the foreach loop that processed the RPN list.  However. it did not.  Therefore, to eliminate this problem, the foreach was simply replaced with a regular for loop for the count of the items in the list using the at() function to access the elements in the list.

This eliminated the unwanted call to the destructor and a call to the clear() function was added to the destructor so it is no longer necessary to call the clear() function from the users of the RPN list instance when they are deleting the instance.

[commit e634d6f196] [commit 1438e1e987]

Saturday, March 30, 2013

Translator RPN List Output

After two failed attempts to create an RPN list class to hold the translator output, smaller incremental changes were made and tested after each change, including the memory test, and then the small changes was committed.

The first small change implemented the new Token::text() member function that returns a string representation of the token.  Previously the Tester::printSmallToken() function performed this task directly to the standard output stream.   It is now necessary to have a string so that it can be output to the program view widget.

The second small change created a new RpnList class based on QList<RpnItem*>, which has all the same functionality as the original list.  This class was defined in a new header file and the RpnItem class definition was moved to this header file from the translator header file.  This class is necessary so that the instance of this class can also hold the error token and message.

The third small change implemented a clear memory function to the new RpnList class to delete the memory used by the RPN item instances created in the translator along with the token instance each item holds.  It is a good idea to have the class perform this task and not every user of the class.

This was where at least one of the problems occurred.  It made sense that the destructor for the RpnList class call this clear function so that the caller would not have clear the list before deleting the instance, but a segmentation fault occurred in the Tester::PrintOutput() function that outputs the text of the RPN List.  The destructor of the instance was called, which deleted all the tokens (it appears the foreach macro is doing this).  When the RPN List instance is then finally deleted, the fault occurred because the token had already been deleted.

This bad change was put on a failedClearAttempt branch [commit a16abf424a] to show what apparently cannot be done.  This will be investigated next.

[commit 9d3d8bc834] [commit f49560c08f] [commit 9522d2a0ad]

Thursday, March 28, 2013

Expected Batch Test Results Change

The translator currently has several outputs depending on the input, either there is an RPN output list (if translation succeeds), or there is an error token and error message (if translation fails).  For now, the program model will be changed to hold the RPN output list for each program line instead of the text of the line.  However, if there is an error, details of the error (location and message) will need to be stored instead.

A new RpnList class was created to contain the list of RpnItem instances, and any error token (with location) and error message.  An instance of this class will be stored in the program model.  After making these changes and some other changes (though there is no point in describing these here), because as a result, all of the parser tests failed.  Worst, all the expression and translator tests caused the application to crash.

The parser tests failed simply because the copyright year had been updated from 2012 to 2013.  The test results could be updated for this, but this will need to be done every year.  There is no point for these expected batch test output files to contain the copyright message along with the warranty and table initialization messages anyway.

Therefore, the copyright, warranty and table initialization messages were removed from the output, but these are still appropriately output in console input test mode.  Since these messages are no longer being put in the expected results files, the translate tr() function was added to these strings.  All of the tests results files were updated, and should not need to be updated again unless the test inputs change or for some reason the outputs change.  Now back to the RPN list changes...

[commit ff17139321]

Saturday, March 23, 2013

Initial Program Model Complete

There were some minor problems with the Save As action causing it to not work as desired, namely the file name was incorrectly defaulting to "." and the directory of the file saved was not being remembered.  The default file name was set to "." in the attempt to use the current directory, but the get save file name dialog saw this as the file name with no directory and used the directory the program was started in.  The string "./" should have been used.

The way it should be working is that the file name should start with the current file name giving the user the option to replace it or modify it.  If the user doesn't change the file name, the dialog will issue a warning asking if the file should be overwritten.  If the current file is untitled, then the default file name will be set to the current directory, and the dialog will contain a blank file name.  After the file is saved successfully, the current directory (that gets saved in the program settings upon exit) is set to the directory of the saved file.

Now it is time to start hooking up the parser and translator between the edit box and program model.  But first, this is a good point to make a development release.  The release related files were updated for a new release and the repository was given the tag v0.3.3.

[commit 143f449330] [commit f95a3d8d55]

Another Undo Issue

Testing has now been completed and I think most of the possible change scenarios have been tested.  There was some more problems with undo operations when at a new line that was not yet reported as inserted.  For some undo operations, a line was not being reported as changed when it should have been.  This occurred when the line of the beginning of the undo change was more than one line away from the current line that was new.

To correct this problem, a check was added if the line of the beginning of the change is more than one line away from the modified (new) line, then the number of lines modified is set to one from zero and since this is the next line, the changed line number is incremented.

Getting into this situation was rather complex, which required an insert of a new line (Control+Enter) in the middle of a line, moving to the end of this new line, deleting the end of this line to combine it with the next line, and then one undo.  This worked so far, but doing undo again is when the problem occurred.  I'm sure there could be more complex sequences that will not be detected correctly, but it's time to move on.  Any new problems that occur will be dealt with as they appear.

There is also a screen update problem that sometime occurs during an undo where a entire line is not redrawn correctly on the screen.  However, this was proven to be a bug in the QPlainTextEdit base class, not in the EditBox class because a simple program using just the QPlainTextEdit also exhibits the same bug (though the QTextEdit class does not).

[commit 2fc26b865a]

Friday, March 22, 2013

Paste Over Selection Update Screen Issue

Another unrelated issue was found while testing, this time with paste.  The problem occurs when there is a selection, and some text is pasted over the selection, replacing the selected text.  Sometimes, the screen does not update correctly where part of the selection remains.

This can be seen by first copying a single line (some characters followed by a new line) into the clipboard.  Then selecting from the middle of a line to the end of the next non-empty line.  Pasting at this point places the cursor at the beginning of the second, the first character on the second line is removed from the screen, but the rest of the line remains and appears selected.  The document is properly updated as can be seen in the program view.

This problem was corrected by reimplementing the paste function (again).  This time it was given an argument for the clipboard mode with a default of clipboard.  The current text cursor is obtained.  If the cursor has a selection, it is copied into a temporary cursor.  With this temporary cursor, the selection is cleared and the edit box text cursor is set to the temporary cursor to applied the cleared selection.  This may not be the best way to solve this issue, but several other attempts did not work and this solution did.

The selection remains in the origin cursor.  The text is then obtained from the clipboard for the clipboard mode selected and inserted using the original cursor (replacing the selection if there was one).  To also correct the middle-click paste, the insert text call with the current text cursor was replaced with a call to the reimplemented paste function with the clipboard selection mode.

[commit 0ef619bc5c]

Thursday, March 21, 2013

Handling Shift+Enter Correctly

Testing continues and no new problems have be found so far.  However, an unrelated problem was discovered with the Shift+Enter key sequence.  When there was no selection, a Shift+Enter behaved liked a regular Enter, either moving to the next line or entering a new line if the cursor was at the end of the line.  But if there was a selection, a new line character was inserted in the middle of the line.  This was evidenced because no line number was displayed including in the program view, which is the same as for a long line.

Normally, the plain text edit widget allows the insertion of a new line with Shift+Enter (like word processors).   The reimplemented edit box key press event handler partially changed this behavior, but the old behavior remained when there was a selection.

I decided to make a Shift+Enter behave as extending the selection (or starting a selection if none is present) to the beginning of the next line.  This is the same as when holding the Shift with other movement keys (arrows, Home, End, etc.).  There is no reason to allow new lines to be inserted in the middle of program lines.

This was corrected by incepting the Shift+Enter key sequence first.  The same moveCursor()  function is called with the same NextBlock move operation, but instead of using the default MoveAnchor move mode, the KeepAnchor move mode was added, which extends (or starts) a selection.

[commit 32149da677]

Tuesday, March 19, 2013

New Line Detection Correction

The next problem discovered occurred when a multiple line selection was replaced with less lines than the selection and the cursor was at the end of the line after the change.  The lines removed were not being reported as deleted, in fact nothing was reported.  This was in the same section of code as the first problem, but this time the problem was caused because the modified line is new flag was being set when it should not have been.

As described on March 6 (second paragraph), an earlier fix added a check if characters were added when the cursor is at the end of the line to set this flag.  However, for this case, both of these conditions were true, so that flag was wrongly set.

Instead of checking if characters were added (which catches some of the wrong conditions), the code was changed to check if lines were added to the document, which was accomplish by checking if the local net line count variable is greater than zero.  If lines were deleted, or no lines were deleted or added, then this flag is not set.

[commit dea0ef4951]

Monday, March 18, 2013

Multiple Line Undo Correction

The first problem identified while testing the many possible change scenarios was with an undo for a multiple line insert, where the last line is still marked as new (the cursor hasn't been moved away from the line yet when it would be reported as inserted).  The previously inserted lines removed by the undo were not reported as being deleted.

The problem occurred in the section that handles when lines are deleted and the cursor line was marked as new.  This was thought to only occur when the operation was either a backspace at the beginning of a new line or a delete at the end of a new line.  This situation was handled by resetting the modified line is new flag and not reporting an lines as being deleted.

However, the undo of a multiple line insert also causes this condition.  This was corrected decrementing the number of lines deleted instead of reporting no lines deleted.  For the case of a backspace or delete (and also an undo of a single line insert), the one line deleted becomes zero and no lines are reported as deleted.  For the undo of a multiple line insert, the correct number of lines are reported as deleted - one less for the new line that hasn't been inserted yet.

[commit faa2467463]

Saturday, March 16, 2013

Program – Custom Data Model

Up to now only the simple predefined string list model has been used to hold the program.  The next task was to start the implementation of a custom data model that will eventually hold the program code that will be run.  To get he program model started, it will just hold a list of strings representing the lines of the program.

The new ProgramModel class is based on the QAbstractListModel as it only needs to hold a list of program lines.  This will be changed as needed since the program model will eventually need to be able to hold multiple lists of program lines, one for the main routine and several for the subroutines and functions of the program.

Now that the initial program model has been implemented (click Continue... for details), using the program view, all the various edit change operations and scenarios will now be tested to make sure all the possible changes are covered and working properly.  This is necessary to make sure the edit box keeps the program model properly informed of program changes.  Then the process of connecting to the parser and translator will begin.

[commit b543f74b6d]

Thursday, March 14, 2013

Edit Box Line Numbers – New Lines

When a new line is being entered into the edit box, a line that has not been inserted into the program yet, the line numbers don't match between the edit box and the program view from the new line to the end.  Therefore, the drawing of line numbers in the edit box was updated to display no number fora new line (just the '+' character).  In the line number paint routine, each line after the new line needed to have one subtracted from its real line number in the edit box document to match the line numbers in the program view.

This lead to a problem after the new line was inserted into the program, the line numbers for all the lines after the new line were not updated to reflect their real line numbers.  This was corrected in the capture modified line routine.  When the line reported was marked as a new line, the update routine of the line number widget (the line number area) was called with the coordinates of the line number area rectangle.  Technically, only the rectangle from the current line down to the bottom is needed, but I couldn't figure out how to determine the Y-coordinate of the current line.  Redrawing the whole line number area shouldn't be a problem.

[commit c75d67d509]

Wednesday, March 13, 2013

Program View Line Numbers

A number of changes were made to display the line numbers in the program view similar to the edit box.  The paint function in the program line delegate was updated to display the line number and the program line in separate rectangles.  The background color of the line number rectangle is displayed in light gray like the edit box.  To space the characters in these rectangles nicely, a half character space was added on both sides of the line number and in front of the program line text.

Before the line number can be drawn, the width of the line number rectangle needs to be determined, which is based on the number of lines present in the program.  A new update width function was added that is called with a new line count each time it changes.  This function calculates the number of digits the new line count will take plus one character to account for the two half spaces on either side of the line number.  The number of pixels required is calculated and if different from the previous value calculated, the new value is stored into a new member variable and a signal is emitted to indicate that the program view needs to be updated on the screen.

Two other members were added to the class, the pixel width of a digit and the base line number (the number of the first line).  The constructor was modified with two new arguments, one for the base line number, which is stored, and the font metrics of the font used for the program view, which is used to get the pixel widget of one digit and is stored for the new width update function.

The lines to set up the program line delegate and program view in the main window constructor needed to be moved to before the initial program is loaded so that the correct line number count gets to the program line delegate.  The program changed slot was modified to check when the program line count has changed by checking a new program line count member variable, which is then stored and the update width function is called.

Finally, the program view update signal is connected to a new main window slot that updates the program view rectangle.  This slot and the program line count member variable are temporary until a more advanced program model is implemented.  Currently the program model is a simple string list model that is unaware of the program.  The other commit made was to have the program view use the same fixed width font of the edit box.

[commit 3b68b11d11] [commit a7f38c99e4]

Monday, March 11, 2013

Saving The Window State Settings

 Saving the window geometry alone is not sufficient to save the state of the Program View dock widget. The state of the main window also needed to be saved to preserve the settings of the tool bars and dock widgets, including where they are docked or floating (undocked), their sizes, and whether they are turned on or off. This window state was added to the save and restore settings routines of the main window, which were given the settings name windowState.

A dock widget can also be turned off by clicking its close button on its upper-right corner. To turn it back on, there is a context (right-click) menu that can be accessed by clicking on the unused part of the menu bar or tool bar area. A dock widget can be undocked (to make it floating) by dragging the dock widget title bar away from the main windows. Tool bars can also be undocked.

When I discovered this context menu when noticing that there was an empty tool bar beside the main tool bar that should not have been there. Besides the Program View dock widget, this context menu also showed a blank tool bar and toolBar. The blank tool bar was actually the main tool bar and it was blank because the main tool bar was never given a title (the windowTitle property).

These issues were corrected by assigned the main tool the title Main Tool Bar and the extra tool bar was removed (which must have been added by default when the Main Window GUI class was created and a new tool bar was inadvertently created to hold the tool bar actions).

[commit 9d3c4a9404]

Sunday, March 10, 2013

Program View Line Numbers – Custom Item Delegates

It will be very helpful during testing if the program view displayed line numbers like the edit box.  This was accomplished with what Qt calls a custom item delegate.  An item delegate is responsible for drawing the items in a widget and widgets have a default delegate.

A new ProgramLineDelegate class was created with the QItemDelegate class as its base.  Since the program list view is read-only, the only function that needs to be reimplemented in this new class is the paint() function, which has arguments to the painter (used for drawing to the screen), the current style option (which contains information about the view item like its bounding rectangle), and an index of the item to paint.

To start simple, the line number is obtained from the row of the index and the text of the line is obtained from the model of the index (currently the QStringListModel setup to hold the program lines), which is used to get the string of the item that needs to be displayed.  These two items are formatted using the string "%1: %2" to put the line number followed by a colon and the string of the program line.  This string is then drawn to the screen using the painter's drawText() function.

This is crude, but was a proof of concept (this is my first time using delegates).  This will be cleaned up next by drawing the line number separately in its own rectangle with a different background color.  It will also need to determine the width of this rectangle based on the maximum line number like with the edit box.

[commit 941b1f8e75]

Loading File and New File Issues

While testing with the new program view, when doing a File/New, the last line in the document remained in the program and the line was set modified.  With New, the entire program should be cleared.  Further testing revealed additional problems when loading a new file replacing the current file where the lines in the old file were not being removed before the new file's lines were inserted.

Some additional checks were needed to properly handle these situations, which occur when the document is empty.  If the cursor move failed (which occurs when the file is emptied either with a New or before a new file is loaded), if the change indicates one character was added (occurs with the first of two change signals), then a New operation is occurring.  The modified line variable is set to -2 to indicate that a New is in progress so that when the second signal is processed, the code knows if it is due to a New and not a file load.  Otherwise, if the current line count is zero (the document was empty before the change), then this is the first signal of a file load and should be ignored.

When the document is empty and neither of these conditions exist, then all of the document contents were removed, either because a new file is being loaded, a New was selected, or all of the characters were deleted (for example, with repeated deletes or Selected All and Delete).  For the first two situations, all of the lines of the program should be reported as deleted, but for the third, the last line should remain and be set as the modified line.  The load file conditional occurs when the cursor move failed and the New previously set the modified line to -2.  For these conditions, the net line count is set to the number of lines that were in the document, the new line count is set 0 and the change at the beginning of the line flag is set because it is not set when the document is empty.

At the end of the document change routine where the modified line is set to the current cursor line (the end of the change), it needs to instead be set to -1 if it currently set to a -2 from a New operation, so that the first (and only) line in the document after a New operation is not marked as modified.

One other minor problem was also discovered when an empty file is loaded and the document was previously not empty.  The window modified flag was set (shown with an asterisk after the file name in the window title bar).  I'm not sure why this occurs, but it was corrected by clearing the window modified flag after a program is loaded and the document is set.  Reseting the edit box document's modified flag was not sufficient.

Finally, it was noticed that the program view list widget was grabbing focus when a new file was loaded or New was selected as evidenced by the edit box cursor disappearing and the focus could be seen be the light blue focus indicator around the widget.  This list view widget was prevented from grabber focus by setting its focusPolicy property to NoFocus.

[commit 65bd6a9233]

Saturday, March 9, 2013

Viewing Program Changes

To monitor the contents of the program, which will be updated by the program changed signal, a Program View dock widget was added to the right side of the application GUI using Designer.  A dock widget can be docked to any side of the window, through this dock widget was restricted to the left and right sides.  A dock widget can also be undocked from the main window.

A QListView widget was added to the Program View dock widget.  The editTriggers property was set to NoEditTriggers to prevent editing and the selectionMode property was set to NoSelection to prevent selection.  In other words, this list view was made read-only.

A QListView is meant to work with a data model.  Eventually a custom Program Model will be created that will hold the program.  The MainWindow class will contain a pointer to the Program Model.  To keep it simple to start, the predefined QStringListModel was used.  This model simply maintains a list of strings, which for now are set to the program line strings.

The program model is instanced in the MainWindow constructor, which must be done before the edit box is instanced, since the edit box will generate a program change signal.  This model is then assigned to the QListView widget.  Any changes to the model will be reflected in the dock widget.  The program changed slot in main window was modified to update the program model as changes are received instead of outputting the changes to the console.

[commit 60e125362e]

Entire Loaded Program Detection

The only remaining use of edit box ignore change flag mechanism was to stop detection when the document was set using the reimplemented setPlainText() function, which set this ignore flag before calling the base class function and cleared it afterward.  The document change function upon seeing this flag set returned without processing the change.

Since it was now desired to process this change and report all lines as being added, the ignore flag mechanism was removed.  Also, the remaining functionality of the reimplemented setPlainText() function was calling the base class function and then setting the line count variable.  The line count variable will now be set by the document change function, and since this function was only calling the base class function, it was also removed.

For some strange reason, there are actually two document contents change signals generated when the document text is set, one where it indicates one character removed and none added, and a second one with no characters removed and the number of characters in the file added.  My guess is that the first signal is generated from the document being cleared before being set, and the one character is an empty line where the document always contains at least one block (with a single new line).

This first change signal needed to be ignored, which can be accomplished by checking if the document is empty.  However, this is not the only case where the document could be empty (like if all the characters were deleted).  Another indicator was needed for this condition.  The document change function does a move cursor position by the number of characters added to determine where the cursor will end up.  It turns out that this function returns whether the move succeeded.  If the document is empty, this move fails, so this status is captured.  If the document is empty and the move failed, the document change function only resets the modified line and returns.

The cursor position move also fails when with the second signal because the number of characters added is one more than the cursor can be moved.  Since this move fails, the number of lines modified ends up being zero instead of being set to the number of lines in the document that were added.  To emit the correct number of lines inserted, the number of lines changed is only adjusted if the cursor move succeeded or the number of lines modified is not less than the net line count change when lines were added to the document.

[commit 23c1ace139]

Newly Inserted Lines Fix

When a new program is loaded, the entire program must be loaded into the document (as plain text) and the class that will hold the encoded program.  One method would be to set the edit box document to the plain text of the program and then set the program class.  Another method is to allow the program change signal that would be emitted when the document is set to the text of the program (which is presently disabled).

After re-enabling the signal when the document text is set, and trying to get the proper signals to be emitted, I discovered that newly inserted lines were not always being emitted correctly.  A simple example of this is when a return is entered at the end of the new line - the line was reported as changed instead of inserted.

This problem occurred because the code needed to check if the current modified line is going to be new, but was not previously new before adjusting the number of lines changed and inserted for the new line.  When the line is new, but wasn't previously new, the number of lines modified is incremented by one and the number of inserted lines is decremented by one to account for the new line that hasn't been inserted yet.

The aid in debugging, a status indicator character was added to the line number widget after the line number of the current line to indicate when the current line is modified (with an asterisk) or is new (with a plus).  This is easier than having a message on the console indicating the line number modified and new status, and then having to refer to edit box to see which line the cursor is at.

[commit 9f15211791]

Line Change Detection Complete

The detection of program line changes should now be complete.  This feature is necessary so that program lines can be incrementally compiled as they are modified.  Even though the implementation was starting to look rather complicated, it turned out to be fairly simply, which was mostly concentrated in the processing of the edit box document's contents change signal that contained sufficient information to report line changes.  From the time the new implementation was started, the size of the edit box code was reduced by about half and the previous implementation wasn't complete.

The next step is to connect the new program changed signal from the edit box to some new program class that will eventually hold the BASIC program code, though the goal of the current 0.3.x release series is to get the translator part hooked up.  However, this is a good point to make a development release.  In preparation for this, there was some minor cleanup of the code:
  1. Renamed the edit box line number widget related functions with the consistent prefix of lineNumberWidget (separate commit).
  2. Corrected a memory leak of the edit box instance by assigning the main window as its parent.
  3. Removed the setting of the ignore change flag at the end of the edit box key press event handler (this flag is now only used when a new program is set).
  4. Updated the copyright of the modified files and a few other very minor changes.
The various files (CMake, read me, and release notes) were updated for this development release and the code was given the tag v0.3.2.

[commit a2cfa5361a] [commit a13c485632]

Friday, March 8, 2013

Capture Modified Line Upon Saving

If the edit box has a modified line, it needs to be reported before the program is saved.  This is accomplished by calling the capture modified line routine (currently called when the cursor is moved from a modified line) in the save program routine.  This required the capture function to be made public.  This function already contains a check if there is a modified line before reporting a change, so if there is not a modified line, no action is taken.

[commit 0561cc9a64]

Save Action Enabling

There is a feature in LibreOffice where the save action (menu and tool bar) is only enabled when the document has been modified, otherwise it is disabled.  Microsoft Office does not have this feature.  This feature was simple to add and only required the edit box's document's modification changed signal to be connected to the save action's enabled slot.

[commit 93c856dcb4]

Select All Correction

While testing, it was noticed that when using the Select All (Control+A) key sequence to select the entire document, a cursor position change signal was not being received.  The prevented a line changed signal from being emitted if the current line was modified.  The cursor should be moved to the end of the document.  Using Select All from either the Edit menu or the context menu did work correctly.  This problem was corrected by intercepting the Select All key sequence and calling the select all function that was connected to the menu actions.

[commit 6a7c9c57e4]

Detecting Changes With Undo/Redo

Curiously, when the document's contents change signal is received for an undo or redo operation, the cursor has not been moved yet, so the current cursor position cannot be used to determine the number of lines changed from its line number and whether the cursor is now at the end of the line.

The beginning of the document changed slot function was modified to get the current text cursor and set its position to the position of the change.  The line number of this position and whether this position is at the beginning of the line is obtained.  This cursor is then moved to the end of the change by moving the cursor right by the number of characters added by the change.  This method also works for all of the other types of document changes.  Several of the local variables in the function were renamed to make the code clearer.

The reimplemented undo and redo functions are no longer deleted and were removed along with the checks for the undo and redo key sequences in the key press event handler.  It is also no longer necessary to keep track of the undo and redo operations on the current modified line, so the undo added slot was removed along with the modified line count and undo active variables.  This mechanism was originally implemented to keep track of changes on the current line so that unnecessary line change signals were not emitted, but now the receiver of this signal is will be responsible for detecting actual line changes (see post on March 3).

[commit a9db922c4d]

Before Selection Not Needed

Previously, information about the selection before a document change operation was saved.  This information was used to figure out what text was replaced by the operation.  This is no longer needed because this information can be determined from the position received in the document's contents change signal and from the current cursor position, which is at the end of the change.

Therefore, the before selection no longer needs to be saved.  Also, since this was the only use of the Selection class, this class was also removed.

[commit ebffb4445c]

Thursday, March 7, 2013

Adjusting/Correcting Return Key Behavior

Previously, a Return key only inserted a new line when the cursor was at the end of a non-blank line.  Otherwise, the cursor is moved to the beginning of the next line.  This will reduce accidentally breaking lines in the middle of them.  The Control+Return key was implemented to insert a new line always.  Upon, using the edit box for a while, I decided to make Return insert a new line when on a blank line.

A problem was corrected when there was a selection, a Return key ignored the selection an moved to the next line instead of replacing the selection.  The code was changed to only move to the next line when there is no selection.

There was also a problem when a selection went across two lines, with part of the second line selected.  A Control+Return key entered should replace the selected text with a new line, which it did, however, the edit box contents were no redrawn properly where the selected characters on the second line remained selected on the screen.  These characters were not actually selected and the were deleted from the document.  Must be some sort of bug in the Qt libraries or the libraries routines were not being utilized correctly.

This problem was corrected by replacing the insert text call of a new line with the creation of a new key press event with a Return key, calling the QPlainTextEdit base class key press event handler, deleting the key press event and returning.

[commit a8b9f09778]

Wednesday, March 6, 2013

Issues With Newly Inserted Lines

The edit box contains a variable to indicate when a line has been inserted but not yet reported as being inserted (in other words, a new line).  Lines are not reported as being modified (changed) until the cursor leaves the line.  This will prevent unnecessary compiling of the line as it is being entered.  This includes a new line that is being entered.  There were some issues with new lines that were corrected.

A new line can only occur when multiple lines have changed or a single line has changed and the change is not at the beginning of a line.  After a change, the modified line is marked as new if there was a single line change and the change was not at the beginning of a line or if the cursor is at the end of a line.  The problem was with this last part when the change was due to a delete at the end of a line and the next line was blank (the cursor was still at the end of the line).  This was corrected by checking if characters were added by the change.

When on a new line, if a backspace occurs is entered the beginning of the line or a delete at the end of the line, the current line or the next line was being reported as deleted, but a new line wasn't reported as inserted yet.  This was corrected by adding a check if the current line is modified and new, to reset the status of the line to just modified, and to not report the line that is removed as deleted.  This change caused another minor problem where an empty lines changed signal was emitted (no changed, deleted or inserted lines), so this empty signal was prevented.

The variable being used to indicate whether a modified line was changed or inserted (new) was an enumeration, however, this enumeration only had two values.  To make the code easier to read, the variable was renamed and changed to a boolean variable.

Finally, deleted lines were not always reported correctly in the main window's program changed slot that is temporarily connected to the lines changed signal for debugging.  The deleted lines loop was corrected so that these lines are reported correctly.

[commit f10eca50ba] [commit 4364d7447f] [commit 74a5eb93a0] [commit 53bf17fda2]

Monday, March 4, 2013

New Line Change Detection – Backspace

A check for the backspace key was originally added to catch the situation where a backspace at the beginning of a line combines the line with the previous line, causing the current line to be deleted.  There were a number of conditions that needed to handled that eventually the functionality was put into a separate function (for details, see posts on January 30, February 3, February 6, February 7, and February 9).

The document changed slot function now handles this backspace operation, so the backspace key no longer needs to be checked for and the backspace function was removed.  However, there is a situation with the backspace that is not yet being handled correctly (that was by the backspace function), specifically if a backspace at the beginning of the line occurs on a line currently marked as a new line not yet inserted.  The line is currently reported as being deleted (but was not yet actually inserted).

There are a number of other situations where the modified line is marked as inserted that are not being handled properly by the document changed function.  One case, this function is incorrectly marking the line as newly inserted if the cursor is at the end of the line after the document change.  This is correct only for some situations.  These issues will be addressed next.

[commit 9b1d127f93]

Sunday, March 3, 2013

New Line Change Detection – Inserting Text

The insert text function of the edit box was implemented to process text inserted into the program so that changed lines could be detected and reported.  It was used to insert a new line, for the return key, the reimplemented pasted function, and the paste selection function (middle-click paste on Linux).  This function is not longer needed and was removed.  The code for the return key was already changed to simply use the insert text function of the text cursor (and the document change function handles the line change detection).

The other two uses were also updated starting with the reimplemented paste function originally necessary to catch the paste action (menu, context menu, and tool bar) and call the insert text function.  The paste function is no longer necessary since the document change slot function will be called for all paste operations.  Therefore the reimplemented paste function was removed.  The check for the paste key sequence is also no longer necessary (will be handled by the plain text edit base class key event handle, which will call the document change slot function).

The mouse release event handler was reimplemented in the edit box class to catch the middle-click paste of the selection and call the insert text function.  This is also no longer necessary, so the handler function was removed.  However, the paste selection function, which was called from the mouse release event handler, is also called for the Control+Shift+Insert key sequence to pasting the selection.  This is still needed, so the insert text function call was replaced with the text cursor insert text function.

[commit 361f10a7f5]

New Line Change Detection Code

Detecting all line changes can be performed by connecting to the edit box document's contents change signal that includes the position in the document of the change along with the number of characters removed and added.  Previously, only the number of character values were being saved for the various detection routines and the position was ignored.  However, the position can be used along with some additional information, to fully detect what has changed in the document, and it turns out the number of characters values no longer need to be stored.

One piece of additional information needed is the net change in the number of lines of the document, which can be used to indicate whether lines were inserted or deleted.  Therefore, a new total line count variable was added to the edit box class and updated after processing a contents change signal.  Other information used is if the position of the change was at the beginning of the line and if the cursor is at the end of the line after the change.

The three signals emitted from the edit box for program changes (line changed, lines inserted and lines deleted) were replaced with a single lines changed signal that includes the line number of the change, the number of lines deleted (could be zero), the number of lines inserted (could be zero) and a list of strings of the lines that were changed (if any) and inserted (if any).  The number of lines changed is the size of this list minus the number of lines inserted.

One of the things the new detection code does not do that the old code attempted to do was determine whether a line actually changed or not, and if not it is not reported.  For example, inserted text that started with a new line inserted at the end of a line, the line is not actually modified so it wasn't reported.  Since the new code does not do this, the receiver of the lines changed signal, will perform this check to see if a particular line was actually changed (to prevent the line from being recompiled).

The new line change detection code is mostly fully working, however, it is not completely hooked up to all the possible document changes that can occur.  In some cases, the code was simply modified to compile, so some code was temporarily commented instead of being changed.  In other cases, the code was modified like the capture deleted lines routine was not needed and was removed.  All of the other causes of changes will be hooked and the code will be cleaned up over the next set of commits.

[commit 00dfbe3268]