Now we can start talking. I downloaded the gcvs 1.01 version from sourceforge
and tried to compile. It failed in different places than where yours did. 
TclGlue compiled correctly and I have below the compile line which is the 
same as yours:

g++ -DHAVE_CONFIG_H -I. -I. -I.. -I../gcvs -I../gcvs/src -I/. -I../cvstree 
-I../rf  -Wall -I/usr/include/gtk-1.2 -I/usr/include/glib-1.2 
-I/usr/lib/glib/include -I/usr/X11R6/include -DqUnix -DqGTK 
-I/usr/X11R6/include -DqCvsDebug=0  -g -O2 -I/usr/local/include/. 
-DUSE_TCL="1" -c TclGlue.cpp

What did fail were UCvsFiles.cpp and UcvsFolders.cpp. These both suffer from 
the same problem of typecasting on an overloaded function called ResetView. I 
have attached both amended sources so you can compare. It also appears that 
the version you have is also suffering from typecasting problems.

Keep Cool


On Saturday 09 October 2004 00:20, Gregory Smirnov wrote:
> Hello,
>
> The point was that you cannot build completely all available packages on
> the fly in gentoo, like someone told here.
>
> I work in KDE environment too, but I guess you have gtk libraries
> installed. If you don't want to try, then there no point to continue
> discussion. I live fine without this gui wrapper.
>
> Regarding subversion, do not forget to update it every week to patch new
> bugs.
>
> Cheers,
> Gregory
>
> --- FYI ---
> g++ -DHAVE_CONFIG_H -I. -I. -I.. -I../gcvs -I../gcvs/src -I/. -I../cvstree
> -I../rf  -Wall -I/usr/include/gtk-1.2 -I/usr/include/glib-1.2
> -I/usr/lib/glib/include -I/usr/X11R6/include -DqUnix -DqGTK
> -I/usr/X11R6/include -DqCvsDebug=0  -O2 -march=athlon-xp
> -fomit-frame-pointer -I/usr/include -DUSE_TCL="1" -c TclGlue.cpp
> TclGlue.cpp: In function `int tclCvsBrowserProc(void*, Tcl_Interp*, int,
>    char**)':
> TclGlue.cpp:444: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:449: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:453: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:458: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:463: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:468: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:473: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:478: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:483: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:488: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:495: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:500: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:505: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:510: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp:515: error: invalid conversion from `const char*' to `char*'
> TclGlue.cpp: In function `int tclCvsEntriesProc(void*, Tcl_Interp*, int,
>    char**)':
> TclGlue.cpp:647: error: invalid conversion from `int (*)(void*,
> Tcl_Interp*, int, char**)' to `int (*)(void*, Tcl_Interp*, int, const
> char**)' TclGlue.cpp: In constructor `CTcl_Interp::CTcl_Interp()':
> TclGlue.cpp:968: error: invalid conversion from `int (*)(void*,
> Tcl_Interp*, int, char**)' to `int (*)(void*, Tcl_Interp*, int, const
> char**)' TclGlue.cpp:971: error: invalid conversion from `int (*)(void*,
> Tcl_Interp*, int, char**)' to `int (*)(void*, Tcl_Interp*, int, const
> char**)' TclGlue.cpp:973: error: invalid conversion from `int (*)(void*,
> Tcl_Interp*, int, char**)' to `int (*)(void*, Tcl_Interp*, int, const
> char**)' TclGlue.cpp:975: error: invalid conversion from `int (*)(void*,
> Tcl_Interp*, int, char**)' to `int (*)(void*, Tcl_Interp*, int, const
> char**)' TclGlue.cpp:977: error: invalid conversion from `int (*)(void*,
> Tcl_Interp*, int, char**)' to `int (*)(void*, Tcl_Interp*, int, const
> char**)' TclGlue.cpp:979: error: invalid conversion from `int (*)(void*,
> Tcl_Interp*, int, char**)' to `int (*)(void*, Tcl_Interp*, int, const
> char**)' TclGlue.cpp:987: error: invalid conversion from `int (*)(void*,
> Tcl_Interp*, int, char**)' to `int (*)(void*, Tcl_Interp*, int, const
> char**)' TclGlue.cpp:990: error: invalid conversion from `int (*)(void*,
> Tcl_Interp*, int, char**)' to `int (*)(void*, Tcl_Interp*, int, const
> char**)' TclGlue.cpp:993: error: invalid conversion from `int (*)(void*,
> Tcl_Interp*, int, char**)' to `int (*)(void*, Tcl_Interp*, int, const
> char**)' TclGlue.cpp:1234:2: warning: no newline at end of file
> make[2]: *** [TclGlue.o] Error 1
> make[2]: *** Waiting for unfinished jobs....
>
> ---
>
> On Friday 08 October 2004 07:40, Andrew Cilia wrote:
> > That won't help much. Besides, I'm set up over KDE only. Just try the
> > compilation at your end and post the screen messages to the group.
> >
> > BTW, you might want to take a look at subversion if you're into version
> > control.
> >
> > On Friday 08 October 2004 01:28, Gregory Smirnov wrote:
> > > Yes. I meant gcvs. Just try to build it. If you manage to build without
> > > errors then we will go in details. Errors I think was with gnome
> > > libraries. Last time I tried to build it about 3 month ago. If I don't
> > > forget, then will try tomorrow. I use Gentoo at work and debian on my
> > > lap.
> > >
> > > Cheers,
> > > Gregory
> > >
> > > On Thursday 07 October 2004 23:04, Andrew Cilia wrote:
> > > > OK, now assuming that you meant gcvs, what errors are you getting?
> > > >
> > > > On Wednesday 06 October 2004 19:11, Gregory Smirnov wrote:
> > > > > give me a hint what viagra my Gentoo lacks to build gsvs?
> > > > >
> > > > > :-) Gregory
> > > > >
> > > > > _______________________________________________
> > > > > MLUG-list mailing list
> > > > > [email protected]
> > > > > http://mailserv.megabyte.net/mailman/listinfo/mlug-list
> > >
> > > _______________________________________________
> > > MLUG-list mailing list
> > > [email protected]
> > > http://mailserv.megabyte.net/mailman/listinfo/mlug-list
>
> _______________________________________________
> MLUG-list mailing list
> [email protected]
> http://mailserv.megabyte.net/mailman/listinfo/mlug-list

-- 
Andrew Cilia B.Sc. MCSE ICSE RHCT
Software Engineer
___________________________________
Philip Toledo Limited
Computer & Communications Solutions
Notabile Road, Mriehel BKR01, Malta

Telephone:+356 21445566
Mobile:    +356 99430588
Fax:        +356 21484316
Email:     [EMAIL PROTECTED]
Web Site: http://www.ptl.com.mt
/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 1, or (at your option)
** any later version.

** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.

** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
 * Author : Alexandre Parenteau <[EMAIL PROTECTED]> --- February 2000
 */

/*
 * 
 */

#include "stdafx.h"

#if qGTK
#	include <gtk/gtk.h>
#endif

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "UCvsFolders.h"
#include "UCvsDialogs.h"
#include "UCvsApp.h"
#include "UCvsFiles.h"
#include "UCvsCommands.h"
#include "UCvsFrame.h"
#include "MultiString.h"
#include "FileTraversal.h"
#include "CvsEntries.h"
#include "CvsPrefs.h"
#include "AppConsole.h"
#include "CvsCommands.h"
#include "TclGlue.h"
#include "MacrosSetup.h"
#include "CvsArgs.h"

#ifdef WIN32
static PCPStr gOldLoc("P_BrowserLoc", "C:\\");
#endif

#ifdef qUnix
static PCPStr gOldLoc("P_BrowserLoc");
#endif

static const char *gDummyFile = "@@@dummy file@@@";

static CMString gHistoryLocs(100, "P_BrowserLocs");

static void *sFolderIcon;
static void *sFolderUnknownIcon;
static void *sFolderIgnoredIcon;
static void *sFolderMissingIcon;

enum
{
	kIconFolderClosed,
	kIconFolderOpened,
	kIconFolderCVSClosed,
	kIconFolderCVSOpened,
	kIconFolderIgnoreClosed,
	kIconFolderIgnoreOpened,
	kIconFolderIgnoreLost
};

UIMPLEMENT_DYNAMIC(UCvsFolders, UWidget)

UBEGIN_MESSAGE_MAP(UCvsFolders, UWidget)
	ON_UUPDATECMD(cmdUPDATE, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdCOMMIT, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdDIFF, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdEDIT, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdEDITORS, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdLOCKF, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdLOG, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdRELEASE, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdSTATUS, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdUNEDIT, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdUPDATE, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdQUERYUPDATE, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdUNLOCKF, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdWATCHERS, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdWATCHON, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdWATCHOFF, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdTAGNEW, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdTAGDELETE, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdTAGBRANCH, UCvsFolders::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdADD, UCvsFolders::OnCmdUIAdd)
	ON_UUPDATECMD(cmdEXPLORE, UCvsFolders::OnCmdUIExplore)
	ON_UUPDATECMD(cmdRELOAD, UCvsFolders::OnCmdUIReload)
	ON_UUPDATECMD(cmdIGNORE, UCvsFolders::OnCmdUIIgnore)
	ON_UUPDATECMD(cmdCHECKOUT, UCvsFolders::OnCmdUICheckout)
	ON_UUPDATECMD(cmdIMPORT, UCvsFolders::OnCmdUIImport)
	ON_UUPDATECMD_RANGE(cmdSELMACRO, cmdSELMACROEND, UCvsFolders::OnCmdUIMacrosSel)
	ON_UDESTROY(UCvsFolders)
	ON_UCREATE(UCvsFolders)
	ON_TREE_EXPANDING(kUMainWidget, UCvsFolders::OnTreeExpanding)
	ON_TREE_SELECTING(kUMainWidget, UCvsFolders::OnTreeSelecting)
	ON_UCOMMAND(cmdUPDATE, UCvsFolders::OnCmdUpdate)
	ON_UCOMMAND(cmdADD, UCvsFolders::OnCmdAdd)
	ON_UCOMMAND(cmdCOMMIT, UCvsFolders::OnCmdCommit)
	ON_UCOMMAND(cmdQUERYUPDATE, UCvsFolders::OnCmdQueryUpdate)
	ON_UCOMMAND(cmdDIFF, UCvsFolders::OnCmdDiff)
	ON_UCOMMAND(cmdLOG, UCvsFolders::OnCmdLog)
	ON_UCOMMAND(cmdSTATUS, UCvsFolders::OnCmdStatus)
	ON_UCOMMAND(cmdLOCKF, UCvsFolders::OnCmdLock)
	ON_UCOMMAND(cmdUNLOCKF, UCvsFolders::OnCmdUnlock)
	ON_UCOMMAND(cmdWATCHON, UCvsFolders::OnCmdWatchOn)
	ON_UCOMMAND(cmdWATCHOFF, UCvsFolders::OnCmdWatchOff)
	ON_UCOMMAND(cmdEDIT, UCvsFolders::OnCmdEdit)
	ON_UCOMMAND(cmdUNEDIT, UCvsFolders::OnCmdUnedit)
	ON_UCOMMAND(cmdWATCHERS, UCvsFolders::OnCmdWatchers)
	ON_UCOMMAND(cmdEDITORS, UCvsFolders::OnCmdEditors)
	ON_UCOMMAND(cmdRELEASE, UCvsFolders::OnCmdRelease)
	ON_UCOMMAND(cmdTAGNEW, UCvsFolders::OnCmdTagNew)
	ON_UCOMMAND(cmdTAGDELETE, UCvsFolders::OnCmdTagDelete)
	ON_UCOMMAND(cmdTAGBRANCH, UCvsFolders::OnCmdTagBranch)
	ON_UCOMMAND(cmdEXPLORE, UCvsFolders::OnCmdExplore)
	ON_UCOMMAND(cmdRELOAD, UCvsFolders::OnCmdReload)
	ON_UCOMMAND(cmdIGNORE, UCvsFolders::OnCmdIgnore)
	ON_UCOMMAND(cmdCHECKOUT, UCvsFolders::OnCmdCheckout)
	ON_UCOMMAND(cmdIMPORT, UCvsFolders::OnCmdImport)
	ON_UCOMMAND_RANGE(cmdSELMACRO, cmdSELMACROEND, UCvsFolders::OnCmdMacrosSel)
