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.

Comments and Discussions

Typing lessons would help. Anyway, my point was to express my appreciation of the continued development of this program. I also use Freeplane and I read an inquiry about integrating the two. There is more to look forward to.

I use Freeplane too. I don't know if you are aware that you can import and export Freeplane files via the TDL import and export feature. You just import and export using the Freemind selection. Freeplane is a fork of Freemind, and because of that the file formats are the same. It would be nice if there were a roundtrip sync of TDL and Freeplane/Freemind. BTW, in my humble opinion, Freeplane is far superior to Freemind, and it has a plugin called Docear, which is pretty awesome if you need to do research and write research papers, a thesis, or a dissertation.

This was "sort of" discussed a few months ago and I'd also like to see it.
We have links to code files, to project solutions, to documentation files, to OneNote, to bugzilla and other client-specific trackers, to web pages, etc. I'm currently launching to most of these from Comments or UDTs.

For anything more refined, my approach would be to create a UDT that cross-references a task list/ID to whatever external resource is required, and then launch the correct application from there. Unfortunately that requires code and an external datastore but it can be modularized into a more generic utility if TDL isn't going to get this functionality anytime soon.

With a UDT using the library, we'll be able to use a custom text field for a task to get the link, derive the application from there, and launch as required. Since this is coming out soon and it's relatively easy to create, perhaps this would be a good way to demonstrate how we can take some of the load off of Dan for features that might only be used by a subset of the audience.

When creating tasks from Outlook it would be great to have an option to have a 'None' attribute in '...maps to Task Attribute'.
F.i. I mostly make tasks from emails for reference use so now I remove unnecessary information manually (such as Flag Request, Permission, Sent On Behalf Of, etc).
P.S. Partially it can be solved by assigning to a very rarely used attribute (for me it can be 'Version') so it goes hidden but who knows maybe I'll need to refer to Version someday..

I confess to a paradox. I write addins for Microsoft Office products, like custom filters for Outlook and buttons that integrate with local applications, and custom database integration and UI components built-into Excel. But I've never used the Outlook integration with TDL. I don't even know where the mapping is which Alex discusses.

If anyone here is doing some complex operation manually to integrate Outlook (or any Office app) with TDL, feel free to post your pain and I might pick it up as a challenge to create a solution. An example might be to pull task data into an email so you can advise a client of their project status, updating a Contact with tasks associated with them, or doing a bi-directional sync of Outlook Tasks or Calendar items with TDL. I can't make any promises but just know that all of these things are possible.

Corporate users, please contact me directly if you'd like specific functionality. I'd prefer to offer commercial solutions as a business offering rather than as freeware which I tend to support more for individual and small business use. Thanks.

I'm sure that this topic concerns only a part of the users and is not easy to implement, so I don't want to make a "Suggestion"; I want to post it here as idea / workflow / point to discuss.
------------Current status:
After my tasks are "done", I make a "transform" to a systematically named HTML-file and send it as report to my clients. At the moment I log when I sent the file to customer and when he affirms it.

Now I see that I have to expand my workflow: Every transformed/reported tasks need to carry also the filename of the report: "When a tasks was reported with which file?". This can be done manually at the moment.

Point to discuss:
- could it be helpful for more users?
- could it be supported by a new feature of TDL?

Sounds like you might be able to use a UDT which zaps some field with a timestamp whenever it's executed.

FYI, I report time via the Analysis functions and I'm also now sending a Transformed HTML report to clients of all open and recently completed tasks. I note you're only telling clients about completed tasks but don't they want to know the open ones, time spent on them, current status, etc?

...but don't they want to know the open ones, time spent on them, current status, etc?

No, not at the current projects. They are more a kind of step-by-step projects (finding a way in the darkest, foggy night) ....
If yes, I would use other transform-files.

Back to my current posting:
I have
- my TDL, mostly for reporting and time-watching my tasks, not for planning
- created HTML (PDF) reports, based on the done tasks (no TDL)
- a TDL, monitoring my created invoices, based on the confirmed reports

Now I have to think about a reorganisation of this workflow to follow the flow "done tasks - created reports - created invoices" - no 1:1. but a m:n relation

If I understand the first part of what you're saying, when you hit 'print' the list is filtered for newly completed tasks, and an html report is generated. [Begs the question of how you get the filter and how it knows what is newly done. My guess is you have a macro that applies a filter and calls out to your transform? Further, either this macro also applies a date range, and/or you fetch a 'since date' out of a file or some other hidey hole.] Presumably the tail end of the macro removes the filter.

