Added preference to use 'Creation Time' when initialising 'Start Date'

Added preference to configure a 'Custom Toolbar'

Added resizability to 'Task Reminders' dialog

Added splitter bar to 'Find Tasks' dialog

Added splitter bar to 'Gantt Chart'

Added support for 'Kanban' tasks to be created directly in selected column

Added support for 'Move > Select Next Task' to 'Gantt Chart'

Added support for 'QuickFind' to 'Gantt Chart'

Added support for high DPI (4K) monitors

Added support for individual 'Custom Attribute' selection in 'Print/Preview' and 'Export/Transform/Email Tasks' dialogs

Added support for inheriting 'Custom Attribute' values from parent task

Added support for title sorting in 'Calendar View'

Added task 'Drag and Drop' support to 'Gantt Chart'

Added task links to 'Stickies' reminders

Added the ability to copy task attributes via the commandline

Added tooltips to 'Task Links' in 'Comments' fields

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, please post to our Google Group.

Comments and Discussions

Very glad to see this; been looking forward to 7.1 being released for a while.

I am seeing a few quirks, and one clear bug.

First, and this happens even with a brand new preferences file using the sample introductory task list: filling in any value for estimated time causes the due date to be set to the start date.

I'm also seeing some oddness with the Kanban view tracking "allocated to", where dragging in the Kanban view causes a change in the value, but changing the value on the list view doesn't result in the item moving on the Kanban view. In fact, it is possible by changing the values in the "allocated to" dropdown after using the Kanban view, to make some tasks disappear from the Kanban view altogether, as if they are not in any of the displayed categories at all.

I've gotten around this by creating a custom single-select attribute that does what I want, but with that, the backlog doesn't work correctly. (Although an easy work-around in this case is just to create a fixed view with a column housing tasks having no value for the tracked attribute.)

I did see one complete application crash at one point, but I can't say what sequence of interactions brought that about except that it happened when I selected a task on the list view and hit the delete key.

Edit: and one question. Is there any way to get the sorting to refresh in the list or tree views after changing the value sorted on? Old versions used to re-sort constantly, which was a bit rough, but I'd love at least to be able to hit F5 or something and get everything to go to its proper ordering.

Edit 2: One more bug. In Kanban view sorting by a custom numeric attribute does not work correctly. It does re-order things, but not clear what pattern it is using. Definitely not ascending or descending.

Okay, definitely seeing repeated crashes when trying to delete tasks, whether by hitting the Del key or by right-clicking and choosing "Delete". Wiped out all or most of what seems to be the tasklist-specific settings, too (all saved searches and the task attribute visibility settings. But not my Kanban fixed column definitions, oddly).

Thanks for the response, and when I get a free moment I'll try to head over to Google Groups and add topics for the remaining items (if they are still remaining by the time I get to it- you're usually pretty quick at getting things fixed). Regarding a couple of your specific replies:

.dan.g. wrote:

Trajan McGill wrote:

Old versions used to re-sort constantly, which was a bit rough

There is a preference to control this so perhaps it has been turned off... Otherwise it could be a bug. Is it reproducible on demand?

Trajan McGill wrote:

Is there any way to get the sorting to refresh in the list or tree views after changing the value sorted on

'Menubar > Sort By > Sort Tasks'. Or the toolbar button. Or your own keyboard shortcut.

I do have "automatically resort after editing" enabled, if that's the setting you're referring to. I'm right now sorting on a custom numeric attribute, so not sure if the behavior is the same for a built-in attribute. As for using the "Sort Tasks" menu option to trigger a re-sort, the problem with that is it seems to be exactly equivalent to clicking on the column header I'm sorting on, which means that it does cause a re-sort but also reverses the ascending/descending order. So I have it, say, ascending, I change a few values, the list is now out of order, I click that header or choose that menu option, and it is now in order- but descending order, and I have to click it again to get it back the way it was originally sorted.

