I‘ve not written a while about programming, let alone anything about that mailing program, RoundAbout. Today’s subject is the Windows TreeView control and its data section, the TreeNodes. As you probably know, a TreeView shows data in an hierarchical way, allowing users to ‘expand’ or ‘close’ so-called TreeNodes, so to expose or hide data they do and don’t want to see. TreeNodes in the Windows world can have user-data attached to it and often, developers will use this to store program specific information. I believe in .Net, this data propery is called ‘Tag': in the Delphi world, it was called plainly ‘Data’. So code-wise this could look like this:
var Node: TTreeNode;
/* FolderData is a pointer to a record */
Node := TreeView.Items.AddChild(Node, FolderData^.Name);
/* Attach the FolderData to the current node */
Node.Data := FolderData;
Early in the process of development, it was noticed that any font or even layout changes caused severe crashes in the TreeView: The TreeView in RoundAbout holds account and message/mail folder information via each TreeNode’s Data member. After a long investigation, I noticed that this was caused by the Delphi TreeView control itself: whenever a window anywhere was refreshed, Windows would send a message to the TreeView control to refresh and recreate itself. Let me say that again: whenever a font was changed in RoundAbout, this would trigger any TreeView to recreate itself. I think this issue was resolved in later versions of Delphi, but I decided to create my own control (PMTreeView, code here) to preserve the data with the following premises:
- Override CreateWnd and DestroyWnd
- Upon destruction of the treeview window, save the data for the nodes to a memorystream.
- Upon creation of the treeview window, (if available) load the node data from the memorystream.
- Trigger an event to notify the developer that the Data structure has changed for further activities.
As I mentioned earlier, I believe in subsequent Delphi versions, Borland fixed this in their own TreeView controls. However, for a piece of code that I debugged and coded in a night or so, my own PMTreeView control wasn’t too bad of an implementation.
Staying on the programming topic: One of the best parts of Roundabout (previously) was the filtering mechanism: before mail was downloaded, the user could (if needed) invoke the Filter dialog box and mark which mails were going to be downloaded (or left/deleted on the server). This happened all in a thread, where connections to SMTP and POP servers were made and commands were issued, synchronously (“blocking”, so you will). The threading class that took care of this was (appropriately) named ‘TOnlineThread’ and resided in a file called TDOnline.pas.
Many times I’ve cursed the existing threading code: I spent plenty of hours fixing up the code, or rather making the code thread-safe, as in, wrapping code that calls the main-thread (the UI thread) in so-called ‘Synchronizers’. Looking through the current code, there were plenty of changes done to this unit (the CVS history only spans a short time and doesn’t count the changes made prior to January of 2005). Anyway, if memory serves well, there were issues during the sending of mail (which happened in that thread) and the update (count of left-over messages) in a mailbox (which resided on the main UI thread) and I ended up correcting the issue, soberly stating:
- FIX (Arthur): Threadsafe RefreshNodes in TDOnline + additional processing…
Which was followed by a more cryptic:
- FIX (Arthur): Sharpened the RefreshNodes/Tree traversal.
Before you click the ‘Continue’ link, you may want to have this link at your disposal, which may explain the whole gimmick below.
I was looking for older code through some older projects and I ended up looking at the code of RoundAbout, a Delphi project I headed with a German (Roland), an American (Marcos) and plenty of other contributors. I thought, I might just as well make this an opportunity to breathe new life into this specific category: There is some exciting and funny code in the project and I wouldn’t do the project good by not showing the effort to collectively create something good out of nothing.
But first: In the early 2000s I ended up looking for an e-mail client for Windows. For years I had been using Eudora, but, I got a bit tired of looking at the ads that Qualcomm pushed upon users. I initially looked at Phoenix Mail, an e-mailer initially programmed by Michael Haller which in turn was passed on to American Delphi developers. Via that mailing-list I discovered Roland’s excellent modernized branch and, as any good open-source branch, I ended up branching his version into RoundAbout because we couldn’t agree on many issues: I believed in going more in-depth (technically speaking) while Roland was more or less adopting a wait-and-see, conservative approach. Both approaches had their successes, and both our branches had attracted a variety of Delphi luminaries and dignitaries (I’m looking at you Duntemann), including offers of help from the original Phoenix Mail branch. In 2004, RoundAbout was left for what it was and like many open-source projects, it died a silent dead. However, without doubt, its code continues to live on in the original branch(es) or is probably floating around on the Internets. I wouldn’t recommend people to try the e-mailer nowadays: it works fine but might look odd on Windows XP and higher.
This brings me to the first piece of code I’d like to point at, which is the ability of adding or dynamically creating toolbars and toolbar buttons: It was heavily pushed by Marcos and it required so many code changes, that I ended up taking the challenge, provided that:
It is possible to create new toolbars and buttons: however, the maximum of toolbars should be 255, the maximum of total buttons (application wide) are 65,5xxx (the number that fits in a word).
I mean, 65 thousand and some buttons should be enough for everybody, right?