UEND_MESSAGE_MAP()

#if 0
	ON_WM_RBUTTONDOWN() // TODO
#endif

static bool sTemporaryTurnOffNotify = false;

class CTempToggleBool
{
public:
	CTempToggleBool(bool & value) : m_value(value), m_didSetIt(false)
	{
		if(!m_value)
		{
			m_didSetIt = true;
			m_value = true;
		}
	}

	~CTempToggleBool()
	{
		if(m_didSetIt)
			m_value = false;
	}
protected:
	bool & m_value;
	bool m_didSetIt;
};

static void *GetIcon(UCvsFolders *treeCrtl, UTREEITEM item, bool hasCvsInfos, bool expand, EntnodeData *data)
{
	int newImage;
	void *result = 0L;

	if(data == 0L)
	{
		if(expand)
			newImage = hasCvsInfos ? kIconFolderCVSOpened : kIconFolderOpened;
		else
			newImage = hasCvsInfos ? kIconFolderCVSClosed : kIconFolderClosed;
	}
	else
	{
		if(expand)
		{
			if(data->IsIgnored())
				newImage = kIconFolderIgnoreOpened;
			else if(data->IsUnknown())
				newImage = kIconFolderOpened;
			else if(data->IsMissing())
				newImage = kIconFolderIgnoreLost;
			else
				newImage = kIconFolderCVSOpened;
		}
		else
		{
			if(data->IsIgnored())
				newImage = kIconFolderIgnoreClosed;
			else if(data->IsUnknown())
				newImage = kIconFolderClosed;
			else if(data->IsMissing())
				newImage = kIconFolderIgnoreLost;
			else
				newImage = kIconFolderCVSClosed;
		}
	}

#if qGTK
	void *pixmap = 0L;
	switch(newImage)
	{
	case kIconFolderClosed:
	case kIconFolderOpened:
		pixmap = sFolderUnknownIcon;
		break;
	case kIconFolderCVSClosed:
	case kIconFolderCVSOpened:
		pixmap = sFolderIcon;
		break;
	case kIconFolderIgnoreClosed:
	case kIconFolderIgnoreOpened:
		pixmap = sFolderIgnoredIcon;
		break;
	case kIconFolderIgnoreLost:
		pixmap = sFolderMissingIcon;
		break;
	}
	if(pixmap != 0L)
	{
		result = gtk_pixmap_new (GTK_PIXMAP(pixmap)->pixmap, GTK_PIXMAP(pixmap)->mask);
	}
#endif

	return result;
}

// regarding a path and a root item, create an
// item with a dummy item inside if and only if
// the folder is not empty.
class TBrowserFillDummy : public TraversalReport
{
public:
	UTREEITEM	m_root;
	UTREEITEM	m_item;
	UCvsFolders	*m_treeCtrl;
	bool		m_empty;
	bool		m_hascvs;
	EntnodeData *m_data;
	UStr		m_dirname;

	TBrowserFillDummy(UCvsFolders *treeCtrl, UTREEITEM root, UTREEITEM item, EntnodeData *data) :
		m_root(root), m_item(item), m_treeCtrl(treeCtrl), m_empty(true),
		m_hascvs(false), m_data(data) {}

	virtual ~TBrowserFillDummy() {}

	virtual kTraversal EnterDirectory(const char *fullpath, const char *dirname, const FSSpec * macspec)
	{
		m_dirname = dirname;
#if qUnix
		if(m_dirname.empty())
			m_dirname = fullpath; // '/'
#endif
		return kContinueTraversal;
	}

	virtual kTraversal ExitDirectory(const char *fullpath)
	{
		if(m_item == 0L)
		{
			UTREE_INSERT insert;
			insert.parent = m_root;
			insert.icon = GetIcon(m_treeCtrl, m_item, m_hascvs, false, m_data);
			insert.title = m_dirname;
			insert.data = 0L;
			UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_INSERT, kUMainWidget, &insert);
			m_item = insert.result;
		}

		// assign the entries to this item
		UTREE_INFO query;
		query.item = m_item;
		if(m_data != 0L)
		{
			UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);
			EntnodeData *data = (EntnodeData *)query.data;

			if(m_data != 0L)
				m_data->Ref();

			query.data = m_data;
			UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_SETDATA, kUMainWidget, &query);

			if(data != 0L)
				data->UnRef();
		}
		else
		{
			UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);
			m_data = (EntnodeData *)query.data;
		}

		if(m_empty)
			return kContinueTraversal;

		// add a dummy item to simulate the folder
		// is not empty. This dummy item will be
		// replaced by a complete listing when the
		// node is expanding...

		UTREE_INSERT insert;
		insert.parent = m_item;
		insert.icon = 0L;
		insert.title = gDummyFile;
		insert.data = 0L;
		UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_INSERT, kUMainWidget, &insert);

		return kContinueTraversal;
	}

	virtual kTraversal OnError(const char *err, int errcode)
	{
    cvs_err(err);
    cvs_err("\n");
    cvs_err(strerror(errcode));
    cvs_err("\n");
		return kTraversalError;
	}

	virtual kTraversal OnIdle(const char *fullpath)
	{
		return kContinueTraversal;
	}

	virtual kTraversal OnDirectory(const char *fullpath,
		const char *fullname,
		const char *name,
		const struct stat & dir, const FSSpec * macspec)
	{
#if qUnix
		if(strcmp(name, "CVS") == 0)
#else
		if(stricmp(name, "cvs") == 0)
#endif
			m_hascvs = true;
		else
			m_empty = false;

		return kSkipFile;
	}
};

// regarding a path and a root item, create an
// item with all the subdirectories inside.
class TBrowserFill : public TraversalReport
{
public:
	UTREEITEM m_root;
	UTREEITEM m_item;
	UCvsFolders *m_treeCtrl;
	CSortList<ENTNODE> & m_entries;
	std::vector<UStr> m_ignlist;

	TBrowserFill(UCvsFolders *treeCtrl, UTREEITEM root, UTREEITEM item, CSortList<ENTNODE> & entries) :
			m_root(root), m_item(item), m_treeCtrl(treeCtrl),
			m_entries(entries) {}

	virtual ~TBrowserFill() {}

	virtual kTraversal EnterDirectory(const char *fullpath, const char *dirname, const FSSpec * macspec)
	{
		ASSERT(m_item != 0L);

		// assign the entries to this item
		Entries_Open (m_entries, fullpath);
		BuildIgnoredList(m_ignlist, fullpath);

		return kContinueTraversal;
	}

	virtual kTraversal ExitDirectory(const char *fullpath)
	{
		m_ignlist.erase(m_ignlist.begin(), m_ignlist.end());

		UTREE_INFO query;
		query.item = m_item;
		UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);
		query.icon = GetIcon(m_treeCtrl, m_item, true /*ignored*/, true, (EntnodeData *)query.data);
		UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_SETICON, kUMainWidget, &query);

		return kContinueTraversal;
	}

	virtual kTraversal OnError(const char *err, int errcode)
	{
		return kTraversalError;
	}

	virtual kTraversal OnIdle(const char *fullpath)
	{
		return kContinueTraversal;
	}

	virtual kTraversal OnDirectory(const char *fullpath,
		const char *fullname,
		const char *name,
		const struct stat & dir, const FSSpec * macspec)
	{
#if qUnix
		if(strcmp(name, "CVS") == 0)
#else
		if(stricmp(name, "cvs") == 0)
#endif
			return kSkipFile;

		// is the sub-directory ignored ?
		EntnodeData *data = Entries_SetVisited(fullpath, m_entries, name, dir, true, &m_ignlist);
		if(!(bool)gFileViewIgnore && data->IsIgnored())
			return kSkipFile;

		// create the item for the sub-directory
		TBrowserFillDummy traverse(m_treeCtrl, m_item, 0L, data);
		/*kTraversal res = */FileTraverse(fullname, traverse);

		// assign the icon regarding our Entries info
		if(traverse.m_item != 0L)
		{
			UTREE_INFO query;
			query.item = traverse.m_item;
			query.icon = GetIcon(m_treeCtrl, m_item, true /*ignored*/, false, data);
			UEventSendMessage(m_treeCtrl->GetWidID(), EV_TREE_SETICON, kUMainWidget, &query);
		}

		return kSkipFile;
	}
};

UCvsFolders::UCvsFolders() : UWidget(kUCvsFoldersID)
{
}

UCvsFolders::~UCvsFolders()
{
}

void UCvsFolders::OnDestroy(void)
{
	delete this;
}

void UCvsFolders::OnCreate(void)
{
	if(sFolderIcon == 0L)
	{
		sFolderIcon = UCreate_pixmap(this, "folder.xpm");
		sFolderUnknownIcon = UCreate_pixmap(this, "foldunk.xpm");
		sFolderIgnoredIcon = UCreate_pixmap(this, "foldign.xpm");
		sFolderMissingIcon = UCreate_pixmap(this, "foldmiss.xpm");
	}

	UStr newpath;
	newpath = (const char *)gOldLoc;
	if(newpath.empty())
		newpath = gCvsPrefs.Home();

	// set the initial root
	ResetBrowser(newpath, true);	
}

