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.

I tried implementing the focus change it but I was very unhappy with the resulting delayed re-creation of the task, as it is so unlike any other part of the app.

So I'm trying an alternative approach which is to always pop up the calendar whenever the date checkbox is ticked, either by clicking with the mouse or by pressing spacebar when the field has the focus. This allows the entire process to be completely modally by both keyboard and mouse. And when the calendar is closed the re-creation takes place.

I was thinking of applying this behaviour to just the Completion date but that could appear really inconsistent so I will demo it in RC4 for all the date fields and then we can see how that looks and feels.

I've had this happen only on 7.0 RC2 and RC3. I got a message saying a "SONAR.PUA!gen5" virus has been detected. I said remove the threat on RC2 and it deleted ToDoList.exe and two .tdl files. When it happened again on RC3 I told Norton to ignore the threat...and so far so good. Norton did a quick virus scan today on my system and did not find any threats. I'll post a note here on CodeProject if Norton detects anything wrong with TDL in the future.

I posted back in June against 7.0 RC1 that Symantec had flagged RC1 as having suspicious file download activity. For RC1 it quarantined the exe, the ini, and the tdl file I was working on, so I was able to recover.

SONAR.SuspBeh!gen476 is a heuristic detection that is designed to detect suspicious file downloads.

It did the same for RC2, but had upped the severity and that time deleted the three files, exe, ini, and tdl. I had to recovery from backup!!!

I suspect it is happening when you check for updates and update from within TDL. Symantec's SONAR heuristics is detecting that as suspicious download activity. I am downloading the new version from the forum and doing a fresh install, which seems to avoid Symantec deleting my tdl.

The network guy where I'm working found he could whitelist TDL, but only for specific versions that Symantec knew about. Verison 7.0 appear to Symantec to have a verison of 6.9_9999, ie. not 7.0 but I think that is Dan's versioning for A/B/RC releases.

So short answer for me was to fresh install new version, don't allow TDL to update.....and BACKUP your tdl!

I have a suspicion that the visibility of the versions comes from the app/version being detected by the installed clients (ie. my PC) and reporting back to the Symantec Endpoint server (this is all Symantec ie. enterprise version of Norton's). Once the Symantec server knows about the app/version the Symantec administrator can then whitelist the app/version.

I'm drawing this from the network guys where I work were telling me they could select a number of different versions of TDL but not the current version I had just installed. I think they could see versions that my PC had installed in the past. They always could see the previous version, but I was tending to install the new RC versions pretty quickly, so they had seen the new version before TDL did a update check (I have now disabled the update check on startup), and I think the update check, or updating TDL from the Help menu was triggering the SONAR exception.

I was confused too by why your AV would also quarantine the .tdl and .ini files and then I realised that if both files were UTF16 encoded with a BOM at the start (the .ini definitely and your .tdl maybe) the AV might treat them as binary files and therefore also suspicious.

...or it could be that TDL had file handles open to the ini and tdl files, and Symantec just quarantined all files related to the app/process that triggered the exception - it may have though the ini or tdl file where the 'suspicious files downloaded'?

Should the tdl and ini be UTF-16? I can confirm that are currently both UTF-16 encoded, and both with BOMs.

I guess changes in recurrence dialog are guilty for the problem encountered.

bug:
In every tabs (Task Occurs), selecting Recreate new task ... is greying the Calculate next occurrence button, but if one change the Task Occurs and come back to initial setting, the Calculate next occurrence button is not greyed any more.

What is the intend of this if the greying is not a bug?

Patrice

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

Can you describe what the ideal tool would do?
What features would you like to see?
How would you like to see data in a format that would help?

I'm thinking it might be cool to use TDL itself for something like this:
- Each language is a task.
- Each phrase is a sub-task.
- Use XLST to generate csv files rather than HTML.
- A custom field can be used to provide the actual translation.
- Comments can be used to explain the translations if required.
- The TDL files can be posted for collaboration just like any other file.

I've never even looked at the language CSVs but I'd be willing to try this if you think it's worth it. I should be able to use the library to build the initial .tdl files from the CSVs.

I think that option is quite elegant because it is all free and the environment is familiar to everyone here.

Now if that is Not as elegant as it sounds, with your description of desired features I might be able to whip up a utility that will help - and of course it will build the exact files that we need where other tools may not.

Thanks for your offer, but my message was rather aimed to people with translation experience.

About Translation.csv files, a translation software will be of little use until one can tell it that column 1 is English and column 2 is YourLanguage and that translations from column 1 are populating column 2.
But since the translation file format can deal with out of synch translations, I don't see any other really better solution.

iamstarbuck wrote:

Can you describe what the ideal tool would do?

For now, I am mainly curious since I have no experience with such a tool.

My small experience with French translation tells me that context is important. So splitting the wiki pages to sentences may not be the best idea.

Patrice

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

OK, my experience with translation is limited to a chemistry book, a math book, and other technical material so that won't apply here. And while I have taught language classes I don't have any experience writing translation software or with I18N of specific apps, so I might be of no use to you here.

Off hand, it sounds like you're talking about a spreadsheet. but I was thinking more along the lines of an intelligent grid or treeview which can be pivoted in different ways.

What's wrong with my suggestion for doing this in TDL where each phrase is assigned a task number (the row of the translation file perhaps?)? The title can be the English text. Then one subtask is created for each language. It would be easy to filter for a specific language or for missing translations, and then to do a transform to generate an update to the CSV.

As a final (?) suggestion (given that I still don't feel like I understand the problem that's to be solved) is an app called Scrivener. I've recently purchased this, which caters to authors who write fiction and non-fiction books, playwrights, legal contract writers, and anyone else who needs to organize volumes of material. It's U$40 from the company[^] but $25 from AppSumo[^].

In short that software allows an author to group small or large blocks of text in many ways, and then to publish them in different ways. So while I haven't tried this I'm thinking about a template where each term or phrase is contextually identified and cloned out to every language. A translator would be able to show a view of that phrase for all languages, fill in what's missing, then render the text back to individual language files.

So my suggestions revolve around parsing the files into a format that can be filtered, edited, then re-assembled. Is that not what you're thinking?

And about the wiki, please don't spend any time translating existing wiki pages yet. They're undergoing heavy modifications and I wouldn't want anyone to translate a page, only to have it completely re-written a day later. I worked on a project where someone eagerly jumped to translate beta software docs to Spanish, but when the docs had to be revised he completely lost heart and didn't want to translate the production docs - of course that meant the entire effort was wasted.

OK, my experience with translation is limited to a chemistry book, a math book, and other technical material so that won't apply here. And while I have taught language classes I don't have any experience writing translation software or with I18N of specific apps, so I might be of no use to you here.

May be I should have said experience with translation software

iamstarbuck wrote:

What's wrong with my suggestion for doing this in TDL where each phrase is assigned a task number (the row of the translation file perhaps?)?

Just my feeling
My experience with French translation is that when text is split in pieces, context is lost. And it complicate things when it comes to translation.

iamstarbuck wrote:

Scrivener

I will give it a try

iamstarbuck wrote:

please don't spend any time translating existing wiki pages yet.

Not planned yet.

Patrice

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

Hello Dan.
I always use the transform function to export the tasklist to html page, and I refered the existed StyleSheets sample to rework my owne project report format.
I want to export milestone png image in the html page,not use an img element style,but embedded png image,like add an image file in the todolist comments.
How can I finish it with xls language and todolist?

Pretty much what iamstarbuck said.
I haven't played with this for a while, and have forgotten some of the detail, but I seem to recall that ideally the image file and TDL are on the C drive (can't quite remember why but something to do with the temp file being created on C drive, and restrictions on grabbing images from other drives).
I run TDL from the D drive, and had all sorts of issues...

