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

I created a new updater in 6.9 to give me more control over the update process, and this requires admin credentials to run. Usually this just triggers Windows to prompt the user to continue but it sounds as though this may be falling foul of your particular setup.

Can you report the text of the SmartScreen warning here so that I can use it to investigate the cause of the problem?

I went to another PC that I have and tried to update TDL from 6.9.rc2 to rc3. It too had been updated from 6.8.10 to 6.9.rc2. I created a video of the problem. you can see that at https://www.screenr.com/k5ZN. Just in case you have problems running the screencast, the message I got from Windows 8.1 was, "Windows SmartScreen prevented an unrecognized app from starting. Running the app might put your PC at risk."

BTW. I tried rebooting as Windows suggested, and that does not fix the problem.

For those that want a workaround for now, here is a link to a screencast that shows the workaround. https://www.screenr.com/z5ZN[^]. Don't forget to re-enable Windows SmartScreen after updating TDL.

Hi I'm new user of ToDoList.
After few minutes I modified my list, the application become readonly. I cannot anymore edit data.
Closing and opening the application all return operative as usual but after few minutes all readonly again.

You probably do want Enable simple source control, attempt check out when loading a tasklist, if a task list cannot be checked out, keep re-trying periodically, check in tasklists when I close them, and include user name when identifying check-out all checked.

You probably want only for remote tasklists left unchecked.

And, most importantly, probably what was doing you in ...

Uncheck check in tasklists if no changes have been made for more than.

- or set it to some large value, like 30 minutes.

Likely the default check back in of 1 minute was causing the behaviour you experienced.

Are there any plans to wrap the title (or other) fields? Sometimes the attributes become many and either the text are cut off or scrolling is required - it would be easier to view content if the pane would just wrap text

I also think the text / non list fields would be better if they could be multiple lined entry (cntrl shift enter)

And what about moving panes in different positions? (I have title field first, but then the checkmark field is on the other side which makes it awkward view, would be nice if user could freely move panes left/right

I also think the text / non list fields would be better if they could be multiple lined entry (cntrl shift enter)
Why?

To have a lesser comment field for when in depth comment is not needed or make the task title easier to read rather than a ,long string separated by slashes.

Alternatively the first line of the comment field could be the mini comment - but then the user would have to hover over each separate title for further clarification rather than just seeing the project all at once. Mini comments btw are especially useful when technical jargon is used to identify tasks- so you have to retranslate

I suppose someone who has really planned their project could create multiple text panes for further comments, but then the issue of non wrapping again pops up, and again the limited scrolling to see all the attributes.

This also permits a)faster data entry than having separate comment fields, and is easier I think for someone who wants just a little organization
B) when side comments are just inserted as non bolded subs, there is more room to see other attributes/fields that are more necessary for organization

Also, because you mention the wrap pane issue it makes even more useful as a long string can be broken down so that all of text is viewed at once.

Does tdl have a find and replace feature?
I searched for it, however can not seem to locate it (if its there)...
It would be strange if its not already present, seems to be feature most progs have? I am probably just missing it?
If it not there- are there any plans to add it?

It would be even better if the find / replace could be restricted to selected tasks...

Hi Dan,
Is there anything I should be watching out for when putting custom attributes into stylesheets for reporting? I tried once before and got stuck. I am trying to test whether the custom attribute has a value, like I do with a normal attribute, but the test always seems to fail. Also when I try to output the custom attribute value, it seems to think it is empty.
Any ideas?
zajchapp

There have been various issues at various times. If you run into something, post your code fragment here - some have beaten upon (and been beaten by) this area. They may be able to help with some humps.

Apologies . Haven't touched this for close to a year, and have forgotten too much! Forgot the node/attribute structure in the TDL file. I was treating the custom attributes like an attribute of the task. All working fine now.

Now to go to the next challenge - to output the custom attribute icon into the stylesheet. Any help welcomed.
zajchapp

I wrote some extensive code in the library to make it easy for a developer to identify and use the icon values. You/we/I can use this to extract icons into individual files which can then be referenced by img links or CSS via your XSL. It won't be long before this is out...

Around Christmas last year I got an image to display on a report via HTML. Took me a bit of messing around, as I am very much an infrequent programmer, and don't know these languages well. I didn't manage to get the icons working before work got busy again. I would be interested in this functionality when available.
zajchapp

