Added history combo to 'Title' field of transform, print/preview dialogs

Added drag'n'drop support for re-ordering tabs

Added optional confirmation dialog to time tracking

Added close buttons to tasklist tabs

Added blank line to single-selection droplists

And much, much more.

Introduction

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.

If you add a column to your tasklist a relavant edit field will appear. I suggest (if it's feasible of course)) making this appearance an option, hiding edit fields behind right click options.
The process could looks as follows: for example I need to add Due date. 1) select a relavant column 2) click on the field of the task I want to put due date a select from calendar (just like we have now for Due date edit field) 3) choose the appropriate date.

In such a case overall design becomes more simplified and not overwhelmed with excessive clicks as you have your tasks, comments and filters on your display.

Whereas Category and Allocated to have check/uncheck boxes for adding/removing them, to remove a certain Status you need to press Delete on your keyboard. Wouldn't it be more consistent to add check/uncheck box to Status as well?

Alex

P.S. It's related to a lower Status edit field, the upper field is ok.

You see I've got "Status", "Allocated to" and "Category" columnes, so relevant edit fields are there too (both upper and lower ones). The question is that in the lower edit field there is no square check box to check/uncheck (f.i. [] Deferred) the upper is ok.

If the tasklist is sorted by priority new tasks are not sorted by their priority. They get not sorted as long you refresh the filter. Maybe it should be optional that new tasks get sorted right away.

If i create a task with a default priority of 8 among tasks of priority 10 by refreshing the filter it gets pushed down to the 8-tasks below. But somehow the task ends in the middle of the 8-tasks. I guess it should appear at the top of all 8-tasks. I don´t know what secondary sorting algorhytm is at work here.

When inserting a flie link in the Comments section, is it possible to assign this file link to some characters instead of having the file link itself be viewed following the task name in the task list?

I am trying to filter "Start_Set AND Priority > 5 OR Completion_Set AND Priority > 5".

However, when I come to enter the last "Priority", I don't get the "Greater than" on the value filter drop-down, just "set / not set, equals / not equal, includes / not includes". In other words, all the >, >=, < etc. comparisons are not available.

Running 6.6 Dev R4.

=John
Of course, brackets would help: "Priority > 5 AND (Start_Set OR Completion_Set)", but that's another wish!

If you change the Category of an task via the edit field it takes about 10 seconds till the hour glass cursor disappears and TDL is responsive again! TDL never showed this behaviour in former versions.

When I went to create a new filter, I changed the type to 'Due Date', but the dropdown next to it remained as for a text field (i.e. no less than, less than or equals etc...). I set it to 'equals' and saved the filter. It didn't filter as expected.
I went out of TDL, then back in, and it seemed to have the correct dropdown now. However, changing it to a text field, didn't change the dropdown back.

When I had created the date filter, it didn't seem to work either. In my case, due date is >= to 26/11 brought up tasks with due dates of 25/11 and 27/11.

Let me know if this is unclear, or need more specific details.
zajchapp

In Version 6.6.Dev 3 the renaming of icons does not work properly. The Assignment between names and icons gets lost. Sooner or later other icons than the renamed icons gets the names you typed in. BTW, where do the names of the icons get stored? In the "ToDoList.ini"?

Dan, in the feature list of 6.6 many features are crossed out. What´s with this features? They are defered or implemented already?

I would like to mention some features i still would love to be realized someday. I don´t know if those will make it in 6.x.
- Editable Hyperlinks
- Defer Options
- Tasks which appear when startdate ist reached (at 0:00 o´clock!)
- TDL remembers the last cursorposition in the comments of each task

I don´t know. I did not try renaming icons for a long time. And yes i´m using own icons as well.

Icons are now sorted alphabetically which is great. But the first 2 icons icon0 and icon1 are not mentioned in the ToDoList.ini. The sort algorythm you use does not consider numbers which leads to the order 0, 1, 10, 100, 11, 29, 3, 30. See below.

I will try to change the names directly in the ToDoList.ini and tell you what happens.

DONE! Everytime you close TDL the ToDoList.ini ist saved and the assigment gets destroyed. There is a pattern. Every new name you typed in is listed alphabetically at the end of the icon list while the order of the icons are not affected. If you rename an icon with a number it seems to work. (Assignment stays) I hope this helps!

Well i think you should be able to rename the icons in the dialog like it is already. After closing the dialog or TDL those names and the link to the icon should be remembered and the list should be sorted alphabetically by iconnames.