Wednesday, January 23, 2013

Keyboard Event Filter

One of the tasks for the edit box is to intercept keys before they are processed by the QTextEdit base class so that additional programming related keyboard commands can be implemented.  This is accomplished by installing a custom event filter function to the widget.  An installed event filter is called before the doing the regular event processing.  An event filter can be a member of any class and be installed to any widget.  Because I don't see a reason not to, the EditBox class was given an event filter and it is installed to itself in the constructor:
installEventFilter(this);
The argument of this function call is the class containing the event filter, which in this case is the instance itself.  The event filter contains an argument of the object receiving the event and the event itself.  In this case, since the event filter was only installed for this instance of the edit box, the object will be the instance itself and there is no need to check it.

The first key to modify is the Return key.  For a text editor, the Return key simply inserts a new line.  It is desired that a Return key enter the current line into the program (parse, translate, etc.) no matter where on the line the cursor is at.  In other words, not to break the line into two lines at the cursor.  However, if the cursor is at the end of the line, it will open a new line (insert a blank line) on the next line.  To allow a line to be broken into two, the Control+Return key will be used.  The Control+Return is ignored by the QTextEdit class.  So the first behavior implemented in the new event filter was to treat a Control+Return key as a Return key.

The event filter receives all event types, so the event type is first checked for key press event.  The event pointer is then cast to a QKeyEvent so that the specifics of the key press event can be checked starting with if it contains the Return key.  Since the Enter key on the numeric keypad is received as a different code, both the Return and Enter values are checked for.  Finally the keyboard modifiers (Control, Shift, Alt, etc.) of the key press event is checked for a control modifier. 

The Control+Return key needs to be changed to a regular Return to allow the new line insertion to take place, but the key event can't be modified and passed on.  Instead, a new key press event is created for a unmodified Return key and this new event is posted by calling the QApplication::postEvent() static function with the edit box instance pointer (this) for the new event.  A true is returned to indicate that the Control+Return key event has been processed.  If the event was not a key press Control+Return event, the event is passed through to the regular event filter by calling QTextEdit::eventFilter().

[commit cb32f9ab0e]

Tuesday, January 22, 2013

Cross-Platform Fixed Width Font

There are several solutions for setting the font in the edit box to a fixed width font, but a cross-platform solution was needed.  One solution would be to use a font that is available on both Windows and Linux, for example Courier, but this is not the best looking font, though it is one of the few available on Windows.  My current preferred fixed width font is Monospace, but this font is not available on Windows.  Attempting to set this font had no effect on Windows, and the default proportional font was used.

After some research, the correct sequence was found to select the Monospace font on Linux and to select an alternate fixed width font on Windows.  First the current font is obtained from the QTextEdit base class.  The font is set to fixed pitch to indicate the type of font desired if the selected font family is not found.  The font family is set to the "Monospace" string and the style hint is set to Monospace.  Finally the current font is set to this modified font.  This code was put into the EditBox constructor:
QFont font = currentFont();
font.setFixedPitch(true);
font.setFamily("Monospace");
font.setStyleHint(QFont::Monospace);
setCurrentFont(font);
On Windows (XP, 7 and 8), this appears to select the Courier New font at a fairly small 8 point font, which doesn't look so good on XP, but better on 7 and 8.  The size of the Monospace font on Linux also looks to be an 8 point font.  This is good enough for the now and eventually a font selection dialog will be added so that any font and size can be selected.

[commit 7155b30097]

Monday, January 21, 2013

Minor Fix

While testing the tagged download archive for release 0.3.1, a warning message from Qt occurred indicating that the window title did not contain a '[*]' placeholder.  This was caused by the application loading the last opened file, after which the window modified flag is cleared.  This triggers Qt to update the window title, which was not set yet, hence the warning message.

This warning did not occur if a file was specified on the command line.  If the application was started with no prior loaded file or recent list, this message also did not occur, but the window title was set to "MainWindow" instead of the correct "Untitled - IBCP" title.

The warning did not occur if the file was specified on the command line because the code called the set current program function with the file specified, which set the window title before the file was loaded.  The solution was to also call the set current program function if no file was specified on the command with the current program member variable value, which solved both the warning message problem and the "MainWindow" title problem.

[commit 6410a5318e]

Edit Box For Program Entry

Now that some additional GUI has been implemented, it is time to start to work on the edit box to make it more appropriate for editing a program and not just text.  The immediate goal is to accept BASIC code that is currently recognized by the parser and translator, parse and translate it and display the translation in a dock widget beside the edit box.  (A dock widget is a widget that can be moved or docked to any side of the application window or detached completely from the window.)