void UCvsFolders::ResetBrowser(const char *path, bool notifyView)
{
	UWaitCursor wait;

	DeleteAllItems();
	bool isReload = path != 0L && !m_root.empty() && stricmp(m_root, path) == 0;

	m_root = path;

	if(path == 0L)
		return;

	if(!isReload)
	{
		if(HasPersistentSettings(m_root))
			LoadPersistentSettings(m_root);
		else
		{
			// check if the path has a CVS folder. If not,
			// we don't want the user to be prompted (like when 
			// WinCvs is starting for the first time).
			UStr cvsFolder(m_root);
			if(!cvsFolder.endsWith(kPathDelimiter))
				cvsFolder << kPathDelimiter;
			cvsFolder << "CVS";
			struct stat sb;
			if (stat(cvsFolder, &sb) != -1 && S_ISDIR(sb.st_mode))
				AskCreatePersistentSettings(m_root);
		}
	}

	if(stricmp(gOldLoc, m_root) != 0)
		gOldLoc = m_root;

	// update the history combo
	gHistoryLocs.Insert(m_root);
	UEventSendMessage(kUCvsFrameID, EV_COMBO_RESETALL, UCvsFrame::kDirCombo, 0L);
	const std::vector<UStr> & list = gHistoryLocs.GetList();
	std::vector<UStr>::const_iterator i;
	int pos = 0;
	for(i = list.begin(); i != list.end(); ++i, pos++)
	{
		UEventSendMessage(kUCvsFrameID, EV_COMBO_APPEND,
						  UCvsFrame::kDirCombo, (void *)(const char *)*i);
	}
	UEventSendMessage(kUCvsFrameID, EV_COMBO_SETSEL, UMAKEINT(UCvsFrame::kDirCombo, 0), 0L);

	// fill the browser
	TBrowserFillDummy traverse(this, 0L, 0L, 0L);
	/*kTraversal res = */FileTraverse(m_root, traverse);

	if(traverse.m_item != 0L)
	{
		UEventSendMessage(GetWidID(), EV_TREE_EXPAND, UMAKEINT(kUMainWidget, 0), traverse.m_item);
		if(notifyView && UCvsApp::gApp->GetFilesView())
			UCvsApp::gApp->GetFilesView()->ResetView(path);
	}
}

void UCvsFolders::ResetView(bool forceReload, bool notifyView)
{
	UWaitCursor doWait;

	std::vector<UStr> allExpanded;
	StoreExpanded(allExpanded);

	bool contentChanged = false;
	UStr selPath;
	UTREEITEM selItem;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &selItem);
	if(selItem != 0L)
		RetrievePath(selItem, selPath);

	if(forceReload)
	{
		ResetBrowser(m_root);
		contentChanged = true;
	}

	if(contentChanged)
	{
		// restore the expanded paths and the selected item
		std::vector<UStr>::const_iterator i;
		for(i = allExpanded.begin(); i != allExpanded.end(); ++i)
		{
			StepToLocation(*i);
		}
		if(!selPath.empty())
		{
			selItem = GetItemByLocation(selPath);
			if(selItem != 0L)
				UEventSendMessage(GetWidID(), EV_TREE_SELECT, UMAKEINT(kUMainWidget, 0), selItem);
		}
	}

	// we don't need to notify the file view if we force the reload
	// because that's already done
	if(notifyView)
	{
		UCvsApp::gApp->GetFilesView()->ResetView(forceReload);
	}
	UEventSendMessage(GetWidID(), EV_CHGFOCUS, kUMainWidget, 0L);
}

void UCvsFolders::StoreExpanded(std::vector<UStr> & allExpanded, UTREEITEM root)
{
	UTREE_INFO query;
	query.item = root;
	UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);

	UTREEITEM item = query.item;
	if(item == 0L)
		return;

	if(query.expanded)
	{
		UStr path;
		RetrievePath(item, path);
		allExpanded.push_back(path);
	}

	UTREEITEM childItem = query.child;

	while(childItem != 0L)
	{
		StoreExpanded(allExpanded, childItem);
		query.item = childItem;
		UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);
		childItem = query.next;
	}
}

void UCvsFolders::StepToLocation(const char *path, bool notifyView)
{
	UStr root(m_root);
	if(!root.endsWith(kPathDelimiter))
		root << kPathDelimiter;
	UStr subpath(path);
	if(!subpath.endsWith(kPathDelimiter))
		subpath << kPathDelimiter;

	// check if it is a sub-path
	if(strncmp(root, subpath, root.length()) != 0)
		return;

	UTREE_INFO query;
	query.item = 0L;
	UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);

	UTREEITEM item = query.item;
	UTREEITEM lastitem = 0L;
	if(item == 0L)
		return;

	// step inside synchronized
	const char *tmp = (const char *)subpath + root.length() - 1;
	while((tmp = strchr(tmp, kPathDelimiter)) != 0L)
	{
		const char *name = ++tmp;
		if(name[0] == '\0')
			break;

		UStr subname;
		const char *tmp2 = strchr(name, kPathDelimiter);
		if(tmp2 == 0L)
			subname = name;
		else
			subname.set(name, tmp2 - name);

		query.item = item;
		UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);
		UTREEITEM childItem = query.child;

		// find the subitem which matches this name
		while(childItem != 0L)
		{
			query.item = childItem;
			UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);
			EntnodeData *data = (EntnodeData *)query.data;
			if(data != 0L)
			{
#ifdef qUnix
				if(strcmp((*data)[EntnodeData::kName], subname) == 0)
#else
				if(_stricmp((*data)[EntnodeData::kName], subname) == 0)
#endif
				{
					// found it !
					lastitem = item = childItem;
					UEventSendMessage(GetWidID(), EV_TREE_EXPAND, UMAKEINT(kUMainWidget, 0), item);
					break;
				}
			}

			childItem = query.next;
		}
	}

	// in case this is called by the view, turn off notifying
	// when the item gets selected
	if(lastitem != 0L)
	{
		if(!notifyView)
		{
			CTempToggleBool toggler(sTemporaryTurnOffNotify);
			UEventSendMessage(GetWidID(), EV_TREE_SELECT, UMAKEINT(kUMainWidget, 0), lastitem);
		}
		else
		{
			UEventSendMessage(GetWidID(), EV_TREE_SELECT, UMAKEINT(kUMainWidget, 0), lastitem);
		}
	}
}

UTREEITEM UCvsFolders::GetItemByLocation(const char *path)
{
	UStr root(m_root);
	if(!root.endsWith(kPathDelimiter))
		root << kPathDelimiter;
	UStr subpath(path);
	if(!subpath.endsWith(kPathDelimiter))
		subpath << kPathDelimiter;

	// check if it is a sub-path
	if(strncmp(root, subpath, root.length()) != 0)
		return 0L;

	UTREE_INFO query;
	query.item = 0L;
	UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);
	UTREEITEM item = query.item;
	if(item == 0L)
		return 0L;

	// step inside synchronized
	const char *tmp = (const char *)subpath + root.length() - 1;
	while((tmp = strchr(tmp, kPathDelimiter)) != 0L)
	{
		const char *name = ++tmp;
		if(name[0] == '\0')
			break;

		CStr subname;
		const char *tmp2 = strchr(name, kPathDelimiter);
		if(tmp2 == 0L)
			subname = name;
		else
			subname.set(name, tmp2 - name);

		UTREEITEM childItem = query.child;

		// find the subitem which matches this name
		while(childItem != 0L)
		{
			query.item = childItem;
			UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);
			EntnodeData *data = (EntnodeData *)query.data;
			if(data != 0L)
			{
#if qUnix
				if(strcmp((*data)[EntnodeData::kName], subname) == 0)
#else
				if(_stricmp((*data)[EntnodeData::kName], subname) == 0)
#endif
				{
					item = childItem;
					break;
				}
			}

			childItem = query.next;
		}
		if(childItem == 0L)
			return 0L;
	}

	return item;
}

void UCvsFolders::OnTreeExpanding(int collapse, UTREEITEM item)
{
	// many situations make that we enter here twice. Fortunately enough
	// we only dare the first signal.
	static bool sSemaphore = false;
	USemaphore policeman(sSemaphore);
	if(policeman.IsEnteredTwice())
		return;

	UWaitCursor wait;

	UTREE_INFO query;
	query.item = item;
	UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);
	EntnodeData *data = (EntnodeData *)query.data;

	// we refuse to expand in this case cause the folder is not really here
  	if(data != 0L && data->IsMissing())
	{
		UEventSendMessage(GetWidID(), EV_TREE_EXPAND, UMAKEINT(kUMainWidget, 1), item);
  		return;
	}

	// erase all the childs
	DeleteAllItems(item);

	UStr path;
	RetrievePath(item, path);

	if(collapse)
	{
		TBrowserFillDummy traverse(this, 0L, item, 0L);
		/*kTraversal res = */FileTraverse(path, traverse);
	}
	else
	{
		CSortList<ENTNODE> entries(200, ENTNODE::Compare);
		TBrowserFill traverse(this, 0L, item, entries);
		/*kTraversal res = */FileTraverse(path, traverse);

#if qGTK
		// gtk is closing the tree when we removed everything in it
		UEventSendMessage(GetWidID(), EV_TREE_EXPAND, UMAKEINT(kUMainWidget, 0), item);
#endif

		// add the missing folders
		Entries_SetMissing(entries);
		int numEntries = entries.NumOfElements();
		for(int i = 0; i < numEntries; i++)
		{
			const ENTNODE & theNode = entries.Get(i);
			EntnodeData *data = ((ENTNODE *)&theNode)->Data();
			if(!data->IsMissing() || data->GetType() != ENT_SUBDIR)
				continue;
			
			UTREE_INSERT insert;
			insert.parent = item;
			insert.icon = GetIcon(this, item, false, false, data->Ref());
			insert.title = (*data)[EntnodeData::kName];
			insert.data = data;
			UEventSendMessage(GetWidID(), EV_TREE_INSERT, kUMainWidget, &insert);
		}
	}
}

void UCvsFolders::OnTreeSelecting(int deselect, UTREEITEM item)
{
	if(deselect)
		return;

	UTREE_INFO query;
	query.item = item;
	UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);
	EntnodeData *data = (EntnodeData *)query.data;
	if(data != 0L && data->IsMissing())
		return;

	if(!sTemporaryTurnOffNotify)
	{
		UStr path;
		RetrievePath(item, path);
		UCvsFiles *fileView = (UCvsFiles *)UEventQueryWidget(kUCvsFilesID);
		if(fileView != 0L)
		{
			ASSERT(fileView->IsKindOf(URUNTIME_CLASS(UCvsFiles)));
			fileView->ResetView((const char *)path);
		}
	}

}

void UCvsFolders::SetDefaultRoot(const char *root)
{
	struct stat sb;

	if (stat(root, &sb) == -1 || !S_ISDIR(sb.st_mode))
	{
		cvs_err("Cannot access directory '%s' (error %d)\n", root, errno);
		return;
	}
	
	gOldLoc = root;
}

void UCvsFolders::RetrievePath(UTREEITEM item, UStr & path)
{
	UStr tmp, newPath;
	path = "";

	do
	{
		UTREE_INFO query;
		query.item = item;
		UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);
		
		item = query.parent;

		tmp = path;
		newPath = item == 0L ? (const char *)m_root : query.title;
		if(!newPath.endsWith(kPathDelimiter))
			newPath << kPathDelimiter;
		newPath << path;
		path = newPath;
	} while(item != 0L);
}

void UCvsFolders::DeleteAllItems(void)
{
	DeleteAllItems(NULL);
}