Patrice also posted about problems caused by TDL updating the task as soon as the 'drop-button' is clicked, so I'm fixing it to always wait until the calendar closes. Hopefully that will resolve all the issues.

ps. I wasn't able to reproduce the 'disappearing tick' once the calendar closes, as shown in your video.
pps. The appearance of the 'tick' as soon as the drop-button is clicked is part of the underlying Windows widget behaviour and I have found no way to override this.

Patrice also posted about problems caused by TDL updating the task as soon as the 'drop-button' is clicked, so I'm fixing it to always wait until the calendar closes. Hopefully that will resolve all the issues.

Another issue on same field.
Rather than using the calendar dropbox, I (try to) use the keyboard.
After checking the checkbox, I click on the date (in edit field) and use the keyboard arrows to select a part of the date to change it.
Just after the first up/down arrow, history is generated and field loose focus.

I think that the solution would be to wait until the field loose focus to apply to changed date and generate history.

Patrice

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

For anyone confused about what's going on at GitHub, here's a summary:

The intent is to create a place where people can contribute to this fine software in different ways. GitHub hosts "repositories" which include a place for files, wiki, and issues. Dan has created several repos for specific purposes. The idea is to keep concepts separate and focused, and downloads small.

On Dan's GitHub profile page[^], we see a list of the repos that he has created.

ToList_Wiki[^] : This is the home for all documentation. It's growing rapidly with contributions and is a bit chaotic, but we'll manage that. When things stabilize, please report issues with the wiki to the Issues are for this specific repo. The wiki repo issue tracker is not for software issues, it's for issues with the wiki. You'll see a trend here soon...

ToDoList_Resources[^] : This is for non-core files that are bundled in the TDL download. This includes stylesheets, themes, and translation files. If you want to contribute in this area, visit this repo, read the ReadMe, post related Issues for that specific repo.

ToDoList_Issues[^] : This is where issues with the software will be hosted. Issues reported in this CodeProject forum should be duplicated there once there is a clear definition of the problem. This helps all of us to see what's wrong with the software, what enhancements have already been proposed, etc. Once again, this is a repo, but we're only using the Issues area, and this is just for the "core" software itself.

ToDoList_Downloads[^] : This repo was created to offload larger files so that the Zip download from other repos weren't too bulky with data that most people wouldn't use anyway. In particular, spell-check dictionaries for a Lot of languages are hosted here as zip files. This repo will also be used for some user contributions, scripts, UDTs, and other materials that don't fit into Resources. If there are issues with the Downloads, report them in the Downloads repo issue tracker. The wiki for this repo will be used to document user contributed contents of this repo. The spell-check files will be documented in the wiki of the Wiki repo, since this is a core feature.

ToDoList_Discussions[^] : This is more of a wiki-only repo where pages will be used to host discussions about specific topics. This is a bit weird for all of us. The idea is to have a page where concepts are discussed and whittled down to a focused set of definitions for change. The final conclusion of such a page should then be summarized in an Issues item in ToDoList_Issues. This CodeProject area remains the main area for all discussions and questions about general topics. The Discussions repo is for more focused debates about nuances on specific topics. The purpose is to try to eliminate some of the confusion we see from long threads in this poor forum which tend to get lost in the paging mechanism here.

More information about each repo will be made available in the ReadMe for each repo. A summary like this will be hosted in the wiki. A final index will also be provided that says something like:
- To report issues with the software, go here.
- To report issues with stylesheets, go here.
- For wiki information about UDTs, go here. ...

That might be the go-to page for all newcomers, the jumping off page for all needs. Just go to the index and jump from there to whatever repo/tracker/wiki that seems to fit your need.