No. But ... reported as I expect (from what you've said) they use common libs between them.

Actually ... not sure if I'd notice - failure flips by so fast, if there even is a screen, at publish. Let alone I don't recall if error (codes) cause a failure popup.

In any case, not sure it matters - if something is going to make msxsl cranky, it can't be permitted to land there in the first place, and TDL is the keeper of the file content, as it were.

Or put in a somewhat different way - sleuthing out the issue involves opening up the .tdl in a text editor, which is not something I expect you want the average user to have to do to. At failure, it's a complete mystery and all but hidden to the user - there is no apparent way or what for what's not working. It will appear as a TDL failure, which is a conclusion I suspect you would prefer not to be drawn.

In the end, it's all a bit strange - given the plain text fields, obviously there is some sort of watchdog in place for non-'text' characters. My guess was 0x92 didn't make it to the 'special characters to watch for list'. Or the keyboard entry to plain text field and windows clipboard input mechanism aren't using a common watchdog.

Speaking of which ... I've noticed on a text (csv, e.g. \t delimiter) the first line of input is lost. Seems the assumption is the first line is the usual .csv field list, but that might not reasonably be true / present on a clipboard paste (tools/input).

In any case, thought I'd better send a heads up. If nothing else, perhaps someone searching the forum will see the heads up and be able to work through their issue.

Was able to see the problem does not exist within TDL's internal processing via print preview.

So, msxsl and the corresponding lib TDL uses must not be exactly the same. Note sure how much that matters if TDL encourages (requires) msxsl calls for any other list printing / transformation output formats.

In this case, problem turned out to be "s, as in '2" from corner'. 0x94

I do see an & in a comment that has been stored in the tdl as &amp; - so no doubt the 0x92 and 0x94 are simply two missed characters in such text processing.

Problem is, the only way I can figure out how to sleuth such out is by text editing the .tdl file and taking out task lines one by one until the culprit is found. If anyone has better / faster suggestions to figure out what's killing things when this happens, I'm all ears! [XSL to the rescue! Mixed blessings, I suppose.]

At least this time the msxsl reported problematic line number was accurate.

Real issue is, I suppose - silent failure. User will note unexpected results, but have no idea as to where, why, or how to fix.

Bonus problem here is ... these comments were moved (cut and paste) from one task to another. But because of the tdl forms of

and the comments between and not taken out of the old task, msxsl still complains, and there is nothing visible within tdl for the user to fix. So in one of the occurrences of the issues in the file, it looks more like:

- and the bottom 2" text entry invisible to the user. (Being a comment since deleted from that task.)

Solution: Replace first two "'s above in .tdl with &quot; and remove the (last) text from /> to </task> (which I wish wasn't there, but never mind that - goes back to needing both plain text and rtf comments, I suppose).

Hey ... if you're into that import/export code ... any chance you could add a back button to the second dialog?

Inevitably I change my mind, have to hit cancel, tools / import, discover I was right the first time, click next, second guess myself again ...

Also ... perhaps prepend "Title\n" to the clip area, or somehow other assume it from file? Perhaps, "If start of first line is not obviously a field title" do the same? I keep losing the first line of the input (being mapped to title).

Or perhaps a 'no headers, assume title' checkbox?

And perhaps rather than leaving first field mapping blank by default, default it to Title?

We can filter tasks and then toggle to view all tasks unfiltered. That's a single custom filter.

But I find myself jumping between filters for what's currently active, what's in planning, what's been worked on recently, etc. So it would be ideal to have multiple filters for quick access. Perhaps an easy way to implement would be to add a Save checkbox to the filter bar. When checked, a new option would be added to the Show dropdown. To avoid conflicts, the default filters can continue to use letters while the custom saved filters would be numbered. When a saved filter is displayed, the related filter items are set and the checkbox is checked. If it's unchecked, the currently selected custom filter is removed from the dropdown list.

I am not sure what you mean by TDF.
Does this mean you will be able to create a filter in the filter bar, and then save it for future re-use? If so, that would be brilliant, especially if this also includes the custom attributes.
zajchapp

Just to add, I also find my situation similar in that the many times the tasks become many, such that it becomes difficult and even unproductive to actually find the data one is looking for(constant scrolling backand forth).

In addition to the filter, I truly think the ability hoist tasks in a separate sub tab of the same document - especially if the two panes can be juxtaposed would permit the user to quickly compare/view two parts of the same document

Also could you please clarify what you had meant about saving the filter as a url link? I asked if that feature was already available or not, but didn't receive a clarification onthat :(

Oh dear, that looks exactly like what I was describing. I think I've used that in the past and it's not just something in my "mind's eye" but was actually in my eye some time ago.

I've experimented with the functionality but I really don't understand some of the filters. Like what's expected in the relative modified date field? Any filter I create seems to return zero tasks, or seems to combine with the last save, or ... something... I'll need to experiment with creating, saving, and then applying the filters.

No problem at all. It sounds as though we will be able to save filters based on the selected filter state in V7, so that is fantastic, especially if the custom attributes are included in this. It would almost totally replace the need for the filters in 'Find Tasks'.

For the relative dates, if you want this month, type 'm', for the following month 'm+1' and so on. 'd' is for day, 'w' is for week etc... And I can't remember if 'm' is the start of this month or the end of this month - trial and error needed.

I have a set of filters I have created, so I can incorporate the custom attributes. The main difficulty currently is that you can't specify parentheses, so complex filters can be a challenge to design and input. Not that I am grumbling...
zajchap

I've made a few comments over the last couple months about separating different kinds of comments but I haven't thought about it enough until now to articulate the concepts.

I think there are four kinds of comments:

1) Comments about a task. This is part of the definition, the spec that tells us what the task is.