void UCvsFolders::DeleteAllItems(UTREEITEM root)
{
	// we don't want the file view to be notified when things get deleted
	CTempToggleBool toggler(sTemporaryTurnOffNotify);

	UTREE_INFO query;
	bool eraseRoot = false;
	query.item = root;
	UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);
	if(root == 0L)
	{
		root = query.item;
		eraseRoot = true;
	}

	if(root == 0L)
		return;

	UTREEITEM childItem = query.child;

	// erase all the childs
	while(childItem != 0L)
	{
		UTREE_INFO queryChild;
		queryChild.item = childItem;
		UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &queryChild);

		EntnodeData *data = (EntnodeData *)queryChild.data;
		if(data != 0L)
		{
			queryChild.data = 0L; // So that subsequent references after UnRef() won't SEGV
			UEventSendMessage(GetWidID(), EV_TREE_SETDATA, kUMainWidget, &queryChild);
			data->UnRef();	// Or move this one after DeleteAllItems? so we don't loose one system call. For now, safe way
		}

		DeleteAllItems(childItem);

		UEventSendMessage(GetWidID(), EV_TREE_DELETE, kUMainWidget, childItem);
		childItem = queryChild.next;
	}

	// erase the root only if initially root was 0L
	if(eraseRoot)
	{
		EntnodeData *data = (EntnodeData *)query.data;
		ASSERT(data == 0L);

		UEventSendMessage(GetWidID(), EV_TREE_DELETE, kUMainWidget, root);
	}
}

bool UCvsFolders::DisableGeneric()
{
	UCvsApp *app = UCvsApp::gApp;
	return app->IsCvsRunning() || gCvsPrefs.empty() || !HasFocus();
}

void UCvsFolders::OnUpdateGeneric(UCmdUI* pCmdUI, bool needCvsInfos)
{
	if(DisableGeneric())
	{
		pCmdUI->Enable(false);
		return;
	}

	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	if(item == 0L)
	{
		pCmdUI->Enable(false);
		return;
	}

	UStr path;
	RetrievePath(item, path);
	if(!path.endsWith(kPathDelimiter))
		path << kPathDelimiter;
	path << "CVS";

	struct stat sb;
	if (stat(path, &sb) == -1 || !S_ISDIR(sb.st_mode))
		pCmdUI->Enable(!needCvsInfos);
	else
		pCmdUI->Enable(needCvsInfos);
}

int UCvsFolders::OnCmdUpdate(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdUpdateFolder(path);
	return 0;
}

void UCvsFolders::OnCmdUIUpdate(UCmdUI *pCmdUI)
{
	OnUpdateGeneric(pCmdUI, true);
}

int UCvsFolders::OnCmdAdd(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdAddFolder(path);
	return 0;
}

int UCvsFolders::OnCmdCommit(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdCommitFolder(path);
	return 0;
}

int UCvsFolders::OnCmdQueryUpdate(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdUpdateFolder(path, true);
	return 0;
}

int UCvsFolders::OnCmdDiff(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdDiffFolder(path);
	return 0;
}

int UCvsFolders::OnCmdLog(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdLogFolder(path);
	return 0;
}

int UCvsFolders::OnCmdStatus(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdStatusFolder(path);
	return 0;
}

int UCvsFolders::OnCmdLock(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdLockFolder(path);
	return 0;
}

int UCvsFolders::OnCmdUnlock(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdUnlockFolder(path);
	return 0;
}

int UCvsFolders::OnCmdWatchOn(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdWatchOnFolder(path);
	return 0;
}

int UCvsFolders::OnCmdWatchOff(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdWatchOffFolder(path);
	return 0;
}

int UCvsFolders::OnCmdEdit(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdEditFolder(path);
	return 0;
}

int UCvsFolders::OnCmdUnedit(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdUneditFolder(path);
	return 0;
}

int UCvsFolders::OnCmdWatchers(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdWatchersFolder(path);
	return 0;
}

int UCvsFolders::OnCmdEditors(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdEditorsFolder(path);
	return 0;
}

int UCvsFolders::OnCmdRelease(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdReleaseFolder(path);
	return 0;
}

int UCvsFolders::OnCmdTagNew(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdTagCreateFolder(path);
	return 0;
}

int UCvsFolders::OnCmdTagDelete(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdTagDeleteFolder(path);
	return 0;
}

int UCvsFolders::OnCmdTagBranch(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);
	CvsCmdTagBranchFolder(path);
	return 0;
}

int UCvsFolders::OnCmdExplore(void)
{
	UTREEITEM *item;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &item);
	ASSERT(item != 0L);

	UStr path;
	RetrievePath(item, path);

#ifdef WIN32
	HINSTANCE hInst = ShellExecute(*AfxGetMainWnd(), "explore", path,
			0L, 0L, SW_SHOWDEFAULT);
	if((long)hInst < 32)
	{
		cvs_err("Unable to explore '%s' (error %d)\n", (const char *)path, GetLastError());
	}
#endif
#ifdef qUnix
	CvsArgs args(false);
	args.add(gCvsPrefs.Browser());
	args.add(path);
	UCvsApp::gApp->Execute(args.Argc(), args.Argv());
#endif

	return 0;
}

int UCvsFolders::OnCmdReload(void)
{
	ResetView(true);
	return 0;
}

int UCvsFolders::OnCmdIgnore(void)
{
	gFileViewIgnore = !(bool)gFileViewIgnore;
	ResetView(true, true);
	return 0;
}

int UCvsFolders::OnCmdCheckout(void)
{
	CvsCmdCheckoutModule();
	return 0;
}

int UCvsFolders::OnCmdImport(void)
{
	CvsCmdImportModule();
	return 0;
}

void UCvsFolders::OnCmdUIAdd(UCmdUI *pCmdUI)
{
	OnUpdateGeneric(pCmdUI, false);
}

void UCvsFolders::OnCmdUIExplore(UCmdUI *pCmdUI)
{
	if(DisableGeneric())
	{
		pCmdUI->Enable(false);
		return;
	}
	UTREEITEM selItem;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &selItem);
	pCmdUI->Enable(selItem != 0L);
}

void UCvsFolders::OnCmdUIReload(UCmdUI *pCmdUI)
{
	UCvsApp *app = UCvsApp::gApp;
	pCmdUI->Enable(!app->IsCvsRunning());
}

void UCvsFolders::OnCmdUIIgnore(UCmdUI *pCmdUI)
{
	pCmdUI->Enable(!DisableGeneric());
	pCmdUI->Check(gFileViewIgnore);
}

void UCvsFolders::OnCmdUICheckout(UCmdUI *pCmdUI)
{
	UCvsApp *app = UCvsApp::gApp;
	pCmdUI->Enable(!app->IsCvsRunning() && !gCvsPrefs.empty());
}

void UCvsFolders::OnCmdUIImport(UCmdUI *pCmdUI)
{
	UCvsApp *app = UCvsApp::gApp;
	pCmdUI->Enable(!app->IsCvsRunning() && !gCvsPrefs.empty());
}

void UCvsFolders::OnCmdUIMacrosSel(int cmd, UCmdUI *pCmdUI)
{
	if(DisableGeneric())
	{
		pCmdUI->Enable(false);
		return;
	}
	UTREEITEM selItem;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &selItem);
	pCmdUI->Enable(selItem != 0L && CTcl_Interp::IsAvail());
}

int UCvsFolders::OnCmdMacrosSel(int cmd)
{
	CTcl_Interp interp;
	CMacroEntry & entry = gMacrosSel.entries[cmd - cmdSELMACRO];
	CStr path = entry.path;
	CTcl_Interp::Unixfy(path);

	UTREEITEM selItem;
	UEventSendMessage(GetWidID(), EV_TREE_GETSEL, kUMainWidget, &selItem);

	CStr selPath;
	RetrievePath(selItem, selPath);
	CStr uppath, folder;
	SplitPath(selPath, uppath, folder);

	UTREE_INFO query;
	query.item = selItem;
	UEventSendMessage(GetWidID(), EV_TREE_GETINFO, kUMainWidget, &query);
	bool deleteData = false;
	EntnodeData *data = (EntnodeData *)query.data;
	if(data == 0L)
	{
		deleteData = true;
		EntnodePath *apath = new EntnodePath(uppath);
		data = new EntnodeFolder(folder, apath);
		apath->UnRef();
	}

	TclBrowserReset();
	TclBrowserAppend(uppath, data);

	interp.DoScriptVar("source \"%s\"", (const char *)path);

	if(deleteData)
		data->UnRef();

	return 0;
}
/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 1, or (at your option)
** any later version.

** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.

** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
 * Author : Alexandre Parenteau <[EMAIL PROTECTED]> --- February 2000
 */

/*
 * 
 */

#include "stdafx.h"

#if qGTK
#	include <gtk/gtk.h>
#endif

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif

#include <string>

#include "UCvsFiles.h"
#include "UCvsDialogs.h"
#include "UCvsFolders.h"
#include "UCvsCommands.h"
#include "UCvsFrame.h"
#include "UCvsApp.h"
#include "CvsPrefs.h"
#include "FileTraversal.h"
#include "MultiFiles.h"
#include "CvsCommands.h"
#include "CvsArgs.h"
#include "TclGlue.h"
#include "AppConsole.h"
#include "MoveToTrash.h"
#include "MacrosSetup.h"

#ifndef NAMESPACE
#       if defined(_MSC_VER) || defined(__MWERKS__) || (__GNUC__ > 2)
#               define NAMESPACE(w) w::
#       else
#               define NAMESPACE(w) ::
#       endif
#endif

UIMPLEMENT_DYNAMIC(UCvsFiles, UWidget)