Are you saying that at send you need each completed task line to have report time and report filename fields updated? [Where are these currently being stored, within comments?] {It occurs to me in thinking about your scenario that a subsequent report after might then update these fields, so having them present in the base / template would not be unwarranted?} Which leads to your filter above of completed and unreported? [But leaves you open to the problem of updates post closing / last report that will go unreported, let alone if you only fix a comma or something and re-send, your customer will ask you why it got sent (again). Perhaps you actually need a 'to be reported' field that gets cleared upon report, so you could set it again only if you had to for material change, and would make appropriate update comments?

I'm writing here as your message made me think you need snapshots. So your transform might actually copy the file off for archives, print, update the fields, and the transform result becomes your new current .tdl?

Moreover, if you 'archive' completed tasks out of your list in the transform, they could be appended to a historical work completed list or csv appended to a spreadsheet historical record list, or something?

In any case, are you not talking customized fields with types, and/or triggering off the last changed field already present?

To go back to the beginning, I'm not entirely following what you're asking for - a last printed date, filename destination, and (presumably) by whom, field?

- I have a TDL for my tasks, nearly only for logging my tasks and my work, but not for scheduling and prios and so on.
- I use the standard-infos Title, category, allocated by, time spent, comment, ..
- Also I use user-defined attribs like "
-> Finished" (which is nearly the same as "Done", but independent from the checkbox)
-> "Reported" as date when I send the task-report (Title, comment, spent time, ID) to client as report
-> "Confirmed" as date when the client says "report is OK"
-> "charged to client" as date when I sent my invoice to client

(The invoices have a separate TDL to check sent / due / paid / cost / ...)

Workflow:
a) working, set to "done" and to "finished" after task that is done
b) at end of the month, I select all "done/finished tasks" (per client) which are not yet reported
c) I create a HTML-report via Ctrl-T with a defined name (Client_A_001.html, Client_A_002.html) and send it to the client and set the date for "Reported".
d) Then I wait for confirmation (set date) and create an invoice (and set date)

The only thing that I want is to add information to "Step c)": "Reported with file-name ...."

And as I said at the beginning: this can already be done manually, but the computer knows the affected tasks and knows the name of the just-created-report, and this is why my question was: How to make this little, simple step automatically.

So, a field that upon execution of a transform gets updated with the output filename of the transform. (1) [What if you have two different transforms?]

- I would also have thought you would want date generated, and by whom, but let's leave that alone for the moment. Never mind issues of mistakes or needing to re-issue, either.

What I don't get is why you would do it this way, it being very manual.

I would have thought that you would update the file as you suggest, exit TDL, then run a batch series of transforms - e.g. for %a in (client1 client2 client3) go msxsl -myfilter -%a -o %afile%date% & blat -subject "month's report" -to "client@email.add", where the transform updates these custom fields as you describe. In essence, self-modifying the TDL.

Which is only all to say - what you're doing sounds really cool, but highly user particular specific. So, I get (1) if it's what you're looking for, and it doesn't seem unreasonable given all the other magic Dan has surrounding reporting, but it feels like you'll still want / save yourself some time via the workflow I describe above. At the least, for example, some manual mis-keying may be avoidable, such as not quite getting the filter right on that run for that client, accidentally sending one client a different client's list, and so on. (Begging your pardon for saying so, I guess, such all being yours to manage and none of mine to comment upon.)

You've already got the transform for reporting, so you've already crossed huge learning curves. Shouldn't it be relatively minor to build a transform that updates fields as you might like? (This is all an example of where a 'comment2' area would be useful, I suppose, you could overwrite it with each run with 'report generated and sent to x on y'). I suspect this actually becomes two transform runs, which will inherently be problematic (if the first fails this second would still update as though it were successful, etc) - since generating two output files in one transform is likely irritatingly complex to program, let alone one in html and the other self-modifying xml. [Thus my expectation you would rename the current tdl with a time stamp, and (re)generate out of it the updated / now base TDL.]

So, a field that upon execution of a transform gets updated with the output filename of the transform.

Yes, that's the basic idea.

Your other ideas (batch, blat, ..) sounds great, but they are above my number of created reports and above my level of knowledge. Of cause the ideas where helpful in an environment with more users, more reports, more clients, ...

Does somebody know how to display a daily view of the tasks planned for the day in ToDoList ?
The weekly view squeezes the small tasks (those lasting less than a couple of hours), and it would be most convient to have a view that clearly shows what I need to do at what time. A bit like in Outlook.

But this answers my need only partially: I hoped I could schedule my day in the morning, and see which task I should be doing at a given time, throughout the day, instead of picking one whenever I'm available.

The act of picking a task is scheduling in some sense, and I think this should be done once a day only.

Setting a start and end time sort of achieves that but it is not clearly visible in the task view. I was hoping for a clear Outook-like view of the day, with a cursor for where 'now' is.