For an incremental compiler, the application will need to know when a line has been edited (when the user leaves a modified line) so that the line can be recompiled (for now translated), which could be several lines (by a deletion when multiple lines were selected, or a paste of several lines).  Also, the font of the edit box needs to be changed to a fixed width font and there needs to be a way to add color, for example, indicating errors and syntax highlighting of BASIC keywords and other program elements.

As seen so far, this will be accomplished with the text cursor that is part of the QTextEdit's document.  The document part of QTextEdit is one continuous string of characters, but there is a way to retrieve and replace individual lines within the document.  All this needs to be figured out, which will take place over the next several commits.

But first, with additional GUI implemented and working, this is a good place to tag for v0.3.1.  The various files (CMake, read me and release notes) were updated for this development release.

[commit a938626ffc]

GUI – Pasting Plain Text

By default, the QTextEdit class that EditBox is derived from accepts rich text (formatted text).  The solution for this matter was simply to call the setAcceptRichText() function with false as the argument to prevent pasting rich text.  This call was added to the constructor of EditBox.

While adding this to the constructor, it was noticed that the EditBox class was essentially empty, deriving from QTextEdit adding no new functionality.  The delete and select all action functions in MainWindow did more that just call a functions in edit box, so this code was moved to new functions in EditBox.  Since delete is a reserved name, the delete text function was named remove().

[commit 4050620cae]

Sunday, January 20, 2013

GUI – Edit Actions – Tool Bar

Adding the actions (icons) to the tool bar was simply a matter of dragging the actions from the Action Editor at the bottom of Designer to the tool bar.  Separators were added between the file actions and the cut, copy, paste and delete actions and the undo and redo actions.

While testing the edit actions, it was noticed that the edit box currently accepts formatted text with the paste action (for example, copying an italicized word from a word processor and pasting it into the program).  This will be corrected in the next commit.

[commit 24c21711b9]

GUI – Edit Actions - Enabling

For enabling the undo and redo actions, there are signals from the edit box (derived from the QTextEdit class) when the undo or redo availability changes.  Likewise, there is a signal for when the copy selection availability changes.  The undo, redo, cut, copy and delete actions were set to disabled in Designer.

The edit box's undo and redo signals are connected to the undo and redo set enabled slot respectively.  When an undo or redo is available, this signal is emitted to the action with a true value, which enables the action.  Likewise when an undo or redo is no longer available, this signal is emitted to the action with a false value, which disables the action.

The edit box's copy available signal is connected to the cut, copy and delete set enabled slot.  The copy available simply means that text has been selected, which can then be copied, but also cut or deleted.

[commit d9a3f3b0b7]

GUI – Edit Menu - Actions

The edit box already has a context (right-click) menu with Undo, Redo, Cut, Copy, Paste, Delete and Select All.  Applications customarily also have these same actions on the Edit menu and on the tool bar.  These actions were created in Designer after adding the Edit menu and adding each of these edit actions.  Once the actions were created, each was edited to add an icon, shortcut key and status tip.

The slot functions for each action was implemented in the MainWindow class with the names on_actionName_triggered so that these would automatically be connected to the actions.  The implementation of most of these functions was a single line that calls the appropriate member function of the EditBox instance (undo, redo, cut, copy, and paste).  The delete and select all actions required slightly different handling.

For delete, there is no function to delete the currently selected text in the QTextEdit class that EditBox is derived from.  The QTextCursor member of QTextEdit, which controls the cursor and selection of QTextEdit, must be used.  The textCursor() access function is used to obtain the text cursor of EditBox.  For deleting the current selected, the removeSelectText() function of QTextCursor is called:
m_editBox->textCursor().removeSelectedText();
The select all action required a little more handling.  The QTextCursor has a way of selecting text by using the select() function with an argument to specify what to select, with QTextCursor::Document being the option for selecting all of the text.  However, the select() function can't be called directly using the textCursor() access function like with delete because the selection doesn't get back to the document inside the edit box.  Instead, the text cursor needs to be obtained, the selection made and the text cursor put back with the setTextCursor() access function:
QTextCursor textCursor = m_editBox->textCursor();
textCursor.select(QTextCursor::Document);
m_editBox->setTextCursor(textCursor);
Additional functionality is required to enable and disable these actions when appropriate.  For example, cut and copy should only be enabled if text is currently selected.  The context menu already works like this.  This functionality will be the subject of the next commit.

[commit d8c2933481]

GUI – Recent Files List – Status Tips