Indeed, if you run 'Help > Check for Updates' again you will get 7.1.0.5 (even though it still says 7.1) where you will find some of the issues already fixed

Trajan McGill wrote:

I'm right now sorting on a custom numeric attribute

Thx, that's probably the missing link.

Trajan McGill wrote:

it seems to be exactly equivalent to clicking on the column header I'm sorting on

It's only equivalent if there hasn't been an edit on the sort attribute, otherwise it just refreshes the sort. This tells me that TDL is not detecting that the custom attribute change requires a resort. This is the bug I need to fix.

Hello Dan,
you have done a great Job with the release 7.1!
I would have questions to dealing with KANBAN based on list with multiple selection Option:

I you utilized Kanban to map Tasks to the field "Assigned To" (this is the Group of persons responsive to resolve the Task) then the follwing happens:

1. If there has been an assignment made earlier using the Task Input/Edit form, then the KANBAN view would not pick up that earlier assignment. However, everything works as expected when performing the drag&drop in the KANBAN view. Is this intented that way?

2. What is the rule for KANBAN assignment in case of multiple selections in the "Assigned To" field? Currently, the user can move the the Task to ressource in the view and the lsit in the form will add the checkmark to that Person.

Dan has put a huge amount of effort into this release and there are a lot of enhancements and fixes.

Sincere thanks to Dan for his time, patience, and careful consideration of change requests.
Update via menu>Help and see this page for a long list of changes.

Thanks also to everyone who reported issues, offered suggestions, tested changes, and provided feedback to help make this a great release through all of the Alpha, Beta, and Release Candidate revisions. This is what drives ToDoList and everyone is welcome to participate in this process.

Special thanks to those who worked on the new language translations to help keep this fine software current for a global audience.

For those who were not following with the development releases, many changes may be confusing. Take some time to get familiar with the new features. Make use of the new Wiki resources - most dialogs now include a (?) icon that links to a relevant help page. Ask questions here or in the other groups available. See links under menu>Help to "Feedback and Support" (Google Groups), Google+, Facebook, LinkedIn, and Twitter. You can also post quick suggestions for Wiki updates to the Wiki Suggestion Box.

lately i was stuck with problem of resizing the dialog and moving/sizing it's child windows according to percentage the parent dialog grow by .

the main concept is the capability to layout dialog in grid-like fashion with capability to grow column or row or both . something like row-span and column-span in HTML table.

i wonder did your code contain a functionality like this and if so in which file? . if not thank you anyway i always enjoyed using to-do-list as task manager and appreciate the hard word you invest in it.

Thank you for answer and great software.
Presumably in blocks: 0-10, 11-20, 21-30, etc?
Probably. But important 0, 100 and any. This makes it easier tracking of status for me.
That is "New," "In-process", "Done".

There is a bug since 7.0
you input a comment and for some reason you leave TDL in input mode in the comment for some time.
When coming back to TDL to finish the input in comment, cursor blink in comment but it is impossible to type in comment anymore.
When mouse click on tasks titles, focus move, when click in comment, focus go back to comment but unable to type.
I am unable to set a sequence of event better than this.

That only solution I found is close TDL and reopen.

Patrice

“Everything should be made as simple as possible, but no simpler.” Albert Einstein

I believe that I have seen the same issue. I have not noticed any specific pattern of activity that leads to the problem.

I have been able to resolve the issue without a restart, but I have not tracked a specific sequence of steps to correct. When I find I cannot edit a comment, I try to toggle between tasks and comments using F11 and Alt + o and I eventually find that I can edit comments again.

Edit: I think I figured this out - the email account I sent the original message from is not the same email address I use with the google group. When I sent the email from my GMail account, I think it worked.

Original message below
I tried using the email address in Dan's signature, but it bounced back saying the group abstractspoon-todolist-support did not exist. I removed the items in parenthesis and replaced them with the proper symbols.

I am looking through the google group now to see if I am doing something wrong.