You know how it is - you start work on one project and halfway through, you find one or two side-projects crop up that have to be solved before you can continue on the original project.

This is one such project with the added twist that it too started its life as a side-project. Here's what happened:

<Cue wavy screen effect>

I can only imagine that the planets must have been in (mis-)alignment or something, because at one point a few months ago, I was suddenly fielding emails on four or five separate articles I had previously submitted to CodeProject, some asking for features and others for bug fixes.

Foolishly or otherwise, I largely agreed with all the points raised, and subsequently found myself with fourteen or fifteen separate issues to resolve.

The situation was also made worse because I was trying to use CodeProject to keep track of all the things I had agreed to do, meaning that I had to continuously trawl the comments section of each article to remind myself of what I was supposed to be working on.

It even got to the stage where I was worrying that I'd fail to deliver on something - silly I know, but there you are!

Keeping a list on paper was a definite step in the right direction, but since I do all my coding on the same machine, it seemed somewhat inelegant, and anyway, we all know what happens to crucial bits of paper left lying around on desks and such.

The next step was to hunt around on the web for a tool to meet the following requirements:

Simple interface

Support for hierarchical data

Numbered items/subitems

Open file format

Freeware

Simple, huh! not!

I will admit that I did not spend weeks searching, but I am still surprised at the general lack of software matching my needs.

On reflection, I think that the reason may be simple: people are so used to commercial software being 'feature-rich' that when they come to design software themselves, they (not unreasonably) think they too need to cram as much in as possible, often leading to software where a lot of essential functionality is hidden away in the menu bar.

So, surprise, surprise, I decided to write something myself.

However, it's fair to say that I did not originally intend to post it on CodeProject and am only really doing so because I had a heap of fun solving some very interesting problems and these are what I think make it worth it.

Using the Software

There's really very little I need to say here since every feature/function is explicitly visible in the interface.

Nevertheless, the following list of basic capabilities and omissions may go someway to answering any questions that arise:

Files are stored in XML format with .xml file extension.

Trying to load a non-tasklist file will generally fail (unless you read the code to see how to circumvent it).

The number of items/subitems is limited only by memory (although performance may be the deciding factor before you exhaust memory).

Marking a parent item as 'done' will also gray-out child items, but they are not disabled or automatically marked as 'done'.

An ellipsis (...) indicates that an item has sub-items.

All items can be expanded or collapsed (by double-clicking).

Top-level items and sub-items are created using different toolbar buttons.

There are task-specific context-menus.

The previously open tasklists are re-opened on startup.

The tasklist is automatically saved when closing the software or minimizing it to the system tray.

The priority of a task is shown as a grayscale box to the left of the item.

Points of Interest

Here's where we come to the side-projects I was talking about, the first two of which I intend to work up into follow-up articles.

They are:

The 'ordered' tree control, which incorporates a non-client gutter for displaying the item numbers.

The idea stemmed from research I did into alternative designs for a tree-list control, which did not solve it by creating a hybrid control incorporating a tree and a list.

The hybrid control seems such an obvious solution that I suspect few people have stopped to question it, but it has still always struck me as looking far too much like hard work to be truly elegant ('square pegs' and 'round holes' spring to mind).

One possible idea is to implement the 'list' portion entirely in the non-client area of the tree. I.e., shift the right hand client edge to the left and then render the list portion in the resulting non-client area.

Whilst I've yet to get round to building a proof of concept, it was nevertheless this ongoing mental debate which prompted me to try to solve the requirement for numbered items and subitems by rendering the item/subitem numbers in the non-client area.

Without going into too much detail (as this will subsequently be an article of its own), this is how I got it to work:

Handle TVM_INSERTITEM and TVM_DELETEITEM to know exactly when items are added and removed.

In these handlers recalculate the width of the gutter required to display the widest 'dotted' item/subitem number. (Note: this is not necessarily simply the deepest subitem.)

Handle WM_NCCALCSIZE when it does, and offset the left border by the required gutter width.

Handle WM_NCPAINT for painting the numbers.

This is necessarily an over-simplification, but it captures the essence of the solution, and all that essentially remains is lots of fiddling about to ensure the non-client area gets redrawn at the the right times to stay synchronized with the client area.

Embedding .RC control definition data directly in a .cpp file to break the dependency on binary resources (a.k.a. 'Runtime Dialogs').

This is an idea that has been floating about for quite some time and which has only recently gelled into a workable solution.

