Sunday 7 February 2010

Bloomin' 'eck! A new post!

Okay so I've been lazy and really neglected this project.

Excuses (not in any particular order):
1. Three year daughter find it boring when I code
2. Proper work has been busy
3. I built this bike: Shiny! Bike!
4. I broke my wrist.

But now I have a shiny rebuilt PC (excuse no.5) running Windows 7, and I have my VS2010 beta. So it is time to update Lizard so I can use it.

I've just been reading this:
http://msdn.microsoft.com/en-us/magazine/ee819091.aspx
and this:
http://blogs.msdn.com/clrteam/archive/2009/06/03/in-process-side-by-side-part1.aspx

It seems that now I can write all my shell extentions in managed .Net code, my diversions into the land of c++ are no longer required. Hoorah!

Now I must find my old code, dust it off, fix it, and find out what I can use now the windows explorer API IColumnProvider has been deprecated.

I've pretty much completed the manual three way diff/conflict resolver too.

Hope this isn't too late for everybody,

Ian.

Wednesday 3 June 2009

SelectedIndexChanged and again! and again! and again!

If you have a ListView, and it has MultiSelect enabled and you select a row, then scroll down, say, 100 rows, and shift-click, how many SelectedIndexChanged events do you expect? How many do you get? 100, of course, one for every row that had a selection change. You get no special EventArg to let you know this is one of a set, or how many you might expect. As far as the eventing is concerned each highlighted row is wonderous occasion in its own right.

I've got a ListView that shows TFS changesets, when I click on one (in the middle in this example) another list populates that shows all the files in that changeset (nifty, eh?). When I shift-click on another row way down the list, I want to see all the files in that set of changesets. Using my trusted SelectedIndexChanged to let me know the selection has changed, I get oodles of lovely events and can refresh my list of files. If I shift-click right up near the top of the list I get an event for each of the rows being de-selected on one for each of the new rows being selected.

This is not what I want. Now I know that I can use each event to add/remove files from my other list, but because I'm merging data where the same file is in two changesets (to get a combined list of change types), this gets complicated. All I want is one event to tell me that SomeSelectionIndicesChanged. Then I can clear the file list, and re-populate it.

Here is some code to do just that. I don't like the gratuitous use of threads like this, but in WinForm apps, you rarely have more than one instance of the app, and users don't normally do complex multi-row selections on several ListViews at once, so there is little danger of weird concurrency issues. All it does is every time a SelectedIndexChanged is raised, it waits 1/10th second and then raises a new AfterMultiSelect event, if another SelectedIndexChanged occurs in that time, it stops and starts waiting again. If a SelectedIndexChanged occurs after the 1/10 second, but before the AfterMultiSelect has finished being handled, that doesn't matter because it's being handled back on the controls own thread.

Anyway, the code:

using System;
using System.Windows.Forms;
using System.Threading;

namespace Project.ControlManagers
{
public class ListManager
{
private ListView listView;
private delegate void SelectionChange();

public event EventHandler AfterMultiSelection;

public ListController(ListView listView)
{
this.listView = listView;
// listen for all the change events
listView.SelectedIndexChanged += new EventHandler(listView_SelectedIndexChanged);
}

Thread t = null;
void listView_SelectedIndexChanged(object sender, EventArgs e)
{
ThreadStart ts = new ThreadStart(QueueSelectionChange);
// if we already had a thread, kill it
if (t != null)
t.Abort();

// start a new thread to process the event
t = new Thread(ts);
t.Start();
}

void QueueSelectionChange()
{
// have a nap. in this time if another SelectedIndexChanged event is fired this thread will
// be aborted and nothing more will happen.
Thread.Sleep(100);
// invoke the call to raise the new event on the ListViews thread, not this one
// otherwise things will go awry
SelectionChange sc = ProcessSelectionChange;
listView.Invoke(sc);
t = null;
}

void ProcessSelectionChange()
{
// if anyone is listening raise the AfterMultiSelection event
if (AfterMultiSelection != null)
AfterMultiSelection(listView, new EventArgs());
}
}
}


I wouldn't be at all surprised if someone didn't have a good reason not to do this. The same technique can be used to do something after a user has stopped scrolling or resizing something if the work you want to do post scroll/resize is rather expensive and looks crappy if it happens on every scroll/resize event.


Footnote: This is too slow for hundreds of rows, but seems fine for a couple of dozen or so.

Monday 13 April 2009

TF10130: '...' is a reserved name and may not be included in a path.

I was just testing some of Lizard when I got this error:
TF10130: 'Con' is a reserved name and may not be included in a path.
from this line:
string serverItem = workspace1.TryGetServerItemForLocalItem(localItem);

Where localItem = "c:\...\Con"

Googling the error I found that other people had found that Com1 is reserved, but there is no obvious list of reserved names. MS documentation on TF error messages isn't much use either (http://msdn.microsoft.com/en-us/library/aa337645(VS.80).aspx).

