A few bugs were reported on the last build, which have now been promptly fixed. I have also updated our to-do list so that everyone knows where we are with regards to the first beta release. It might look much, but keep in mind that most of these task take 1 hour tops each. Only the most elaborate tasks will take longer.
Note: This post is 3 days late. I came down with a nasty cold on thursday and pretty much spent the entire weekend in bed. A national holiday started on monday, and it was my time to take the kids on a trip. So it’s been a less than productive weekend, but that’s just how it has to be. I always make up for lost time.
Ok, let’s go through the tasks for this build.
Bugfix list
- A bug where starting two instances of the IDE caused the latter to throw an access violation
- A strange case where the resize grab-handles for a selected widget suddenly would not render
- The caption property was not set on windows (TQTXWindow) in windowed projects. This turned out to be quite critical
- Windowed project file was missing the {$I “app::form.init”} compiler injection point, meaning that forms would not be automatically created. Instead the windowed default project operated with code that created windows manually
Multiple instances of the IDE
It was suggested that we use a Mutex to make sure only one instance of the IDE is running. However, the IDE should be able to run in multiple instances by design. The reason for this is because it simplifies writing client / server solutions on the same machine.
The IDE is initially designed to handle multiple projects simultaneously, but to save time I decided to push that feature into the future. It’s not a critical thing at this point. Not as critical as getting the first version out the door in good condition is.
Log4Delphi
When inspecting what caused the problem I discovered that it was in fact the logging system that was the first culprit. We use Log4Delphi which is a 1:1 conversion of Log4Java. All in all a very simple system that I could have written better myself, but again – time is a factor here since we are overdue by almost 2 months. Hence I just picked a ready to use logging system that we could use without much hassle.
Turns out that Log4Delphi opens a permanent filestream without any sharing flags (meaning that it locks the file for read and write access by other processes). Since the Log4Delphi is open-source I simply went in and added the fmShareDenyNone if the log is opened in either fmOpenRead or fmOpenWrite modes.
I decided to make it more bullet-proof, so I implemented a filename function that generates a filename based on date and time. This ensures that two instances will never try to own the same file – at the cost of each IDE operating with separate logfiles. Not a huge deal I feel, since the logfile is not a permanent fixture – we will be logging to standard WinAPI after the release candidate.
TZipfile and packages
The next culprit that prevented multiple instances to run was the package loader. Quartex Pascal uses ordinary zip-files as the package format. Zip-files are almost universal and natively supported by Windows, so using that for packages makes a lot of sense. This way developers can easily create package-files for their components ready for distribution.
The problem was, again, that TZipFile’s Open() method does add the fmShareDenyNone flag, effectively locking the package for the entire IDE session. Since TZipFile is a part of the Delphi RTL I can’t simply copy the code and change it to better suit our needs. But as luck would have it there was an overload for Open() that takes a TStream. So I just modified the Zipfile filesystem driver to open the package file via a TFileStream with fmShareDenyWrite flag (allowing reading but refusing other processes to write to the file).
With this change, you can now run multiple instances of the IDE without problems.
Form designer grab handles
Before the previous release I more or less re-coded the selection logic for our form-editor. A form editor that supports the features we do is not easy to write, especially since the widgets are not Delphi TCustomControl’s (like most other designers operate with), but are drawn and represented purely via TCanvas.
The code had reached a level of complexity where, if we continued, it would have grown into a spectacular mess. So I decided to refactor the entire selection system, which is spread out over the 3 common mouse handling methods (mousedown, mousemove and mouseup).
For some reason I had forgotten to create the TProxyResizeIndicators instance in the selection situation code (all actions you can do like select a single widget, multiple select, add or remove from a selection — these all make up specific “situations” that the designer must check for and respond to). I also needed a call to __ImmediateRedraw(). Once these were in place, the resize-bars were back as they should be.
The missing caption
When I implemented the code for the last build I was quite tired, but how I managed to miss this puzzles me. The codegen that converts the prototype (a “prototype” is an object that contains all the published properties for widget. The IDE scans each widget when it boots, and whenever you drop a widget on a form, it clones out the properties that the inspector can work with) for a widget into code at compile-time, a process which is recursive and has zero room for errors.
For some strange reason the TViewImplementationCodegen was missing a call to EmitPropertiesFor() where the properties for the form was generated for the TQTXForm or TQTXWindow itself. This is obviously due to the fact that we waited with that part of the RTL until we had delegates added to the codegen.
It is a good thing we noticed this, because the code was only emitting properties like width, height and name. This meant that the Caption property was effectively never set! It would also mean that none of the other properties would be generated. A bit sloppy, but the code we are talking about here is very dense. Recursive code on this level is easy to get wrong, believe you me. You have to take account for every situation, and distinguish between subtle differences.
For example, if the project is of type dynamic, the height property should never be written (otherwise the page would have fixed sizes on the content and not scale). Windowed projects are different and must have width, height etc. set early in the constructor code — so there are a lot of levels to this type of code.
Updates the Windowed project template
The code for windowed projects is old and was written just before we got delegates into the mix. At that time the IDE did not recognize TQTXWindow as a form, and would only deal with TQTXForm. As such the windowed project type would have code to manually create a TQTXWindow, and there was no DFM file to house the design – and consequently no way for the IDE to automatically create windows added to the program.
This has now been updated and the new windowed application type works exactly like a normal dynamic project.
What is left before we can enter beta?
There are quite a few minor additions and changes we have to implement before we go into beta. The “bugs” above are good examples of smaller tasks that can be found here and there throughout the codebase. Nothing critical or overly complex, but they have to be dealt with.
Right now I am operating with the following task list:
- Delegate event code. When you double click on a delegate the IDE should either inject the event handler (like Delphi does) if it does not exist, and consequently switch to the code-tab and goto the procedure.
- Delegate add dialog. The “new delegate” must have a name-field and also be simplified, right now the design makes little sense.
- Delegate edit dialog. This is essentially the same dialog as above, but without the code for adding anything, it should be edit only, allowing you to change the delegate class-type and name. This is more elaborate since it also requires the form code to be changed automatically by the IDE.
- The TRagnarokProtocolImplementationCodegen class must be completed. Right now the codegen for ragnarok protocols emits the interface, but not the implementation. Again this type of code can be complex due to its recursive native, but I estimate a full work-day to get it done and ready for testing.
- Ragnarok project types: we need to make it easy to create ragnarok based projects. This includes node.js servers, node.js system service, dynamic and windowed client. Ragnarok does not impose itself, so you can add a protocol to any project and the IDE will spit out the code for it, but having ready to rock project types will make it easier to get to grips with.
- The preferences dialog has a lot of options that must be finished. Also, the layout needs a refactoring, especially for the SynEdit color palette stuff. It is less than intuitive.
- The HTML dialog must be refactored. Right now we are using the default HTMLComponents editor with toolbars, and the toolbars dont really work well in a dialog form. A traditional toolbar must be implemented. This should not take long since all toolbar features are isolated as TActions
- The IDE must have dialogs for all supported dialog types (around 10), right now we have 2. Thankfully a lot of this is boilerplate and functionality is largely displaying options and writing them to the widget prototype
- TQTXMainMenu editor. Not critical but I think this is a very important feature. Being able to create windowed applications easily for HTML5, mobile, embedded etc. requires a good menu editor. We might push this to version 1.1 is we dont have time.
- Probably 100 little things and tweaks, but thankfully nothing fancy or huge, one-liners mostly and smaller graphical adjustments.
As always, the latest build will be available on Patreon and for our backers on Facebook in Quartex Developer.