Sunday, January 20, 2013

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]

Sunday, December 30, 2012

GUI – Status Bar

The status bar on the bottom of the window was already automatically created when the MainWindow class was created from the new file wizard and is already being used for the menu item status tips.  Eventually program information like current line and column will be displayed on the status line along with error messages.  But for now there are a few places where messages are needed for the file operation functions, specifically when the program has been loaded or saved successfully.

[commit ea1b7585bb]

GUI – File Operations - Functions

A couple of helper functions were implemented to support the file operation functions.  The first is a function check if it is okay to continue, which checks if the file has been modified and if it has, ask if the file should be saved or the operation canceled.  This check is needed on the new, open and close program functions.

The second helper function sets a new member variable that holds the current program file path and sets the window title to the base file name of the current program file path.  The window title is set to the string "<file name>[*] ‑ IBCP" where the [*] is a placeholder for whether the file has been modified.  Qt handles this in a platform specific way.  Qt handles this in a platform specific way.  Generally on Windows and Linux, it  simple puts an asterisk after the file name, but on MAC, a dot is put in the close bubble.  If the program file path is blank, the program name is set to the "Untitled" string.

In the main window constructor, a connection was added to the edit box document's modification changed signal to the main windows set window modified slot.  Whenever the document is modified, this signal causes the file modified indicator to appear.

Two support functions were also implemented that load and save the program into or from memory, though right now they simply read and write a text file to or from the edit box document as plain text.  Eventually when a program is loaded, it will need to be parsed, translated, encoded and stored in memory.  Details of the main file operation functions can be found by clicking Continue...

[commit ea1b7585bb]

Actions/Menus – Using Designer

I discovered a much better and easier way to create actions and menus for the application without having to write all the lines of code by using Designer within QtCreator.  The UI form for the main window is opened in Designer by double-clicking on mainwindow.ui from the project files area.

Main menus are added by double-clicking on the "Type Here" text at the top of the edit area and entering the text.  Hot keys are entered by preceding the desired character with an '&' ampersand character.  The menus can be repositioned by dragging them as desired.

Menu items are added is a similar way, by selecting the main menu and again double-clicking the "Type Here" text.  Separators are added by double-clicking the "Add Separator" text.  Status tips are entered in the statusTip field on the lower-right side properties after selecting the desired action from the upper-right side object tree list.  Shortcut keys can be entered in the shortcut field in the properties area or can be entered using the Action Editor tab at the bottom of Designer.

Designer automatically names the actions with the name "actionXxx" where Xxx is the text entered for the menu item.  The under-bar character is used for spaces, so these were removed to follow the camel casing naming convention.  Qt will make connections between actions and functions automatically if the functions are named correctly.  For the menu item actions, the functions are named on_actionXxx_triggered() where actionXxx is the name of the action and triggered is the name of the signal to connect.  All of the dummy program functions were renamed to this form so that the needed connections are made automatically.

However, this does not work for connecting the actionExit triggered signal to the MainWindow::close() function, since this does not follow the automatic naming convention.  This was accomplished by using Signal & Slots Editor tab at the bottom of Designer.  A new signal/slot is added by clicking the large plus icon.  For this new entry, the Sender was set to actionExit, the Signal was set to triggered(), the Receiver was set to MainWindow, and the Slot was set to close().

The actionAboutQt action could not be setup in Designer since there is no way to connect to the application's aboutQt() function using the Signal & Slots Editor because the application object is not an available Receiver.  This was instead accomplished by adding a new on_actionAboutQt_triggered() function to MainWindow, which simply calls qApp‑>aboutQt().

Now that all the actions and menus are in the UI form for MainWindow, the action enumeration, action pointers and menu pointers were removed from the class definition.  The pointers are now contained in the Ui::MainWindow class that is automatically generated from the mainwindow.ui form file by the UIC (Qt User-Interface Compiler), which MainWindow contains a member pointer to.  Since the setupUi() function, called in the constructor, now creates the actions and sets up the menus, the createActions() and createMenus() functions are no longer needed and were removed.

[commit 46737de13d]

GUI – File Operations - Actions

To start, the EditBox will be made to handle simple text files.  Once the base GUI functionality is implemented, the process of implementing a full program editor will commence .  The first file operations to implement are new, open, save, and save as.