UBEGIN_MESSAGE_MAP(UCvsFiles, UWidget)
	ON_UUPDATECMD(cmdUPDATE, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdCOMMIT, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdDIFF, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdEDIT, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdEDITORS, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdLOCKF, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdLOG, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdTAGNEW, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdTAGDELETE, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdTAGBRANCH, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdSTATUS, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdUNEDIT, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdQUERYUPDATE, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdUNLOCKF, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdWATCHERS, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdWATCHON, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdWATCHOFF, UCvsFiles::OnCmdUIUpdate)
	ON_UUPDATECMD(cmdADD, UCvsFiles::OnCmdUIAdd)
	ON_UUPDATECMD(cmdADDB, UCvsFiles::OnCmdUIAddB)
	ON_UUPDATECMD(cmdRELEASE, UCvsFiles::OnCmdUIRelease)
	ON_UUPDATECMD(cmdRMV, UCvsFiles::OnCmdUIRmv)
	ON_UUPDATECMD(cmdGRAPH, UCvsFiles::OnCmdUIGraph)
	ON_UUPDATECMD(cmdEDITSELDEF, UCvsFiles::OnCmdUIEditseldef)
	ON_UUPDATECMD(cmdRELOAD, UCvsFiles::OnCmdUIReload)
	ON_UUPDATECMD(cmdUPFOLDER, UCvsFiles::OnCmdUIUpone)
	ON_UUPDATECMD(cmdTRASH, UCvsFiles::OnCmdUITrash)
	ON_UUPDATECMD(cmdEXPLORE, UCvsFiles::OnCmdUIExplore)
	ON_UUPDATECMD(cmdIGNORE, UCvsFiles::OnCmdUIIgnore)
	ON_UUPDATECMD(cmdEDITSEL, UCvsFiles::OnCmdUITrash)
	ON_UUPDATECMD_RANGE(cmdSELMACRO, cmdSELMACROEND, UCvsFiles::OnCmdUIMacroSel)
	ON_UCOMMAND(cmdUPDATE, UCvsFiles::OnCmdUpdate)
	ON_UCOMMAND(cmdADD, UCvsFiles::OnCmdAdd)
	ON_UCOMMAND(cmdADDB, UCvsFiles::OnCmdAddb)
	ON_UCOMMAND(cmdCOMMIT, UCvsFiles::OnCmdCommit)
	ON_UCOMMAND(cmdRMV, UCvsFiles::OnCmdRmv)
	ON_UCOMMAND(cmdQUERYUPDATE, UCvsFiles::OnCmdQueryUpdate)
	ON_UCOMMAND(cmdRELOAD, UCvsFiles::OnCmdReload)
	ON_UCOMMAND(cmdUPFOLDER, UCvsFiles::OnCmdUpone)
	ON_UCOMMAND(cmdTRASH, UCvsFiles::OnCmdTrash)
	ON_UCOMMAND(cmdDIFF, UCvsFiles::OnCmdDiff)
	ON_UCOMMAND(cmdLOG, UCvsFiles::OnCmdLog)
	ON_UCOMMAND(cmdGRAPH, UCvsFiles::OnCmdGraph)
	ON_UCOMMAND(cmdSTATUS, UCvsFiles::OnCmdStatus)
	ON_UCOMMAND(cmdLOCKF, UCvsFiles::OnCmdLock)
	ON_UCOMMAND(cmdUNLOCKF, UCvsFiles::OnCmdUnlock)
	ON_UCOMMAND(cmdWATCHON, UCvsFiles::OnCmdWatchOn)
	ON_UCOMMAND(cmdWATCHOFF, UCvsFiles::OnCmdWatchOff)
	ON_UCOMMAND(cmdEDIT, UCvsFiles::OnCmdEdit)
	ON_UCOMMAND(cmdUNEDIT, UCvsFiles::OnCmdUnedit)
	ON_UCOMMAND(cmdWATCHERS, UCvsFiles::OnCmdWatchers)
	ON_UCOMMAND(cmdEDITORS, UCvsFiles::OnCmdEditors)
	ON_UCOMMAND(cmdRELEASE, UCvsFiles::OnCmdRelease)
	ON_UCOMMAND(cmdTAGNEW, UCvsFiles::OnCmdTagNew)
	ON_UCOMMAND(cmdTAGDELETE, UCvsFiles::OnCmdTagDelete)
	ON_UCOMMAND(cmdTAGBRANCH, UCvsFiles::OnCmdTagBranch)
	ON_UCOMMAND(cmdEXPLORE, UCvsFiles::OnCmdExplore)
	ON_UCOMMAND(cmdIGNORE, UCvsFiles::OnCmdIgnore)
	ON_UCOMMAND(cmdEDITSEL, UCvsFiles::OnCmdEditsel)
	ON_UCOMMAND(cmdEDITSELDEF, UCvsFiles::OnCmdEditseldef)
	ON_UCOMMAND_RANGE(cmdSELMACRO, cmdSELMACROEND, UCvsFiles::OnMacroSel)
	ON_LIST_DBLCLICK(kUMainWidget, UCvsFiles::OnDblClick)
	ON_LIST_SELCOLUMN(kUMainWidget, UCvsFiles::OnSelColumn)
	ON_UDESTROY(UCvsFiles)
	ON_UCREATE(UCvsFiles)
UEND_MESSAGE_MAP()

#if 0
	ON_UUPDATECMD(cmdSMALLICONS, OnCmdUISmallIcons)
	ON_UUPDATECMD(cmdFULLLIST, OnCmdUIList)
	ON_UUPDATECMD(cmdROWDETAILS, OnCmdUIFullRowDetails)
	ON_COMMAND(ID_VIEW_SMALLICONS, OnViewSmallIcons)
	ON_COMMAND(ID_VIEW_FULLLIST, OnViewList)
	ON_COMMAND(ID_VIEW_ROWDETAILS, OnViewFullRowDetails)
	ON_WM_LBUTTONDOWN()
	ON_WM_RBUTTONDOWN()
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick)
	ON_NOTIFY_REFLECT(LVN_KEYDOWN, OnKeydown)
	ON_WM_TIMER()

	//}}AFX_MSG_MAP
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
#endif

static void *sFileIconTextIcon;
static void *sFileIconBinaryIcon;
static void *sFileIconUnknownIcon;
static void *sFileIconAddedIcon;
static void *sFileIconConflictIcon;
static void *sFileIconMissIcon;
static void *sFolderIconIcon;
static void *sFolderIconUnknownIcon;
static void *sFolderIconMissIcon;
static void *sFileIconTextModIcon;
static void *sFileIconBinaryModIcon;
static void *sFileIconIgnoredIcon;
static void *sFolderIconIgnoredIcon;
static void *sFileIconRemovedIcon;

/*
kFileIconText,cvsfile
kFileIconBinary,binfile
kFileIconUnknown,unkfile
kFileIconAdded,addfile
kFileIconConflict,conflict
kFileIconMiss,missfile
kFolderIcon,folder
kFolderIconUnknown,foldunk
kFolderIconMiss,foldmiss
kFileIconTextMod,modfile
kFileIconBinaryMod,modbin
kFileIconIgnored,ignfile
kFolderIconIgnored,foldign
kFileIconRemoved,delfile
*/

enum
{
	kFileIconText = 0,
	kFileIconBinary,
	kFileIconUnknown,
	kFileIconAdded,
	kFileIconConflict,
	kFileIconMiss,
	kFolderIcon,
	kFolderIconUnknown,
	kFolderIconMiss,
	kFileIconTextMod,
	kFileIconBinaryMod,
	kFileIconIgnored,
	kFolderIconIgnored,
	kFileIconRemoved
};

#define NUM_COLUMNS	7

static char *_gszColumnLabel[NUM_COLUMNS] =
{
	"Name", "Rev.", "Option", "Status",	"Tag", "Date", "Conflict"
};

static int _gnColumnWidth[NUM_COLUMNS] = 
{
	150, 50, 50, 100, 150, 150, 150
};

static const char * month_names[12] =
{
        "Jan", "Feb", "Mar", "Apr",
        "May", "Jun", "Jul", "Aug",
        "Sep", "Oct", "Nov", "Dec"
};

CPersistentBool gFileViewIgnore("P_FileViewIgnore", true);
CPersistentInt gFileViewSort("P_FileViewSort", EntnodeData::kName);
CPersistentBool gFileViewSortAsc("P_FileViewSortAsc", true);

class TViewFill : public TraversalReport
{
public:
	UCvsFiles *m_listCtrl;
	CSortList<ENTNODE> & m_entries;
	NAMESPACE(std) vector<CStr> m_ignlist;

	TViewFill(UCvsFiles *listCtrl, CSortList<ENTNODE> & entries) :
		m_listCtrl(listCtrl), m_entries(entries) {}

	virtual ~TViewFill() {}

	virtual kTraversal EnterDirectory(const char *fullpath, const char *dirname, const FSSpec * macspec)
	{
		Entries_Open (m_entries, fullpath);
		BuildIgnoredList(m_ignlist, fullpath);

		return kContinueTraversal;
	}

	virtual kTraversal ExitDirectory(const char *fullpath)
	{
		m_ignlist.erase(m_ignlist.begin(), m_ignlist.end());
		return kContinueTraversal;
	}

	virtual kTraversal OnError(const char *err, int errcode)
	{
		return kTraversalError;
	}

	virtual kTraversal OnIdle(const char *fullpath)
	{
		return kContinueTraversal;
	}

	virtual kTraversal OnDirectory(const char *fullpath,
		const char *fullname,
		const char *name,
		const struct stat & dir, const FSSpec * macspec)
	{
#if qUnix
		if(strcmp(name, "CVS") == 0)
#else
		if(stricmp(name, "CVS") == 0)
#endif
			return kSkipFile;

		EntnodeData *data = Entries_SetVisited(fullpath, m_entries, name, dir, true, &m_ignlist);
		if(!(bool)gFileViewIgnore && data->IsIgnored())
			return kSkipFile;

		// get the tag
		CStr subCVS;
		CStr tagName;
		subCVS = fullname;
		if(!subCVS.endsWith(kPathDelimiter))
			subCVS << kPathDelimiter;
		subCVS << "CVS";
		if(chdir(subCVS) == 0)
			Tag_Open(tagName, subCVS);
		if(chdir(fullpath) != 0)
			return kTraversalError;

		int rownum;
		UEventSendMessage(m_listCtrl->GetWidID(), EV_LIST_NEWROW, kUMainWidget, &rownum);
		UEventSendMessage(m_listCtrl->GetWidID(), EV_LIST_ROWSETDATA, UMAKEINT(kUMainWidget, rownum), data);
		ULIST_INSERT entry;
		entry.row = rownum;

		entry.col = 0;
		entry.title = name;
		entry.icon = UCvsFiles::GetImageForEntry(data);
		UEventSendMessage(m_listCtrl->GetWidID(), EV_LIST_INSERT, kUMainWidget, &entry);

		entry.icon = 0L;

		// set item text for additional columns
		for(int j = 1; j < NUM_COLUMNS; j++)
		{
			const char *info = (*data)[j];
			if(info != 0L)
			{
				entry.col = j;
				entry.title = info;
				UEventSendMessage(m_listCtrl->GetWidID(), EV_LIST_INSERT, kUMainWidget, &entry);
			}
		}
		entry.col = EntnodeData::kStatus;
		entry.title = data->GetDesc();
		UEventSendMessage(m_listCtrl->GetWidID(), EV_LIST_INSERT, kUMainWidget, &entry);
		entry.col = EntnodeFile::kTag;
		entry.title = tagName.empty() ? "" : (const char *)tagName;
		UEventSendMessage(m_listCtrl->GetWidID(), EV_LIST_INSERT, kUMainWidget, &entry);

		return kSkipFile;
	}

	virtual kTraversal OnAlias(const char *fullpath,
		const char *fullname,
		const char *name,
		const struct stat & dir, const FSSpec * macspec)
	{
		return OnFile(fullpath, fullname, name, dir, macspec);
	}