Comments on task activity. This is where we use the ctrl+D to document what's been done on a task as it happens. There are actually two kinds of activity comments:
2) Notes for people working on the task so that there is a detailed log of what's going on. These notes are not published in reports to clients or management. I'll refer to these as Internal Activity Comments
3) Notes for clients/management about general activity, issues, milestones. These notes are for reports. I'll refer to these as Public Comments.

4) Comments in time logs detail why the time is being logged. This could be for purposes 2 or 3 above, so we'd have Internal Log Comments and Public Log Comments.

How might we get from here to there?

We currently have two comment fields, the task comment and the time log comment. One quick/cheap way to separate comments is to use an unusual character in the text (alt-sequence) to separate Internal from Public comments. In XSL we can parse either side for specific report types. I do this to parse the first line of a comment as a task summary, using the EOL character as the delimiter. My code then checks the result to see if it's null before wrapping it in HTML. I can share my XSL. For time logs, the single comment field can similarly be parsed by a macro or other code that post-processes the CSV data. This DIY method can be used by anyone now with some discipline and XSL changes, but requires no effort by Dan.

Another mechanism requires code changes. Keeping the Comments field for all who use it, three new fields can be added to the tasklist schema for anyone who wishes to separate the concepts: TaskDescription, TaskInternalActivity, and TaskPublicActivity. Like Comments, each of these fields would be optionally PlainText or RTF. It would be up to anyone who desires to use these field to copy relevant parts of the existing Comments field to whichever field they wish. The general purpose Comments field can still be used by each individual for whatever purpose they wish, as it's used now, or in addition to the other fields. The UI would need to accommodate up to four comments blocks. The time log would also have another comment box added to separate Internal from Public comments, and the CSV would get a new related column.

As I sometimes do, I'm presenting a challenge that I have just to see if others have the same challenge. I've presented my thoughts for a solution but I'd be interested to know what others do or think.

I think 'comments' are sometimes a misnomer. Some times 'Notes' are a better name.

There is an additional comment 'type' - app / task / maintainer comments. "Set up this task with these fields ..."

I think the various comment types reflect more on the task type than on the comments. Arguably anything with sub-tasks are summary tasks, and only summary information should be present. Thus task execution comments might not belong in that record, but in a sub-record.

Arguably, for each comment type you note, there should be a corresponding sub-task within which the associated comment type would be entered. [You're almost suggesting a hierarchy of comments within a record, when that hierarchy organization is already inherently present at the task level - wheel reinventing?] Milestone, for example, is typically a standalone task. Or a summary task. (Bottom up vs top down, almost, depending upon your personal viewing preferences.)

It feels like you are groping towards sub-comments. If you instead consider summary tasks as the task, providing you a sub-hierarchy of task and therefore comment types, are you not already where you're trying to go? [I do get, given your musings, that the presentement that you are looking for may not currently be present - but is it possible that that is because of some lack in filtering / presentation facilities for where you're trying to go, which would be a different beastie? i.e. Enhancement request is not for comment sub-hierarchy but for a 'filter by tag plus other considerations' combination.]

More succinctly - treating sub-summary tasks as the task definition, and applying tags, is what you're looking for not already present?

Thanks @_BS_. I've thought about your comments carefully, mixed thoughts on each reconsideration. I do use a hierarchy of sub-tasks (project level task, parent task, child task) where the parent task is a container, not actually used for logging, and thus can be used to contain task definitions. One can assume here that the child tasks would be used purely for tracking activity, and their comments would have the related log data that I describe.

However, each child task needs its own description - why does this task exist such that it will be worked on separately? That can't always be summarized in the top line. So using your scenario I would need to use these child tasks as definition items and do my actual processing on grandchild tasks. In other words, each task that gets actual work would require an immediate parent to define that item. This doubles the number of task nodes in a list.

The problem is that while the structure is sound for some folks with some applications and with some additional handling, this is an imposed structure which may not conform to existing lists.

To back up a bit - To me, a task has many fields, and I find myself using the single Comments field for multiple purposes. I think it's quite reasonable to propose additional fields on the task to support this application, because I'm guessing that while most people haven't yet considered this to be an annoyance, now that we're talking about it I'd think some folks would see the value in enhancements in this area.

Here's another option - supporting additional data types on Custom Attributes: Text Area and Rich Text Area. Right now we just have a small text field suitable for tag-like text. I'm wondering if people use that for more text and just accept that they can't see the whole thing. Rather than having a new standard field to separate descriptions from comments, I'd be happy creating custom attributes for my own purposes. If course we'd also need another mod to set which custom attribute are displayed in the grid, and the edit block would need to adapt to support larger custom fields.

So in my initial note I proposed adding new fields and structuring the Comments field for these purposes. @_BS_ has proposed another mechanism. And here I propose yet another. I'd be interested in other comments and proposals.