The problem, put simply, is that if you want to take advantage of the resource editor in Visual Studio (and who doesn't), then you very quickly find yourself stuck with having to load dialog templates from resources compiled into the binary file.

This further means that if you want to make use of a dialog across multiple projects, then either you need to copy and paste the dialog template between project .RC files, or you need to build the dialog into a DLL from which it can be accessed.

'Runtime Dialogs' (a snappy title I coined myself) is a solution that neatly sidesteps both the nuisance of copying dialog resources between resource files and the extra work (and maintenance) involved in packaging dialogs in DLLs.

And it works like this:

First, you design your dialog template in the resource editor, create a CDialog derived class using class wizard, and wire up all the controls just as you normally would.

Next, you #include "runtimedlg.h" and change all instances of CDialog to CRuntimeDlg.

Then, you cut and paste the control definition section from the appropriate section in the .RC file and embed it directly in the dialog's .cpp file as a static string (with a bit of tweaking to handle double quotes and such like).

Finally, in the constructor of your dialog, you simply call CRuntimeDlg::AddRCControls(...) passing the control definitions as a string.

And CRuntimeDlg takes care of the rest including, if required, auto-sizing the dialog to suit the control layout.

I'm certainly not suggesting that this is a 'win-win' solution for all situations but it certainly has merits in its closer coupling of dialog template to dialog code which makes sharing dialogs across multiple projects a breeze.

P.S.: In case it's not clear here, I used CRuntimeDlg to create CToDoCtrl which encapsulates the ordered tree together with the priority, date and comments controls as a single simple-to-instantiate control.

This is possibly the most satisfying aspect of the whole project because it was completely unexpected.

What I mean is that, until recently, my knowledge of DOM and XMLDOM was virtually non-existent, as it's only since I've become more interested in the presentation of AbstractSpoon that I've been forced to get to grips with the various implementations of DOM and XMLDOM out there.

I'm pleased to say that the code on my site works under IE 6.0, Netscape 7.1, and Mozilla, although custom code was required to achieve this.

Generic MFC Classes that may prove Useful to You

The following table lists a wide range of utility classes written for this project. They can all be included in any MFC project provided you include any class dependencies too. Feel free to ask any questions relating to these specific classes and how to use them.

Adds support for recognizing urls, clicking them and setting custom url callbacks

CWinClasses

Encapsulates the ::GetClassName Win32 functions

CXmlFile, CXmlItem

Non-Unicode class for reading and writing xml files

CXmlFileEx

Adds encryption capabilities to CXmlFile

CXmlFile, IEncryption

* CSubclassWnd was originally written by Paul DiLascia for MSJ magazine. The version I use has been heavily extended to suit my specific needs. The classes that depend on it here need this extended version.

Further Work

Whilst this tool was originally intended for my personal use only, it is now a 'community' project, so if you find it useful and want to make suggestions for enhancements or bug fixes, then post below.

History

7.1.4 (26 Aug 2017)

Fixed filter selection when names contain brackets

Fixed HTML exporting of '&', '<', '>'

Fixed application window resizing on startup

Fixed file encoding of 'Transformed' tasklists when auto-exporting after saving

Hi Dan, the idea is that instead of doing the backup in TDL format can run a script, vbs or bat, with which to perform the backup. Having this ability to automate agility copies increases, ftp shipping zip format, emailing, etc.

On one hand I think it would be cool for the auto-backup to check to see if there is a program name which should get executed rather than simply doing a Write to disk. Dan, this could be implemented as a plugin hook, and also to execute a UDT which is checked with "Execute on save".

On the other hand it would be rather trivial to have code which watches the file system for backup files, or which runs in a service/tray and periodically polls for new files which are then post-processed in some custom way. Like the UDT option, this allows for any language or technology to be used to post-process the backup files.

With this second method, Dan doesn't need to make any changes whatsoever, and every individual is free to use any of millions of tools which operate on files.

With syntax $(seltcustom, <customID>), a field of type Date will show the raw xxxxx.yyyyy rather than an externally formatted date. Please check this for type Date and any others which may be required.

Free and Open Source Software is a great thing. Someone provides free labor, and publishes tools that the rest of us use to work more efficiently. The result, ideally, is that we users reduce expenses (time=money) and increase profit for our businesses. We all like this free-as-in-beer aspect of freeware/FOSS.

Many companies have specific needs which are not addressed by general purpose software. These companies have a few related options:
1) Write it themselves using the core as a base. It is Open Source after all and the only expense is the time of the developer/employee, if a person is on-staff with the time and skills.
2) Hire someone else to write code for them. This is more expensive, but the result should be a utility which will do exactly what the company needs.
3) Wait for a feature from the core author (Dan in this case). This option is precarious as the feature might not be in line with the author's preferences, interests, or time constraints. Users often wait for years for freeware features and they never come. Or they get a feature, with full source code, but it's not implemented as desired. This leads back to options 1 and 2 to modify the the code, to continue with option 3 to wait for an update, or...
4) Do without. This is the what usually happens when a company wants industry-specific functionality for free from a general-purpose tool. It often simply doesn't exist.
5) Find some other software which has the feature. Unfortunately people are forced to choose between software they like, but which doesn't suit specific business needs, and something that does suit many of their needs, but even for a high price it might not have the features of the freeware.

But if you really like freeware like ToDoList, do you need to hire a developer, go without features, or go buy something else just to get what you don't see here?

Absolutely not.

As a developer and business owner with excellent credentials, with a focus on business applications, and a particular fondness for ToDoList, I'd like to create a number of utilities which will allow companies to get much more out of this fine software. This can include:

- Export to an attractive calendar/scheduler
- Tighter integration with MS Office apps like Outlook or Excel
- Import/export with relational databases and other applications
- Integration of scheduling data and statuses from other systems (MRP, accounting, dispatch, CRM)
- Update to task lists, and notifications with SMS, phone menus, email, or a generic web service API
- Integration with Slack, Twitter, or other services
- Adding logic to tasks, like flagging a task when %complete is less than time available
- More extensive reporting via management dashboards with charts and graphs
- Alternative UIs for Android, iOS, WinPhone, new watches, and browsers
- Integration with issue trackers

All of these things are possible (and some already done). But development for commercial usage can't continue for "free". So I'm hoping that business users will comment here or contact me off-list to exchange notes about funding development for specific solutions built around ToDoList. The resulting solutions could be sold to other companies to recover the investment. But without funding, many of these great things will simply never exist.

If you work for a company, and ToDoList is your "secret weapon", this can be a way to get others to use it. Your management can get the benefits of using the data you enter into ToDoList, in a format that they require. But business owners understand that as their clients pay them for something of value, they must also pay for some things that they value. The question is about what solutions they want and what they feel those solutions are worth to the business. At least now you know that these things are possible. So let's open the discussion and see where it goes.

( Disclaimer: This is a completely independent note from myself, just another TDL fan, and not related at all to Dan or his own preferences or intentions. )

The library is not available yet. Huge apologies to those who are interested.

It was pretty much ready to go and then I realized that two features needed to be implemented.

The first was to make all properties observable, to allow an application to subscribe to changes which occurred to any task in a list. That led me to big changes with observable collections. Then I realized I wasn't exposing collections properly for this specific use. So I undertook a major effort to revise how collections are being handled.

The problem is that a List<t> collection like list.Tasks is being returned through a calculated property. This would allow developers to write code like list.Tasks.Add(task) or list.Tasks[n].Prop=value, where operations were being performed a temporary object returned from the container, not on the object within the container itself. That would cause a lot of "hey, what happened to my update?" questions. The same applies to the SortedList<t> used for categories, etc. So to avoid this I started a shift toward read only collections. That leads to some real nuances and implementation of things like a SortedReadOnlyObservableCollection<t>.

That's where it is no - trying to ensure that developers don't walk into a trap, providing a full/expected set of functionality, and still maintained the integrity of the data.

In hind-sight I could have released the beta-1 code about 6 months ago to get feedback, with a promise to add all this other stuff in a v2. But since this completely new, I have the luxury of being able to modify the API without breaking any code in the field, and this wouldn't have been traumatic had the library already been published.

So I'm doing my best and appreciate your patience.

And with that - if there are other questions specific to the library, it would be best to post them at CodePlex. This specific thread is about Business Applications, not the library. Thanks.

Just in case: I hope I haven't mis-communicated my intent to folks here. My goal isn't to scope the group for app ideas and then to come up with for-fee apps. I really do want to contribute utilities as freeware. This is my way of giving back, of balancing karma, of "paying forward", which is how freeware (and separately open-source) is supposed to work. In addition to this I'm hoping to encourage businesses to contribute something to this ecosystem to help foster more of this. Businesses don't generally subscribe to karma - they "give back" simply when they pay for what they use. That's where I'm going with all of this and I hope I haven't put anyone off with regular references to business use.

My personal problem is that while running a software business, with obligations to clients, and constant marketing for new prospects, that I don't have too much "free" time to invest in freeware. So with a passion for all that ToDoList can do, I'm always looking for a way for commercial users to help kickstart my development. In fact there's no reason why a company can't support some specific initiative which leads to freeware for everyone else. This is a very common model. But until some entity can help me to justify a shift of energy from clients who are paying for services right now, it's really hard to choose freeware development whenever I have some extra time. This scenario is faced by all FOSS developers - it's one reason why we have Priority and Risk settings in TDL.

Version 6.9.6 on Windows 8.1 64bit: For some reason the choices of English(Great Britain) and English(United States) are showing up in combo box drop down lists. Some can be deleted with the x at the end of the option and others not???

Some combos: right now in Priority, Status, Category, Allocated To, Tags. They are the only entries in previously unused combos and the combo, such as Priority ONLY has these entries but none of the default priorities are listed. In Combos which have previous entries made, these appear along with the previous entries.

This is on Windows 8.1 with all updates. It appears that this behavior may not have started until I tries to customize some of the settings.

I just loaded 7.0.B2 and it is also occurring there. I also noticed that English(United States) does not appear in the Language choices in preferences but does appear in the drop downs where it does not belong, along with the English(UK) choice.

My tdl file is located on a webserver.
At the moment Im informing my customers about my project progress by exporting the tasks locally and then manually ftp the exported html file to my webserver.
This workflow should be made more easy.

If someone can provide a spec I should be able to add this into my UDT fairly quickly. You'll notice the UDT already does a file Rename of the HTML report. It's quite simple to get that to FTP using details provided in the UDT command-line.

@Magnihan, please read about the Rename UDT from the link in my sig and let me know if that would help.