To create an action, several lines of code are needed, plus there needs to be a QAction pointer added to the class definition for each.  The program is going to end up with a lot of actions, so a more streamlined way of handling actions was needed.

In the MainWindow class definition, an enumeration for all actions was added.  Values will be added to this enumeration for each new action implemented.  The enumeration ends with a size of value, which is used to declare an array of QAction pointers.

In the createActions() function, a simple action information structure was added containing the action enumeration value, the name, the shortcut key sequence and the status tip string of the action.  An array of these action information structures is declared and initialized.  The size of enumeration value in the action value is used to indicate the end of the array.

A loop was added to process each element in this array, creating the QAction instance, setting its shortcut key sequence and status tip.  Not all actions will have a shortcut key sequence, so for these, the key sequence is initialized to an unknown value and no key sequence will not be set for these.

Finally all the actions are connected to their associated functions.  Unfortunately, the connection call could not be included in the loop because of the Qt SIGNAL and SLOT macros and the inability to declare a function pointer that could be added to the information array.  Plus, not all connection calls are identical (the close function returns a boolean instead of nothing and the About Qt action is connected to an application function, not a MainWindow function).  For now only dummy file operation functions were added - these will be implemented next.

[commit 8958bacc2e]

Saturday, December 29, 2012

GUI – Edit Box (Begin)

To create the new EditBox class source and header file, the new file wizard of QtCreator was again used (New File or Project... under the File menu). Under File and Classes the C++ option was selected and then C++ Class was selected to create both files and Choose... was clicked.

On the next C++ Class Wizard dialog, the Class name: was set to EditBox, Base class: was set to QTextEdit and for Type information: the Inherits QWidget option was selected.  The rest were left to the filled in defaults.  On the final Project Management dialog, git was selected to add to version control and the wizard was finished.

For now, nothing was changed in the created editbox.h and editbox.cpp files except the customary comment headers were added and the formatting was corrected to match the style of the rest of the project files.  Functionality for the EditBox class will be implemented in the commits that follow.  The sources files were also added to the CMake build file, and because the EditBox class contains QOBJECT, the editbox.h file was added to the MOC sources instead of the header files variable.

A new EditBox member pointer was added to the MainWindow class.  In the MainWindow constructor, an EditBox instance was created.  There is no need to give it a parent here because the next call to setCentralWidget() does this automatically, and makes the edit box widget the main widget of the main window.  This also means that for new there is no need to delete the EditBox instance because Qt will do this when the MainWindow instance is deleted upon the program closing.

Eventually this basic mechanism of how the single EditBox instance is maintained will change since there will be a need to have multiple edit boxes open (the plan is that subroutines and functions will be contained in their own edit boxes).  The exact interface hasn't been designed or decided yet (split windows, tabs, multiple windows, etc. are all possibilities).

[commit de0ec4eb2b]

C++ Explicit Constructors

The new EditBox class was created using QtCreator's new class wizard and I noticed that it put the explicit keyword in front of the constructor definition (it also did this with the MainWindow class).  (More about the new EditBox class in the post.)  Curious what this keyword does (which was added since I learned C++ in the early 90's), I did some research.  The explicit keyword tells the compiler not to allow implicit type conversions on constructors that take a single argument.  Consider this partial example:
class MyFloat {
    float m_value;
public:
    MyFloat(int value): m_value(value) {}
    float value(void) { return m_value; }
};

float square(MyFloat myFloat) {
    return myFloat.value() * myFloat.value();
}

MyFloat something = 47;
std::cout << square(12) << std::endl;
On the last two lines, implicit conversions occur from int to MyFloat, which are perfectly acceptable  for this simple class.  However, if the implicit conversion was not desired, the explicit keyword can be added in front of the constructor to prevent it.  The compiler will now generate errors for the last two lines above.  These lines can be rewritten to work:
MyFloat something = MyFloat(47);
std::cout << square(MyFloat(12)) << std::endl;
This is a contrived example and would probably make sense to allow the implicit conversion in this class, however, this is not the case with the classes used in this project.  Therefore, the explicit keyword was added to all the constructors that take a single argument, which included the CommandLine, Parser, Tester, Token and Translator classes.

The most glaring constructor requiring explicit was the Token constructor Token(int column = -1) that would have allowed a statement like Token token = 47;, which does not make sense (a token should not be assigned an integer).