Anyone know anything more about reserved names?

Thursday 8 January 2009

Happy Birthday LizardTF!

I just realised that yesterday was the birthday of this blog and in two days it's a year since the first release (that was 0.1.3, I'm not sure what happened to 0.1.0,1,2)

It feels like so much longer!

Thanks to everyone who has supported Lizard though comments and suggestions, please keep it up,

Thanks,

Ian.

Merging and Rollbacks

Recent work has been now been focussed on finishing of the functions that I've been planning from the beginning, that got left behind for the extension re-write.

No new builds yet, but the source is coming along. I've had to spend some time re-familiarising myself with the folder diff engine, the gnu diff integration and the scintilla.Net controls. Finally I cleared up some rather tatty code behind the 3-way diff visualiser. This is neatly laid out in a set of classes under LizardDiff.Diff3Docs, one class per view, instead of a big single mess.

New features are:
  • Uncontrolled Changes in Lizard Review - see changes to files not checked out, new files added to TFS controlled folders but not 'added' and files deleted from the file system but not from TFS. This was a popular request.
  • Create Patch from the Folder Compare screen; you can build/save a gnu unified diff based patch file from the difference found by the comparer.
  • Proper (and improved) version browsing from the Folder Compare screen
  • Rename Tracking when comparing file system to TFS or TFS to TFS when 'to' and 'from' have the same repository path. This is done be parsing the changesets between 'to' and 'from' for renames. These are displayed in the output.
  • 2 Way Diff now shows numbers of Inserts, Changes and Deletions.

The next step is to manage applying the generated patch file to another folder/branch and list updated files and conflicts, and allow conflict resolution through the diff/merge tool. This be the 'Lizard Merge' tool, and will allow merging across any folders, 2nd/3rd, etc generation branches as well as strict TFS 1st generation branches. This will also become the 'Lizard Rollback' tool by taking the difference between a higher and lower change set (rather than lower to higher) and applying to the higher version.

All the current work is being checked into the .Net 2.0 branch, and will be merged into the 3.5 branch (using Lizard Merge) prior to the next.

I'll have to check my notes, but I think that will make LizardTF feature complete and ready for Beta!

Sunday 9 November 2008

Swiftly followed by 0.3.1

I've ironed out some install issues, hopefully now it is much simpler to install, get the Tortosie Overlays installed, clean up old installs etc.
The current checked in source code has an extra option to replace the standard Tortoise overlays for 'Unversioned' and 'Ignored' with the LizardTF ones for 'Out of date' and 'Checked-in but modified'. I was going to replace the release with this but I have to check them first, so they are in as a planned release 0.3.2.

Most of my work has been trying to get a decent build for those who want to download the source and build their own. To this end there are various prebuild and postbuild .bat files that stop and start explorer and movc various dependeny files around. It's all a lot more fiddly than I wanted. A lot of the problems come from the main build having to always target x86 (so they can call the TFS client API dlls), and the extentions having to target the right platform for the OS. I've been using the 'Batch Build' option to build both x86 and x64 versions of the extensions and x86 versions of everything else, except the Lizardx64Registry project. This is a command line .exe app that sets/tests various registry settings. If you are running a 64bit OS this is needed to change the main registry that the x64 extensions and TortoiseOverlays use. This is needed because as the main application is all built for x86 it only accessed the WoW parts of the registry. Only by calling an Out-Of-Process command line can I easily modify HK_LocalMachine for x64 applications.

I've changed the way the meta-data cache folder is structured. Rather than all the folder path hashes going straight into the root meta-data folder, I've split them up by first charactor, then second charactor. This is to prevent getting overly populated folders. Any one who was using Lizard 0.3.0 will need to re-parse their folders, and should delete any folder with a name more the 1 char long from the meta-date folder.

I think it's all in place now, I think all the necessary files are in the right places. I'll hopefully be testing on x86 hardware during the week. Everything seems good on x64 so far.

Also new is the whole new build for dotNet 3.5 - and associated VS9 solution branch. All the source is the same as the dotNet 2.0 branch except the .sln, .csproj, .vcproj and .vdproj files. I can't see any real benefit of using Linq or lambda expressions in Lizard right now, so it will probably stay that way.

I've started using the WorkItem support provided by CodePlex, so feel free to raise any issues as WorkItems, or just add a comment to the Blog. Now the really big structural change is out of the way I should be turning aroung smaller issues much faster.

Please let me know if you have problems gettings either the msi or source code up and running, and I'll do what I can.

Sunday 19 October 2008

LizardTF alpha0.3.0 Has Landed!

Release posted and source code in Codeplex is up to date.

I will be testing the release over the next few days.

New features include:

All c++ Explorer extensions - no more loading the CLR into the shell
Multi server support - Have working folders for Codeplex and local TF Servers
Paged history - get revision logs in smaller chunks
History through branches - see history belonging to originating branches

More to follow...