	virtual kTraversal OnFile(const char *fullpath,
		const char *fullname,
		const char *name,
		const struct stat & dir, const FSSpec * macspec)
	{
		EntnodeData *data = Entries_SetVisited(fullpath, m_entries, name, dir, false, &m_ignlist);
		if(!(bool)gFileViewIgnore && data->IsIgnored())
			return kContinueTraversal;

		int rownum;
		UEventSendMessage(m_listCtrl->GetWidID(), EV_LIST_NEWROW, kUMainWidget, &rownum);
		UEventSendMessage(m_listCtrl->GetWidID(), EV_LIST_ROWSETDATA, UMAKEINT(kUMainWidget, rownum), data);
		ULIST_INSERT entry;
		entry.row = rownum;

		entry.col = 0;
		entry.title = name;
		entry.icon = UCvsFiles::GetImageForEntry(data);
		UEventSendMessage(m_listCtrl->GetWidID(), EV_LIST_INSERT, kUMainWidget, &entry);

		entry.icon = 0L;

#if 0 /* TODO */
		lvi.state = data->IsLocked() ?
			INDEXTOSTATEIMAGEMASK(2) : INDEXTOSTATEIMAGEMASK(1);
#endif

		// set item text for additional columns
		for(int j = 1; j < NUM_COLUMNS; j++)
		{
			const char *info = (*data)[j];
			if(info != 0L)
			{
				entry.col = j;
				entry.title = info;
				UEventSendMessage(m_listCtrl->GetWidID(), EV_LIST_INSERT, kUMainWidget, &entry);
			}
		}
		entry.col = EntnodeData::kStatus;
		entry.title = data->GetDesc();
		UEventSendMessage(m_listCtrl->GetWidID(), EV_LIST_INSERT, kUMainWidget, &entry);

		return kContinueTraversal;
	}
};

UCvsFiles::UCvsFiles() : UWidget(kUCvsFilesID), m_entries(200, ENTNODE::Compare), m_entriesMod(0), m_entriesLogMod(0)

{
	m_sort = (int)gFileViewSort;
	m_ascendant = (bool)gFileViewSortAsc;
}

UCvsFiles::~UCvsFiles()
{
	gFileViewSort = m_sort;
	gFileViewSortAsc = m_ascendant;
}

void UCvsFiles::OnDestroy(void)
{
	delete this;
}

void UCvsFiles::OnCreate(void)
{
	if(sFileIconTextIcon == 0L)
	{
		sFileIconTextIcon = UCreate_pixmap(this, "cvsfile.xpm");
		sFileIconBinaryIcon = UCreate_pixmap(this, "binfile.xpm");
		sFileIconUnknownIcon = UCreate_pixmap(this, "unkfile.xpm");
		sFileIconAddedIcon = UCreate_pixmap(this, "addfile.xpm");
		sFileIconConflictIcon = UCreate_pixmap(this, "conflict.xpm");
		sFileIconMissIcon = UCreate_pixmap(this, "missfile.xpm");
		sFolderIconIcon = UCreate_pixmap(this, "folder.xpm");
		sFolderIconUnknownIcon = UCreate_pixmap(this, "foldunk.xpm");
		sFolderIconMissIcon = UCreate_pixmap(this, "foldmiss.xpm");
		sFileIconTextModIcon = UCreate_pixmap(this, "modfile.xpm");
		sFileIconBinaryModIcon = UCreate_pixmap(this, "modbin.xpm");
		sFileIconIgnoredIcon = UCreate_pixmap(this, "ignfile.xpm");
		sFolderIconIgnoredIcon = UCreate_pixmap(this, "foldign.xpm");
		sFileIconRemovedIcon = UCreate_pixmap(this, "delfile.xpm");
	}

	UEventSendMessage(GetWidID(), EV_LIST_SETFEEDBACK, UMAKEINT(kUMainWidget, 0), 0L);
	UEventSendMessage(GetWidID(), EV_LIST_ADDCOLUMNS, UMAKEINT(kUMainWidget, NUM_COLUMNS), 0L);
	for(int i = 0; i < NUM_COLUMNS; i++)
	{
		UEventSendMessage(GetWidID(), EV_LIST_SETCOLTITLE, UMAKEINT(kUMainWidget, i), _gszColumnLabel[i]);
		UEventSendMessage(GetWidID(), EV_LIST_SETCOLWIDTH, UMAKEINT(kUMainWidget, i), (void *)_gnColumnWidth[i]);
	}
	UEventSendMessage(GetWidID(), EV_LIST_SETFEEDBACK, UMAKEINT(kUMainWidget, 1), 0L);
}

void UCvsFiles::ResetView(const char *path, bool notifyBrowser)
{
	m_path = path;
	ResetView(true);

	UStr title(UCvsApp::gApp->GetAppName());
	title << ": ";
	title << m_path;
	UEventSendMessage(kUCvsFrameID, EV_SETTEXT, kUMainWidget, (void *)(const char *)title);

	if(notifyBrowser)
	{
		// notify the tree
		UCvsApp::gApp->GetBrowserView()->StepToLocation(path);
	}
}

void UCvsFiles::GetEntriesModTime(time_t & newEntriesMod, time_t & newEntriesLogMod)
{
	newEntriesMod = 0;
	newEntriesLogMod = 0;
	if(chdir(m_path) != 0)
		return;
	if(chdir("CVS") != 0)
		return;

	struct stat sb;
	if (stat("Entries", &sb) != -1)
		newEntriesMod = sb.st_mtime;
	if (stat("Entries.log", &sb) != -1)
		newEntriesLogMod = sb.st_mtime;
	chdir(m_path);
}

int UCvsFiles::Search(const char *title)
{
	int row = -1;
	while((row = UEventSendMessage(GetWidID(), EV_LIST_GETNEXT,
									 UMAKEINT(kUMainWidget, row), 0L)) != -1)
	{
		ULIST_INFO info;
		info.col = 0;
		info.row = row;
		UEventSendMessage(GetWidID(), EV_LIST_GETINFO, kUMainWidget, &info);
		if(info.title == 0L)
			continue;

#if qUnix
		if(strcmp(title, info.title) == 0)
#else
		if(stricmp(title, info.title) == 0)
#endif
			return row;
	}

	return -1;
}

void UCvsFiles::ResetView(bool forceReload, bool notifyBrowser)
{
	UWaitCursor wait;

	static bool sSemaphore = false;
	USemaphore policeman(sSemaphore);
	if(policeman.IsEnteredTwice())
		return;

	// - check if we really need to reload (forceReload == false)
	// - wait a bit for the watcher in order to let him tell us
	// if something was modified.
	time_t newEntriesMod;
	time_t newEntriesLogMod;
	GetEntriesModTime(newEntriesMod, newEntriesLogMod);
	if(!forceReload)
	{
		if(m_entriesMod == newEntriesMod && m_entriesLogMod == newEntriesLogMod)
			return;
	}	

	// reset all the watchers
	m_entriesMod = newEntriesMod;
	m_entriesLogMod = newEntriesLogMod;

	// get the selection to later try to restore it
	CvsArgs selection(false);
	int nItem = -1;

	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL,
									 UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);
		selection.add((*data)[EntnodeData::kName]);
	}

	UEventSendMessage(GetWidID(), EV_LIST_RESETALL, kUMainWidget, 0L);

	// refetch all items
	TViewFill traverse(this, m_entries);
	/*kTraversal res = */FileTraverse(m_path, traverse);

	// add the missing files
	Entries_SetMissing(m_entries);

	int numEntries = m_entries.NumOfElements();
	for(int i = 0; i < numEntries; i++)
	{
		const ENTNODE & theNode = m_entries.Get(i);
		EntnodeData *data = ((ENTNODE *)&theNode)->Data();
		if(!data->IsMissing())
			continue;

		int rownum;
		UEventSendMessage(GetWidID(), EV_LIST_NEWROW, kUMainWidget, &rownum);
		UEventSendMessage(GetWidID(), EV_LIST_ROWSETDATA, UMAKEINT(kUMainWidget, rownum), data);
		ULIST_INSERT entry;
		entry.row = rownum;

		entry.col = 0;
		entry.title = (*data)[EntnodeData::kName];
		entry.icon = UCvsFiles::GetImageForEntry(data);
		UEventSendMessage(GetWidID(), EV_LIST_INSERT, kUMainWidget, &entry);

		entry.icon = 0L;

		// set item text for additional columns
		for(int j = 1; j < NUM_COLUMNS; j++)
		{
			const char *info = (*data)[j];
			if(info != 0L)
			{
				entry.col = j;
				entry.title = info;
				UEventSendMessage(GetWidID(), EV_LIST_INSERT, kUMainWidget, &entry);
			}
		}
		entry.col = EntnodeData::kStatus;
		entry.title = data->GetDesc();
		UEventSendMessage(GetWidID(), EV_LIST_INSERT, kUMainWidget, &entry);
	}

	Resort();

	// now restore the selection
	int argc = selection.Argc(), c;
	char * const *argv = selection.Argv();
	for(c = 0; c < argc; c++)
	{
		int row = Search(argv[c]);
		if(row != -1)
			UEventSendMessage(GetWidID(), EV_LIST_ADDSEL, UMAKEINT(kUMainWidget, row), 0L);
	}

	if(notifyBrowser)
	{
		// notify the tree
		UCvsApp::gApp->GetBrowserView()->ResetView(forceReload);
	}
}

void *UCvsFiles::GetImageForEntry(EntnodeData *data)
{
	int result;
	void *resIcon = 0L;

	if(data->GetType() == ENT_FILE)
	{
		const char *info = 0L;
		if(data->IsIgnored())
		{
			result = kFileIconIgnored;
		}
		else if(data->IsUnknown())
		{
			result = kFileIconUnknown;
		}
		else if(data->IsMissing())
		{
			result = data->IsRemoved() ? kFileIconRemoved : kFileIconMiss;
		}
		else if((*data)[EntnodeFile::kConflict] != 0L)
		{
			result = kFileIconConflict;
		}
		else if(data->IsRemoved())
		{
			result = kFileIconRemoved;
		}
		else if((info = (*data)[EntnodeFile::kOption]) != 0L && strcmp(info, "-kb") == 0)
		{
			result = data->IsUnmodified() ? kFileIconBinary : kFileIconBinaryMod;
		}
		else
		{
			result = data->IsUnmodified() ? kFileIconText : kFileIconTextMod;
		}
	}
	else
	{
		if(data->IsIgnored())
		{
			result = kFolderIconIgnored;
		}
		else if(data->IsUnknown())
		{
			result = kFolderIconUnknown;
		}
		else if(data->IsMissing())
		{
			result = kFolderIconMiss;
		}
		else
		{
			result = kFolderIcon;
		}
	}

#if qGTK
	void *pixmap = 0L;
	switch(result)
	{
	case kFileIconText:
		pixmap = sFileIconTextIcon;
		break;
	case kFileIconBinary:
		pixmap = sFileIconBinaryIcon;
		break;
	case kFileIconUnknown:
		pixmap = sFileIconUnknownIcon;
		break;
	case kFileIconAdded:
		pixmap = sFileIconAddedIcon;
		break;
	case kFileIconConflict:
		pixmap = sFileIconConflictIcon;
		break;
	case kFileIconMiss:
		pixmap = sFileIconMissIcon;
		break;
	case kFolderIcon:
		pixmap = sFolderIconIcon;
		break;
	case kFolderIconUnknown:
		pixmap = sFolderIconUnknownIcon;
		break;
	case kFolderIconMiss:
		pixmap = sFolderIconMissIcon;
		break;
	case kFileIconTextMod:
		pixmap = sFileIconTextModIcon;
		break;
	case kFileIconBinaryMod:
		pixmap = sFileIconBinaryModIcon;
		break;
	case kFileIconIgnored:
		pixmap = sFileIconIgnoredIcon;
		break;
	case kFolderIconIgnored:
		pixmap = sFolderIconIgnoredIcon;
		break;
	case kFileIconRemoved:
		pixmap = sFileIconRemovedIcon;
		break;
	}
	if(pixmap != 0L)
	{
		resIcon = gtk_pixmap_new (GTK_PIXMAP(pixmap)->pixmap, GTK_PIXMAP(pixmap)->mask);
	}
#endif

	return resIcon;
}