[commit 5979939788]

Sunday, December 16, 2012

GUI – Settings and Window Title

All programs should save all of their settings upon exit and restore them so that when restarted the program starts up in exactly the way it was when it exited, because otherwise it is time consuming to set all the settings again.  Very few programs do however, but this approach will be used for this project.

Fortunately, Qt has the QSettings class to perform the saving and restoring mostly automatically.  The vendor (programmer) name and program name is provided to the constructor of the QSettings instance.  For saving, the setValue() method function is used with the name of the property to save and the value to save.  When the instance goes out of scope, the settings are saved.  For restoring, the settings are automatically read when the instance is created.  The properties are accessed with the value() method function.

The settings are stored to a platform specific location.  On Windows, this is to the registry.  On Linux, this is to a text file located in the .config directory on the user's home directory within a sub-directory for the vendor name under another sub-directory for the program name.  The file name is the program name with the .conf extension.

The settings are restored in the MainWindow constructor.  For saving, the closeEvent() function was implemented.  This function is called when a close event occurs (for example, the File/Exit menu item, the close icon, etc.) and can decide whether to accept or reject the request.  For now, the settings are saved and the event is accepted.

For now, only the position and the size of the main window is saved and restored.  These are obtained from the geometry of the MainWindow instance.  The program will now remember where it was and how big the last time the program was closed.  Additional settings will be added as the are implemented in the program.

[commit 54a5b24f69]

Saturday, December 15, 2012

GUI – Initial Actions and Menu Items

The first thing to add to the GUI are some top level File and Help menus with menu entries under them.  Menu entries are added to each top level menu using actions.  Actions can also be added to the tool bar.  For now the File menu will contain an Exit entry and the Help menu will contain the About and About Qt entries.  A separator is added before the Help menu so that Qt knows to put this menu on the right side of the menu for those styles that support this (Windows does not do this and KDE only does this for certain application appearance styles).

Actions contain information including the name of the action (an ampersand '&' is put in front of the character that is the hot key for the entry), along with an optional shortcut key, icon, and a status tip.  No icons were added to any of the entries at this time.  A connection is made from the triggered signal of each action to the function that will perform the action.

All the actions are created in the createActions() function and the menus are created in the createMenus() function, both called from the MainWindow constructor.  The about() function was moved from the private section to the private slots section of the class definition so that the connection can be made from the about action.  The temporary show() function was removed since it is no longer needed.  The size of the header for program name in the About box was reduced to match the header size in the About Qt box.

Now the GUI will start, but doesn't do much beyond the menus (see image below).  The window still has the default name given when the MainWindow class was created and there is just a generic program icon.  There is also a blank tool bar under the menu bar.  The dot or two on the left side of the tool bar allows the bar to be dragged to any side of the window and even detached from window.  Icons (via actions) will be added to the tool bar later.


[commit 16e6755c0d]

Tuesday, December 11, 2012

Initial GUI Design Plan

A plan is needed for what form the GUI will take for the program initially, especially considering that only the translator and parser are implemented (and only for a limited number of BASIC commands).  The basic GUI will consist of a menu bar, tool bar, status bar and the main editing window.

This menu bar will probably only consist of the File, Edit and Help menus to start.  The File menu will start with New, Open, Save, Save As, and Quit entries.  The Edit menu will start with Copy, Cut, and Paste entries.  The Help menu will have About and About Qt entries (the about Qt is customary for Qt applications and shows information about the version of Qt used to build the program).  The initial tool bar will have buttons for items in the File and Edit menus.

Most of the effort for this initial GUI will be in the main editing window and getting it to work for the requirements needed for the interactive nature of the interactive compiler.  Namely, the code will need to catch when the enter key is hit so that the current line can be read from the editing box, compiled (translated and encoded) and stored in internal memory.  Eventually the line will need to be recreated from the internal representation back to the original text (or close to it).

Since only the translator is currently implemented, each line entered into the editing window will be translated to the RPN (reverse polish notation) list.  The tokens of the  RPN list will be converted to text (as now by the test code) and displayed in a special area in the GUI known as a dock widget.  A dock widget can be moved and docked to any side of the main editing window, and can also be undocked from the application window.  This dock widget will use to validate correct operation of the program.