I realized that no status tips were given to the open recent menu actions.  Therefore a status tip was added for the Clear Recent List action in Designer.  Sub-menu actions can not be given status tips (they can be assigned, but they don't show up when hovering over the sub-menu because the sub-menu is opened).

Status tips were also assigned to each of the open recent file actions added to the sub-menu with a string that simply says "Open" followed by the full path of the file name.

The code was also changed to use the QstringList::at() function to access the files in the file list member variable instead of using the [] operator.  The reason is that the at() function is more efficient because the [] operator returns a modifiable reference to the item (an lvalue), where as the at() function just returns a reference (an rvalue).

[commit 858bbe1e28]

GUI – Current Directory

While the application is running, it will remember the directory of the last file loaded so when the open file dialog is displayed again, that directory will be the starting directory.  This application's current working directory is updated by the open file dialog after a file is selected.  A "." for the current directory is used as the starting directory passed to the open file dialog box, so when the application is restarted, the current directory starts back to where the application was started from.  The application should remember the last directory when restarted.

To have the application remember the last directory, a new current directory member variable was added to the MainWindow class.  After a new file is loaded from the Open menu action, the directory of the file path is saved in this variable.  This variable is then saved as part of the application settings and restored when the application is started.

As was done for the restore and save settings for the RecentFiles source file, the names of the settings were put into constant character strings so that the strings are not specified in two different places (the restore and save functions) to prevent the possibility of a mistake in the name between the two functions, which would cause a setting to not be restored properly.

[commit 04c28a8252]

Saturday, January 19, 2013

GUI – Recent Files List

The next GUI feature implemented is a recent programs list, which consists of a new Open Recent sub-menu item on the File menu below the Open menu item.  This sub-menu contains a list of recent programs along with a separator and a Clear Recent List menu item.  The Open Recent menu item is disabled if there are not recent files.  Files are added to the recent list when opened or when the Save As... menu item is used.

New files are inserted at the top of the list, pushing older programs down the list.  Currently only 4 programs are listed in the list (this will be made configurable later), but up to a  maximum of 10 recent programs are kept in the list.  When a new program is added to the list, any existing entry of the program in the list is removed first and any files above the maximum count are removed.

A new RecentFiles class was implemented to maintain this list of recent files and the Open Recent sub-menu actions.  When instanced, the open recent file actions are created for the maximum number of files, sets each to invisible, sets its icon to the file open icon and connects their triggered signal to an open file slot (which does not occur automatically like when menu actions are added in Designer).  The open recent file actions are inserted before the first existing action in the menu, which is assumed to contain a separator and the Clear Recent List actions (added in Designer).

The RecentFiles class contains public functions for adding a file to the recent list, clearing the list, restoring the list (and count) from the saved application settings, and saving the list (and count) to the application settings.  When one of the recent file menu actions is triggered, an open file signal is emitted.  When MainWindow instances this class, it connects this signal to a new program open slot function.

The RecentFiles class contains two private support functions.  One to update the actions on the sub-menu list, which first removes any files in the list that don't exist, and then scans the list setting the open recent file menu action's text and data to the base name of the file path and its full path, and makes it visible.  Any actions above the current count or the number of files present are set invisible.  The second is a simple support function for returning the base file name of a path.

[commit bf8cda57eb]

Tuesday, January 1, 2013

GUI – Program File Argument

The next feature added is the ability to specify a program file to load on the command line.  This is specifically to support integrating the application with the OS where files with a certain extension can be associated with the application.

The CommandLine class was modified to look for a single argument that does not begin with a "-" option character if none of the other expected options were found.  This argument is stored into a new file name member variable, which has an access function to get its value.  The usage help message was updated for the new argument.

The MainWindow constructor was modified to check if the file name from the CommandLine instance is not empty.  If it is not empty, then the current program is set to this file name overriding any in the saved settings.  If this program doesn't exist or there is an error loading the program, then the application starts up blank but with the current program name set to the file specified instead of being Untitled.

[commit c8f48aa9d5]

GUI – Save Current Program

Now, that the basic GUI elements are in place, some additional features will be added before beginning work in changing the edit box from a simple text editor into a program editor.  The first feature to add is to have the application save the program file path name that was loaded the last time it was run.  This involves saving the current program path as part of the saved settings.

When the settings are restored, the set current program helper function is called with the restored program name.  The current program member variable can't be set directly because the window title does not get set and a warning message is issued by the Qt routines that there is no '[*]' placeholder in the window title when the program is loaded.  When the program is loaded into the edit box, a document modified signal is sent to the set window modified slot, when then attempts to set the modified flag, but placeholder has not yet been set in the window title.  The helper function takes care of this.

Once the edit box instance has been created, the constructor checks if the current program is not empty.  It then checks if the program file still exists, otherwise the file was either deleted or moved since the last run, so the current program path is cleared.  Also, if there is an error loading the program file, the current program path is cleared.

[commit dd489476cc]

Base GUI Complete

All the basic GUI elements have now been added, so this is a good place to tag the release, which was tagged with the name v0.3.0.  The various files (license, read me, release notes, etc.) were updated for this development release.

It was also noticed the about box (nor the test output) contained the full GPL statement, only the copyright and warranty statements.  The CommandLine class was updated to reflect this, but the test output was not changed so that the regression tests continue to pass.  The About box was updated to contain the full GPL statement along with the required Oxygen icons license statement and web links.

The original release numbering is again being used.  While Git did sort the tags as desired with the '-' developmental release before the '.' official release (so v0.2.0 will be listed after v0.2-6); GitHub (on the tags page) appears to only look at the numbers ignoring the separator characters, so v0.2.0 is sorted before v0.2-1 instead of after v0.2-6, which could be very confusing even though a fuzzy time of the release is listed, it's not obvious, and there is no way to sort by this time.

Since all 0.x releases are development releases, there is no reason to have development development releases.  For now on, only the last one of the development release series will be uploaded to Sourceforge, whatever is release number is at that point.  The source code of the others can be downloaded as archives from GitHub on the tags page.  The release number for any patches needed for an official release will simply increment the last (patch) number and re-uploaded.

[commit 4f0378e72c]

Monday, December 31, 2012

GUI – Icons and Tool Bar

Now that the resource mechanism has been added to the project, actions can now be added to the tool bar with appropriate icons.  Contrary to what was said at the beginning of the last post, tool bar items can be text and are text if no icon has been assigned to them.  In any case, icons will be used here for the tool bar.  Also, when an action has an assigned icon, the icon also appears on the menu item in the menus.

First icons need to be assigned to the actions.  The easiest way to do this is with Designer inside QtCreator.  The icons can be assigned the same as with the MainWindow object, but it is easier to add the icons from the Action Editor tab at the bottom of Designer.  Double-clicking on the action brings up the Edit Action dialog.  The icon is added by clicking the ... button on the Icon: field line.  Appropriate icons were added to all of the actions.  To add the actions to the tool bar, the actions are simply dragged from the Action Editor to the tool bar.

Note: The icons will not be available on the
Select Resource dialog until the program has been built after the icons have been added to the resource file.

The icons were obtained from the KDE Oxygen icon set (found in the /usr/share/icons/oxygen/32x32/actions/ directory on Linux) except for the Qt icon, which was obtained from the Qt SDK.  All of the icon file names were renamed to match the menu and menu item the icon was assigned to.  The Oxygen icons can be distributed with the source code and embedded within the program as long as the program is under the LGPL (Lesser GNU Pulbic License) version 3, which this program is being developed under.

[commit a2d2675627]

GUI – Icons and Resources

The next item for the GUI is to add items to the tool bar, which has already been created, but is currently only blank.  Unlike the menu items which are text, the tool bar items are icons.  It is convenient if the icons are part of the application file and not separate files that must be included to run and must be loaded by the application.

This is accomplished by converting the icon files into C++ source files that are then compiled and linked into the application.  The Qt Resource Compiler (RCC) is used to convert the icon files to source files.  All the resources for the program are listed in an XML resource (.qrc) file.  QtCreator makes it easy to create and maintain these resource files.

To create the resource file, the new file wizard was again utilized.  Under Files and Classes the Qt item (lower-left) and Qt Resource file (upper-right) was selected.  On the next Choose the Location dialog, the Name: field was set to ibcp.qrc.  On the next Project Management dialog, the defaults were selected (which was set to git).  Once finished, QtCreator opened up a specific resources editing window.

To start simple, an application icon was given to the program, which will appear in the upper corner of the application window and on the task bar of the OS.  Up to now, a generic icon was being used (an X icon on Linux/KDE and a generic program icon on Windows).  An icon file was created by the name ibcp.png and placed in the new images sub-directory.  The image chosen and created consists of two lightning bolts, which represents the letter I, two to represent Interactive and Incremental, for the type of BASIC compiler being created.  The lightning bolt itself represents speed, since the goal of this project is to make a fast interactive BASIC compiler.

To add this new icon to the resource file, the Add button at the bottom resource editing window was clicked and Add Prefix was selected.  The Prefix: field, which defaulted to /new/prefix1 was cleared (which set it to a single slash).  The Add/Add Files was then selected, which opened a file selection dialog.  The images/ibcp.png file was selected, which added the file to the resource list.

To assign this icon file to the application, in Designer, the MainWindow object was selected (upper-right panel) and under properties (lower-right panel), the ... button was clicked for the windowIcon property, which displayed a Select Resource dialog.  The images item (left-side) was selected, which displayed the ibcp.png icon (right-side), which was selected.

To finish, the building of the resources needed to be added to the CMake build file.  Resources are handled by the qt4_add_resources command that is added as part of the Qt4 CMake module.  This command is given a list of resource files (in this case ibcp.qrc) and produces a list of resource source files that are generated by RCC.  This list of generated source files was then added to the add_executable command.

[commit ba9ee1be2a]