int UCvsFiles::OnCmdUpdate(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdUpdateFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdUpdateFiles(&mf);
	}
	return 0;
}

bool UCvsFiles::DisableGeneric()
{
	return UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, -1), 0L) == -1 ||
		UCvsApp::gApp->IsCvsRunning() || gCvsPrefs.empty() || !HasFocus();
}

void UCvsFiles::OnCmdUIUpdate(UCmdUI *pCmdUI)
{
	if(DisableGeneric())
	{
		pCmdUI->Enable(false);
		return;
	}

	int nItem = -1;
	bool res = true;
	int numFiles = 0;
	int numFolders = 0;

	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->IsUnknown())
		{
			res = false;
			break;
		}
		if(data->GetType() == ENT_FILE)
			numFiles++;
		else
			numFolders++;

		if((numFiles != 0) && (numFolders != 0))
		{
			res = false;
			break;
		}
	}

	pCmdUI->Enable(res);
}

void UCvsFiles::OnCmdUIAdd(UCmdUI *pCmdUI)
{
	if(DisableGeneric())
	{
		pCmdUI->Enable(false);
		return;
	}

	int nItem = -1;
	bool res = true;
	int numFiles = 0;
	int numFolders = 0;

	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(!(data->IsUnknown() || (data->IsRemoved() && data->IsMissing())))
		{
			res = false;
			break;
		}
		if(data->GetType() == ENT_FILE)
		{
			numFiles++;
		}
		else
			numFolders++;

		if((numFiles != 0) && (numFolders != 0))
		{
			res = false;
			break;
		}
	}

	pCmdUI->Enable(res);
}

void UCvsFiles::OnCmdUIAddB(UCmdUI *pCmdUI)
{
	if(DisableGeneric())
	{
		pCmdUI->Enable(false);
		return;
	}

	int nItem = -1;
	bool res = true;

	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() != ENT_FILE)
		{
			res = false;
			break;
		}
		if(!(data->IsUnknown() || (data->IsRemoved() && data->IsMissing())))
		{
			res = false;
			break;
		}
	}

	pCmdUI->Enable(res);
}

void UCvsFiles::OnCmdUIRelease(UCmdUI *pCmdUI)
{
	if(DisableGeneric())
	{
		pCmdUI->Enable(false);
		return;
	}

	int nItem = -1;
	bool res = true;
	int numFolders = 0;

	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->IsUnknown() || data->GetType() != ENT_SUBDIR)
		{
			res = false;
			break;
		}
		numFolders++;

		if(numFolders > 1)
		{
			res = false;
			break;
		}
	}

	pCmdUI->Enable(res);
}

void UCvsFiles::OnCmdUIRmv(UCmdUI *pCmdUI)
{
	if(DisableGeneric())
	{
		pCmdUI->Enable(false);
		return;
	}

	int nItem = -1;
	bool res = true;

	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->IsUnknown() || data->IsRemoved() || data->GetType() == ENT_SUBDIR)
		{
			res = false;
			break;
		}
	}

	pCmdUI->Enable(res);
}

void UCvsFiles::OnCmdUIGraph(UCmdUI *pCmdUI)
{
	if(DisableGeneric())
	{
		pCmdUI->Enable(false);
		return;
	}

	int nItem = -1;
	bool res = true;

	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->IsUnknown() || data->GetType() == ENT_SUBDIR)
		{
			res = false;
			break;
		}
	}

	pCmdUI->Enable(res);
}

void UCvsFiles::OnCmdUIEditseldef(UCmdUI *pCmdUI)
{
	if(DisableGeneric())
	{
		pCmdUI->Enable(false);
		return;
	}

	int nItem = -1;
	bool res = true;

	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR || data->IsMissing())
		{
			res = false;
			break;
		}
	}

	pCmdUI->Enable(res);
	if(gCvsPrefs.Viewer() != 0L)
	{
		CStr title("Edit with ");
		title << gCvsPrefs.Viewer();
		pCmdUI->SetText(title);
	}
}

void UCvsFiles::OnCmdUIReload(UCmdUI *pCmdUI)
{
	pCmdUI->Enable(!DisableGeneric());
}

void UCvsFiles::OnCmdUIUpone(UCmdUI *pCmdUI)
{
	pCmdUI->Enable(!DisableGeneric());
}

void UCvsFiles::OnCmdUITrash(UCmdUI *pCmdUI)
{
	if(DisableGeneric())
	{
		pCmdUI->Enable(false);
		return;
	}

	int nItem = -1;
	bool res = true;

	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);
		if(data->GetType() == ENT_SUBDIR || data->IsMissing())
		{
			res = false;
			break;
		}
	}

	pCmdUI->Enable(res);
}

void UCvsFiles::OnCmdUIExplore(UCmdUI *pCmdUI)
{
	if(DisableGeneric())
	{
		pCmdUI->Enable(false);
		return;
	}

	int nItem = -1;
	bool res = true;
	int numItem = 0;

	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->IsMissing() || ++numItem > 1)
		{
			res = false;
			break;
		}
	}

	pCmdUI->Enable(res);
}

void UCvsFiles::OnCmdUIIgnore(UCmdUI *pCmdUI)
{
	pCmdUI->Enable(!DisableGeneric());
	pCmdUI->Check(gFileViewIgnore);
}

void UCvsFiles::OnCmdUIMacroSel(int cmd, UCmdUI *pCmdUI)
{
	if(DisableGeneric())
	{
		pCmdUI->Enable(false);
		return;
	}

	int nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, -1), 0L);
	pCmdUI->Enable(nItem != -1 && CTcl_Interp::IsAvail());
}

int UCvsFiles::OnCmdAdd(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdAddFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdAddFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdAddb(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdAddFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdAddBinaryFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdCommit(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdCommitFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdCommitFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdRmv(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() != ENT_FILE)
			continue;

		mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdRemoveFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdQueryUpdate(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdUpdateFolder(fullpath, true);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdUpdateFiles(&mf, true);
	}
	return 0;
}

int UCvsFiles::OnCmdReload(void)
{
	ResetView(true, true);
	return 0;
}

int UCvsFiles::OnCmdUpone(void)
{
	UStr uppath, filename;
	SplitPath(m_path, uppath, filename);
	ResetView((const char *)uppath, true);
	return 0;
}

int UCvsFiles::OnCmdTrash(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() != ENT_FILE)
			continue;

		mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
	}

	if(mf.NumFiles() != 0)
	{
		CvsArgs args(false);
		mf.next();
		const char *dir = mf.add(args);
		char * const *argv = args.Argv();
		int argc = args.Argc();
		for(int i = 0; i < argc; i++)
		{
			CStr fullpath(dir);
			if(!fullpath.empty() && !fullpath.endsWith(kPathDelimiter))
			{
				fullpath << kPathDelimiter;
			}
			fullpath << argv[i];

			if(chmod(fullpath, 0666) != 0)
			{
				cvs_err("Unable to change permission on '%s' (error %d)\n", (const char *)fullpath, errno);
				continue;
			}
			
			if(!CompatMoveToTrash(argv[i], dir))
				cvs_err("Unable to remove '%s' (error %d)\n", (const char *)fullpath, errno);
			else
#ifdef WIN32
				cvs_out("'%s' has been moved successfully to the recycle bin...\n", (const char *)fullpath);
#else
				cvs_out("'%s' has been deleted successfully...\n", (const char *)fullpath);
#endif
			}

		ResetView(true);
	}
	return 0;
}

int UCvsFiles::OnCmdDiff(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdDiffFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdDiffFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdLog(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdLogFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdLogFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdGraph(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() != ENT_FILE)
			continue;

		mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdLogFiles(&mf, true);
	}
	return 0;
}

int UCvsFiles::OnCmdStatus(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdStatusFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdStatusFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdLock(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdLockFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdLockFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdUnlock(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdUnlockFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdUnlockFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdWatchOn(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdWatchOnFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdWatchOnFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdWatchOff(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdWatchOffFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdWatchOffFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdEdit(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdEditFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdEditFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdUnedit(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdUneditFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdUneditFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdWatchers(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdWatchersFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdWatchersFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdEditors(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdEditorsFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdEditorsFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdRelease(void)
{
	int nItem = -1;

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdReleaseFolder(fullpath);
		}
	}
	return 0;
}

int UCvsFiles::OnCmdTagNew(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdTagCreateFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdTagCreateFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdTagDelete(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdTagDeleteFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdTagDeleteFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdTagBranch(void)
{
	int nItem = -1;

	MultiFiles mf;
	mf.newdir(m_path);

	// first add the folders
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		if(data->GetType() == ENT_SUBDIR)
		{
			CStr fullpath;
			fullpath = m_path;
			if(!fullpath.endsWith(kPathDelimiter))
				fullpath << kPathDelimiter;
			fullpath << (*data)[EntnodeData::kName];
			CvsCmdTagBranchFolder(fullpath);
		}
		else
		{
			mf.newfile((*data)[EntnodeData::kName], 0, (*data)[EntnodeFile::kVN]);
		}
	}
	if(mf.NumFiles() != 0)
	{
		CvsCmdTagBranchFiles(&mf);
	}
	return 0;
}

int UCvsFiles::OnCmdExplore(void)
{
	int nItem = -1;

	// first add the folders
	if((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);

		CStr fullpath;
		fullpath = m_path;
		if(!fullpath.endsWith(kPathDelimiter))
			fullpath << kPathDelimiter;
		fullpath << (*data)[EntnodeData::kName];

#ifdef WIN32
		HINSTANCE hInst = ShellExecute(*AfxGetMainWnd(), "explore", fullpath,
									   0L, 0L, SW_SHOWDEFAULT);
		if((long)hInst < 32)
		{
			cvs_err("Unable to explore '%s' (error %d)\n", (char *)m_path, GetLastError());
		}
#endif
#ifdef qUnix
		CvsArgs args(false);
		args.add(gCvsPrefs.Browser());
		args.add(fullpath);
		UCvsApp::gApp->Execute(args.Argc(), args.Argv());
#endif
	}
	return 0;
}

int UCvsFiles::OnCmdIgnore(void)
{
	gFileViewIgnore = !(bool)gFileViewIgnore;
	ResetView(true, true);
	return 0;
}

int UCvsFiles::OnCmdEditsel(void)
{
	int nItem = -1;

	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);
		EditSel(data);
	}
	return 0;
}

int UCvsFiles::OnCmdEditseldef(void)
{
	int nItem = -1;

	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);
		EditSel(data, true);
	}
	return 0;
}

int UCvsFiles::OnMacroSel(int cmd)
{
	CTcl_Interp interp;
	CMacroEntry & entry = gMacrosSel.entries[cmd - cmdSELMACRO];
	CStr path = entry.path;
	CTcl_Interp::Unixfy(path);

	TclBrowserReset();

	int nItem = -1;
	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);
		TclBrowserAppend(m_path, data);
	}

	interp.DoScriptVar("source \"%s\"", (const char *)path);
	return 0;
}

void UCvsFiles::EditSel(EntnodeData *data, bool useDefault)
{
	CStr fullpath;
	fullpath = m_path;
	if(!fullpath.endsWith(kPathDelimiter))
		fullpath << kPathDelimiter;
	fullpath << (*data)[EntnodeData::kName];
	if(data->GetType() == ENT_SUBDIR)
	{
		ResetView((const char *)fullpath, true);
	}
	else
	{
#ifdef WIN32
		char viewer[_MAX_PATH];
		HINSTANCE hInst = FindExecutable((*data)[EntnodeData::kName],
			m_path, viewer);
		bool done = false;
		if(!useDefault && (UINT)hInst >= 32)
		{
			HINSTANCE hInst = ShellExecute(*AfxGetMainWnd(), "open", (*data)[EntnodeData::kName],
				NULL, m_path, SW_SHOWDEFAULT);
			if((long)hInst < 32)
			{
				cvs_err("Unable to open '%s' (error %d), using default viewer instead\n", (char *)fullpath, GetLastError());
			}
			else
				done = true;
		} 

		if(!done)
		{
			const char * argv[3] = {0L, 0L, 0L};
			CStr program, file;
			if(strchr(gCvsPrefs.Viewer(), ' ') != 0L)
			{
				program << '\"';
				program << gCvsPrefs.Viewer();
				program << '\"';
			}
			else
				program = gCvsPrefs.Viewer();
			if(strchr(fullpath, ' ') != 0L)
			{
				file << '\"';
				file << fullpath;
				file << '\"';
			}
			else
				file = fullpath;
			argv[0] = program;
			argv[1] = file;
			int process = _spawnvp(_P_NOWAIT, gCvsPrefs.Viewer(), argv);
		}
#endif
#ifdef qUnix
		CStr fullpath;
		fullpath = m_path;
		if(!fullpath.endsWith(kPathDelimiter))
			fullpath << kPathDelimiter;
		fullpath << (*data)[EntnodeData::kName];

		CvsArgs args(false);
		args.add(gCvsPrefs.Viewer());
		args.add(fullpath);
		UCvsApp::gApp->Execute(args.Argc(), args.Argv());
#endif
	}
}

void UCvsFiles::OnDblClick(void)
{
	int nItem = -1;

	while((nItem = UEventSendMessage(GetWidID(), EV_LIST_GETNEXTSEL, UMAKEINT(kUMainWidget, nItem), 0L)) != -1)
	{
		EntnodeData *data;
		UEventSendMessage(GetWidID(), EV_LIST_ROWGETDATA, UMAKEINT(kUMainWidget, nItem), &data);
		EditSel(data);
	}
}

static int compareName(UWidget *wid, void *data1, void *data2)
{
	UCvsFiles *w = (UCvsFiles *)wid;
	EntnodeData *d1 = (EntnodeData *)data1;
	EntnodeData *d2 = (EntnodeData *)data2;
	int res = stricmp((*d1)[EntnodeData::kName], (*d2)[EntnodeData::kName]);
	return w->IsSortAscendant() ? res : -res;
}

static int compareStatus(UWidget *wid, void *data1, void *data2)
{
	UCvsFiles *w = (UCvsFiles *)wid;
	EntnodeData *d1 = (EntnodeData *)data1;
	EntnodeData *d2 = (EntnodeData *)data2;
	int res = stricmp((*d1)[EntnodeData::kStatus], (*d2)[EntnodeData::kStatus]);
	if(res == 0)
		res = stricmp((*d1)[EntnodeData::kName], (*d2)[EntnodeData::kName]);
	return w->IsSortAscendant() ? res : -res;
}

static int compareOption(UWidget *wid, void *data1, void *data2)
{
	UCvsFiles *w = (UCvsFiles *)wid;
	EntnodeData *d1 = (EntnodeData *)data1;
	EntnodeData *d2 = (EntnodeData *)data2;
	const char *s1 = (*d1)[EntnodeFile::kOption];
	const char *s2 = (*d2)[EntnodeFile::kOption];
	int res;
	if(s1 != 0L && s2 != 0L)
		res = strcmp(s1, s2);
	else
		res = (long)s1 < (long)s2 ? -1 : ((long)s1 > (long)s2 ? 1 : 0);
	if(res == 0)
		res = stricmp((*d1)[EntnodeData::kName], (*d2)[EntnodeData::kName]);
	return w->IsSortAscendant() ? res : -res;
}

static int revcmp(const char *rev1, const char *rev2)
{
	if(rev1 == 0L && rev2 == 0L)
		return 0;
	else if(rev1 == 0L || rev2 == 0L)
		return rev1 == 0L ? -1 : 1;

	CStr r1(rev1), r2(rev2);
	CStr q1, q2;
	char *tmp;
	int v1, v2;

	if((tmp = strchr(r1, '.')) != 0L)
	{
		tmp[0] = '\0';
		q1 = tmp + 1;
	}

	v1 = atoi(r1);

	if((tmp = strchr(r2, '.')) != 0L)
	{
		tmp[0] = '\0';
		q2 = tmp + 1;
	}
	v2 = atoi(r2);

	if(v1 == v2)
		return revcmp(q1.empty() ? (char *)0L : (const char *)q1, q2.empty() ? (char *)0L : (const char *)q2);

	return v1 < v2 ? -1 : 1;
}

static int compareRevs(UWidget *wid, void * data1, void * data2)
{
	UCvsFiles *w = (UCvsFiles *)wid;
	EntnodeData *d1 = (EntnodeData *)data1;
	EntnodeData *d2 = (EntnodeData *)data2;
	const char *s1 = (*d1)[EntnodeFile::kVN];
	const char *s2 = (*d2)[EntnodeFile::kVN];
	int res;
	if(s1 != 0L && s2 != 0L)
		res = revcmp(s1, s2);
	else
		res = (long)s1 < (long)s2 ? -1 : ((long)s1 > (long)s2 ? 1 : 0);
	if(res == 0)
		res = stricmp((*d1)[EntnodeData::kName], (*d2)[EntnodeData::kName]);
	return w->IsSortAscendant() ? res : -res;
}

static int compareTag(UWidget *wid, void * data1, void * data2)
{
	UCvsFiles *w = (UCvsFiles *)wid;
	EntnodeData *d1 = (EntnodeData *)data1;
	EntnodeData *d2 = (EntnodeData *)data2;
	const char *s1 = (*d1)[EntnodeFile::kTag];
	const char *s2 = (*d2)[EntnodeFile::kTag];
	int res;
	if(s1 != 0L && s2 != 0L)
		res = strcmp(s1, s2);
	else
		res = (long)s1 < (long)s2 ? -1 : ((long)s1 > (long)s2 ? 1 : 0);
	if(res == 0)
		res = stricmp((*d1)[EntnodeData::kName], (*d2)[EntnodeData::kName]);
	return w->IsSortAscendant() ? res : -res;
}

static int compareConflict(UWidget *wid, void * data1, void * data2)
{
	UCvsFiles *w = (UCvsFiles *)wid;
	EntnodeData *d1 = (EntnodeData *)data1;
	EntnodeData *d2 = (EntnodeData *)data2;
	const char *s1 = (*d1)[EntnodeFile::kConflict];
	const char *s2 = (*d2)[EntnodeFile::kConflict];
	int res;
	if(s1 != 0L && s2 != 0L)
		res = strcmp(s1, s2);
	else
		res = (long)s1 < (long)s2 ? -1 : ((long)s1 > (long)s2 ? 1 : 0);
	if(res == 0)
		res = stricmp((*d1)[EntnodeData::kName], (*d2)[EntnodeData::kName]);
	return w->IsSortAscendant() ? res : -res;
}

static int compareTimestamp(UWidget *wid, void *data1, void *data2)
{
	UCvsFiles *w = (UCvsFiles *)wid;
	EntnodeData *d1 = (EntnodeData *)data1;
	EntnodeData *d2 = (EntnodeData *)data2;
	
	const char *s1 = (*d1)[EntnodeFile::kTS];
	const char *s2 = (*d2)[EntnodeFile::kTS];
	
	int res;
	
	if(s1 != 0L && s2 != 0L ) {
		UStr str[2] = {s1, s2};
		
		UStr t[2];
		
		for(int i=0; i < 2; i++) {
			// put the year in front of the date string
			t[i] = str[i].substr(str[i].rfind(" ")+1, 4);
			t[i] += " ";

			// convert month name to month number
			for(int j=0; j < 12; j++) {
				if( !(strcmp(str[i].substr(4,3), month_names[j]) ) ) {
					if(j<9)
						t[i] += "0";
					
					t[i] += j+1; 
					
					break;
				}
			}

			t[i] += " ";
			// paste day and time to time string
			t[i] += str[i].substr(8, str[i].rfind(" ")-4);
		}
		
		res = t[0].compare(t[1]);
		
#ifdef DEBUG
		fprintf(stderr, "%s %c %s\n", t[0].c_str(), (res==1?'<':'>') , t[1].c_str());
#endif
		
	} else {
		res = s1 < s2 ? -1 : (s1 > s2 ? 1 : 0);
	}
	
	if(res == 0)
		res = stricmp((*d1)[EntnodeData::kName], (*d2)[EntnodeData::kName]);
		
	return w->IsSortAscendant() ? res : -res;
}

void UCvsFiles::Resort(void)
{
	UListSorter fsort = 0L;
	switch(m_sort)
	{
	case EntnodeData::kName:
		fsort = compareName;
		break;
	case EntnodeFile::kVN:
		fsort = compareRevs;
		break;
	case EntnodeData::kStatus:
		fsort = compareStatus;
		break;
	case EntnodeFile::kOption:
		fsort = compareOption;
		break;
	case EntnodeFile::kTag:
		fsort = compareTag;
		break;
	case EntnodeFile::kConflict:
		fsort = compareConflict;
		break;
	case EntnodeFile::kTS:
		fsort = compareTimestamp;
		break;
	}
	if(fsort != 0L)
		UEventSendMessage(GetWidID(), EV_LIST_RESORT, UMAKEINT(kUMainWidget, m_sort), (void *)fsort);
}

void UCvsFiles::OnSelColumn(int column)
{
	if(column == m_sort)
		m_ascendant = !m_ascendant;
	else
	{
		m_ascendant = true;
		switch(column)
		{
		case EntnodeData::kName:
		case EntnodeData::kStatus:
		case EntnodeFile::kOption:
		case EntnodeFile::kTag:
		case EntnodeFile::kConflict:
		case EntnodeFile::kTS:
		case EntnodeFile::kVN:
			m_sort = column;
			break;
		}
	}

	Resort();
}

Reply via email to