/******************************************************************************
 GMailboxTreeWidget.cc

	<Description>

	BASE CLASS = public JXNamedTreeListWidget

	Copyright © 1997 by Glenn W. Bach.  All rights reserved.
	
	Base code generated by Codemill v0.1.0

 *****************************************************************************/

#include <GMailboxTreeWidget.h>
#include <GMailboxTreeDir.h>
#include <GMailFileTreeNode.h>
#include <GMessageHeader.h>
#include <GSimpleFileTree.h>
#include <GMailboxTreeDir.h>
#include <GMailboxChooseSaveFile.h>
#include <GMGlobals.h>
#include "envelopes_cursor.h"
#include "GMApp.h"
#include "gMailUtils.h"

#include "envelopes.xpm"
#include "tall_envelopes.xpm"
#include "locked_envelopes.xpm"
#include "selected_envelopes.xpm"
#include "selectedfolderIcon.xpm"
#include "gm_folderIcon.xpm"
#include "gm_tall_folderIcon.xpm"
#include "unlock.xpm"

#include <JNamedTreeNode.h>
#include <JNamedTreeList.h>

#include <JXToolBar.h>
#include <JXMenuBar.h>
#include <JXTextMenu.h>
#include <JString.h>
#include <JXWindow.h>
#include <JXWindowPainter.h>
#include <JXDirector.h>
#include <JXSelectionManager.h>
#include <JXUserNotification.h>
#include <JXApplication.h>
#include <JXDNDManager.h>
#include <JXChooseSaveFile.h>
#include <JXImage.h>
#include <JXDisplay.h>
#include <JXColormap.h>
#include <JXInputField.h>

#include <JTableSelection.h>
#include <JTableSelectionIterator.h>
#include <JOrderedSetIterator.h>
#include <JUNIXDirInfo.h>
#include <JUNIXDirEntry.h>
#include <JError.h>

#include <jDirUtil.h>
#include <jFileUtil.h>
#include <jProcessUtil.h>
#include <jASCIIConstants.h>
#include <jStrStreamUtil.h>
#include <jStreamUtil.h>
#include <jErrno.h>

#include <GMailboxUtils.h>

#include <X11/keysym.h>
#include <strstream.h>
#include <iostream.h>
#include <fstream.h>
#include <jAssert.h>

static const JCharacter* kGMailboxMenuTitleStr = "Mailboxes";
static const JCharacter* kGMailboxMenuStr = 
	"New mailbox %k Meta-N  %i \"NewMailbox::Arrow\""
	"|New directory %k Meta-Shift-N %i \"NewDir::Arrow\""
	"|Add mailbox %i \"AddMailbox::Arrow\""
	"|Add directory %k Meta-D  %i \"AddDir::Arrow\""
	"%l| Remove from list %i \"Remove::Arrow\""
	"| Delete from file system %i \"Delete::Arrow\""
	"|Unlock %i \"Unlock::Arrow\""
	"%l|Edit tool bar... %i \"EditToolBar::Arrow\""
	"%l|Close %k Meta-W %i \"Close::Arrow\"";

enum
{
	kNewMBoxCmd = 1,
	kNewDirCmd,
	kAddMBoxCmd,
	kAddDirCmd,
	kRemoveCmd,
	kDeleteCmd,
	kUnlockCmd,
	kEditToolBarCmd,
	kCloseCmd
};

const JCoordinate kDragBeginBuffer 		= 5;
const JCoordinate kCurrentPrefsVersion	= 0;
const JCoordinate kMinRowHeight			= 18;
const JFloat kRowHeightFactor			= 1.2;

static const JCharacter* kDragMessagesXAtomName  = "GMailMessages";
static const JCharacter* kDragMailboxesXAtomName = "GMailBoxes";

/******************************************************************************
 Constructor

 *****************************************************************************/

GMailboxTreeWidget*
GMailboxTreeWidget::Create
	(
	GSimpleFileTree*	tree,
	JNamedTreeList* 	treeList, 
	JXMenuBar* 			menuBar,
	JXScrollbarSet* 	scrollbarSet, 
	JXContainer* 		enclosure,
	const HSizingOption	hSizing, 
	const VSizingOption vSizing,
	const JCoordinate 	x, 
	const JCoordinate 	y,
	const JCoordinate 	w, 
	const JCoordinate 	h
	)
{
	GMailboxTreeWidget* widget =
		new GMailboxTreeWidget(tree, treeList, menuBar,
			scrollbarSet, enclosure, hSizing, vSizing, x, y, w, h);
	assert(widget != NULL);

	widget->JXTreeListWidgetX();
	return widget;
}

GMailboxTreeWidget::GMailboxTreeWidget
	(
	GSimpleFileTree*	tree,
	JNamedTreeList* 	treeList, 
	JXMenuBar* 			menuBar,
	JXScrollbarSet* 	scrollbarSet, 
	JXContainer* 		enclosure,
	const HSizingOption	hSizing, 
	const VSizingOption vSizing,
	const JCoordinate 	x, 
	const JCoordinate 	y,
	const JCoordinate 	w, 
	const JCoordinate 	h
	)
	:
   JXNamedTreeListWidget(treeList, scrollbarSet,
   							enclosure, hSizing, vSizing, x, y, w, h)
{
	itsTree 	= tree;
	
	itsMailboxMenu = menuBar->AppendTextMenu(kGMailboxMenuTitleStr);
	itsMailboxMenu->SetMenuItems(kGMailboxMenuStr);
	itsMailboxMenu->SetUpdateAction(JXMenu::kDisableNone);
	ListenTo(itsMailboxMenu);

	GSimpleFileTreeNode* base = 
		dynamic_cast(GSimpleFileTreeNode*, itsTree->GetRoot());
    
	itsCurrentDndHereIndex 	= 0;
	itsDraggingFiles		= kFalse;
	itsOutsideRoot			= kFalse;
	itsWaitingToEdit		= kFalse;

	const Atom dndName 		= (GetDNDManager())->GetDNDSelectionName();	
	itsMessageXAtom    		= GetDisplay()->RegisterXAtom(kDragMessagesXAtomName);
	itsMailboxXAtom    		= AddSelectionTarget(dndName, kDragMailboxesXAtomName);

	itsMailIcon = new JXImage(GetDisplay(), GetColormap(), JXPM(tall_envelopes));
	assert( itsMailIcon != NULL );
	itsMailIcon->ConvertToRemoteStorage();

	itsSelectedMailIcon = new JXImage(GetDisplay(), GetColormap(), JXPM(selected_envelopes));
	assert( itsSelectedMailIcon != NULL );
	itsSelectedMailIcon->ConvertToRemoteStorage();

	itsLockedMailIcon = new JXImage(GetDisplay(), GetColormap(), JXPM(locked_envelopes));
	assert( itsLockedMailIcon != NULL );
	itsLockedMailIcon->ConvertToRemoteStorage();

	itsSelectedFolderIcon = new JXImage(GetDisplay(), GetColormap(), JXPM(selectedfolderIcon_xpm));
	assert( itsSelectedFolderIcon != NULL );
	itsSelectedFolderIcon->ConvertToRemoteStorage();

	itsFolderIcon = new JXImage(GetDisplay(), GetColormap(), JXPM(tall_folder_xpm));
	assert( itsFolderIcon != NULL );
	itsFolderIcon->ConvertToRemoteStorage();

	if (!(GetDisplay())->GetCursor(kEnvelopesCursorName, &itsDNDCursor))
		{
		itsDNDCursor =
			(GetDisplay())->CreateCustomCursor(kEnvelopesCursorName, kEnvelopesCursor);
		}

	itsMailboxMenu->SetItemImage(kNewMBoxCmd, JXPM(envelopes));
	itsMailboxMenu->SetItemImage(kNewDirCmd, JXPM(folder_xpm));
	itsMailboxMenu->SetItemImage(kUnlockCmd, JXPM(unlock_xpm));

	JCoordinate height = GetDefaultRowHeight();
	height = JMax(JCoordinate(height*kRowHeightFactor), kMinRowHeight);	
	SetDefaultRowHeight(height);
}

/******************************************************************************
 Destructor

 *****************************************************************************/

GMailboxTreeWidget::~GMailboxTreeWidget()
{
	delete itsSelectedMailIcon;
	delete itsLockedMailIcon;
	delete itsSelectedFolderIcon;
	delete itsFolderIcon;
	delete itsMailIcon;
}

/******************************************************************************
 Draw (virtual protected)


 ******************************************************************************/

void
GMailboxTreeWidget::Draw
	(
	JXWindowPainter& p, 
	const JRect& rect
	)
{
	JXNamedTreeListWidget::Draw(p, rect);
	if (itsOutsideRoot && itsDraggingFiles)
		{
		p.ResetClipRect();
		if (itsCurrentDndHereIndex == 0)
			{
			JRect crect = GetCellRect(JPoint(2, GetRowCount()));
			crect.bottom -= 2;
			p.Line(0, crect.bottom, crect.right, crect.bottom);
			}
		else
			{
			JRect crect = GetCellRect(JPoint(2, itsCurrentDndHereIndex));
			crect.top++;
			p.Line(0, crect.top, crect.right, crect.top);
			}
		}
}

/******************************************************************************
 Receive (virtual protected)


 ******************************************************************************/

void
GMailboxTreeWidget::Receive
	(
	JBroadcaster*	sender,
	const Message&	message
	)
{
	if (sender == itsMailboxMenu && message.Is(JXMenu::kItemSelected))
		{
		 const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandleGMailboxMenu(selection->GetIndex());
		}
	else if (sender == itsMailboxMenu && message.Is(JXMenu::kNeedsUpdate))
		{
		UpdateGMailboxMenu();
		}
	JXNamedTreeListWidget::Receive(sender, message);
}

/******************************************************************************
 HandleKeyPress

 ******************************************************************************/

void  
GMailboxTreeWidget::HandleKeyPress
	(
	const int key,
	const JXKeyModifiers&   modifiers
	)
{
	JPoint topSelCell;
	JTableSelection& s          = GetTableSelection();
	const JBoolean hadSelection	= s.GetFirstSelectedCell(&topSelCell);
	JPoint oldBoat 				= s.GetBoat();

	if (key == kJReturnKey && !IsEditing())
		{
		if (hadSelection)
			{
			if (s.GetSelectedCellCount() == 1 && 
				GetNamedTreeList()->GetNode(topSelCell.y)->IsOpenable())
				{
				if (GetNamedTreeList()->IsOpen(topSelCell.y))
					{
					GetNamedTreeList()->Close(topSelCell.y);
					}
				else
					{
					GetNamedTreeList()->Open(topSelCell.y);
					}
				}
			else
				{
				JTableSelectionIterator iter(&s);
				JPoint cell;
				while (iter.Next(&cell))
					{
					if (!GetNamedTreeList()->GetNode(cell.y)->IsOpenable())
						{
						OpenMailbox(cell.y);
						}
					}
				}
			}
		}

	else if (key == kJForwardDeleteKey || key == kJDeleteKey)
		{
		JBoolean okDir;
		JBoolean okFile;
		JBoolean unLock;
		CheckSelectionForMenus(&okDir, &okFile, &unLock);
		if (okDir)
			{
			DeleteSelected();
			}
		}

	else if ((key == kJEscapeKey) && 
			 !IsEditing())
		{
		GetWindow()->GetDirector()->Deactivate();
		}

	else if ((key == kJUpArrow) && !IsEditing())
		{
		if (hadSelection)
			{
			if (modifiers.shift())
				{
				if (s.OKToExtendSelection())
					{
					if (oldBoat.y > 1)
						{
						s.ExtendSelection(JPoint(2, oldBoat.y - 1));
						TableScrollToCell(JPoint(1, oldBoat.y - 1));
						(GetWindow())->Update();
						}
					}
				}
			else
				{
				s.ClearSelection();
				JIndex index = topSelCell.y;
				if (index > 1)
					{
					index -= 1;
					}
				s.SelectCell(index, 2);
				s.SetBoat(JPoint(2, index));
				s.SetAnchor(JPoint(2, index));
				TableScrollToCell(JPoint(1, index));
				(GetWindow())->Update();
				}
			}
		else
			{
			if (GetRowCount() > 0)
				{
				s.SelectCell(GetRowCount(), 2);
				s.SetBoat(JPoint(2, GetRowCount()));
				s.SetAnchor(JPoint(2, GetRowCount()));
				TableScrollToCell(JPoint(1, GetRowCount()));
				(GetWindow())->Update();
				}
			}
		}
	else if ((key == kJDownArrow) && !IsEditing())
		{
		if (hadSelection)
			{
			if (modifiers.shift())
				{
				if (s.OKToExtendSelection())
					{
					if (oldBoat.y < (JCoordinate)GetRowCount())
						{
						s.ExtendSelection(JPoint(2, oldBoat.y + 1));
						(GetWindow())->Update();
						TableScrollToCell(JPoint(1, oldBoat.y + 1));
						}
					}
				}
			else
				{
				s.ClearSelection();
				JIndex index = topSelCell.y;
				if (index < GetRowCount())
					{
					index += 1;
					}
				s.SelectCell(index, 2);
				s.SetBoat(JPoint(2, index));
				s.SetAnchor(JPoint(2, index));
				TableScrollToCell(JPoint(1, index));
				(GetWindow())->Update();
				}
			}
		else
			{
			if (GetRowCount() > 0)
				{
				s.SelectCell(1, 2);
				s.SetBoat(JPoint(2, 1));
				s.SetAnchor(JPoint(2, 1));
				TableScrollToCell(JPoint(1, 1));
				(GetWindow())->Update();
				}
			}
		}
	else
		{
		JXNamedTreeListWidget::HandleKeyPress(key, modifiers);
		}
}
/******************************************************************************
 UpdateGMailboxMenu 


 ******************************************************************************/

void
GMailboxTreeWidget::UpdateGMailboxMenu()
{
	JTableSelection& s = GetTableSelection();
	JSize count = s.GetSelectedCellCount();
	if (count == 0)
		{
		itsMailboxMenu->DisableItem(kDeleteCmd);
		itsMailboxMenu->DisableItem(kRemoveCmd);
		itsMailboxMenu->DisableItem(kUnlockCmd);
		return;
		}
	JBoolean okDir;
	JBoolean okFile;
	JBoolean unLock;
	CheckSelectionForMenus(&okDir, &okFile, &unLock);
	if (okFile)
		{	
		itsMailboxMenu->EnableItem(kDeleteCmd);
		}
	else
		{
		itsMailboxMenu->DisableItem(kDeleteCmd);
		}
	if (okDir)
		{	
		itsMailboxMenu->EnableItem(kRemoveCmd);
		}
	else
		{
		itsMailboxMenu->DisableItem(kRemoveCmd);
		}
	if (unLock && okFile)
		{	
		itsMailboxMenu->EnableItem(kUnlockCmd);
		}
	else
		{
		itsMailboxMenu->DisableItem(kUnlockCmd);
		}
}

/******************************************************************************
 HandleGMailboxMenu 


 ******************************************************************************/

void
GMailboxTreeWidget::HandleGMailboxMenu
	(
	const JIndex index
	)
{
	if (index == kNewMBoxCmd)
		{
		JString mbox;
		if (JXGetChooseSaveFile()->SaveFile("Name of new mailbox:", "", "",  &mbox))
			{
			GMGetApplication()->NewMailbox(mbox, kFalse);
			}
		}
	else if (index == kNewDirCmd)
		{
		JString dir;
		if (JXGetChooseSaveFile()->SaveFile("Name of new directory:", "", "",  &dir))
			{
			JError err = JCreateDirectory(dir);
			if (!err.OK())
				{
				if (err.Is(kJAccessDenied))
					{
					JGetUserNotification()->ReportError("The access to create this directory was denied.");
					}
				else if (!err.Is(kJDirectoryAlreadyExists))
					{
					JGetUserNotification()->ReportError("I was unable to create this directory.");
					}
				}
			}
		}
	else if (index == kAddMBoxCmd)
		{
		JPtrArray<JString> fullNameList;
		if (GMGetMailboxCSF()->ChooseFiles("Select the mailboxes to add", "", &fullNameList))
			{
			JSize count = fullNameList.GetElementCount();
			for (JSize i = 1; i <= count; i++)
				{
				AddFile(*(fullNameList.NthElement(i)));
				}
			
//			JTreeNode* base = itsTree->GetRoot();
//			JNamedTreeNode* parent = 
//				dynamic_cast(JNamedTreeNode*, base);
//			assert(parent != NULL);
//			JSize count = fullNameList.GetElementCount();
//			for (JSize i = 1; i <= count; i++)
//				{
//				JUNIXDirEntry* entry = new JUNIXDirEntry(*(fullNameList.NthElement(i)));
//				assert(entry != NULL);
//				GMailFileTreeNode* node = 
//					new GMailFileTreeNode(itsTree, entry, parent, entry->GetName(),kFalse);
//				assert(node != NULL); 
//				}
			}
		}
	else if (index == kAddDirCmd)
		{
		JString fullname;
		JBoolean ok = JXGetChooseSaveFile()->ChooseRPath("Select directory to add:", "", "", &fullname);
		if (ok)
			{
			AddDirectory(fullname);
			}
		}
	else if (index == kRemoveCmd)
		{
		DeleteSelected();
		}
	else if (index == kDeleteCmd)
		{
		JTableSelection& s = GetTableSelection();
		JBoolean ok = JGetUserNotification()->AskUserYes("Are you sure you want to delete the selected mailboxes from the file system?");
		if (ok)
			{
			JTableSelectionIterator iter(&s);
			JPoint cell;
			iter.MoveTo(kJIteratorStartAtEnd, cell);
			while(iter.Prev(&cell))
				{
				JTreeNode* jnode = GetNamedTreeList()->GetNode(cell.y);
				GSimpleFileTreeNode* node = dynamic_cast(GSimpleFileTreeNode*, jnode);
				JError err = JRemoveFile(node->GetFullPathAndName());
				if (err.OK())
					{
					delete node;
					}
				else
					{
					JGetUserNotification()->ReportError("Unable to delete file.");
					}
				}
			}
		}	
	else if (index == kUnlockCmd)
		{
		JTableSelection& s = GetTableSelection();
		JBoolean ok = JGetUserNotification()->AskUserYes("Are you sure you want to unlock the selected mailboxes?");
		if (ok)
			{
			JTableSelectionIterator iter(&s);
			JPoint cell;
			iter.MoveTo(kJIteratorStartAtEnd, cell);
			while(iter.Prev(&cell))
				{
				JTreeNode* jnode = GetNamedTreeList()->GetNode(cell.y);
				GSimpleFileTreeNode* node = dynamic_cast(GSimpleFileTreeNode*, jnode);
				GUnlockFile(node->GetFullPathAndName());
				}
			}
		}
	else if (index == kEditToolBarCmd)
		{
		JXDirector* dir = GetWindow()->GetDirector();
		GMailboxTreeDir* aDir = 
			dynamic_cast(GMailboxTreeDir*, dir);
		assert(aDir != NULL);
		aDir->EditToolBar();
		}
	else if (index == kCloseCmd)
		{
		GetWindow()->GetDirector()->Deactivate();
		}
}

/******************************************************************************
 HandleMouseDown

 ******************************************************************************/

void
GMailboxTreeWidget::HandleMouseDown
	(
	const JPoint&			pt,
	const JXMouseButton 	button,
	const JSize 			clickCount,
	const JXButtonStates& 	buttonStates,
	const JXKeyModifiers& 	modifiers
	)
{
	ClearIncrementalSearchBuffer();
	
	if (IsEditing())
		{
		EndEditing();
		}
	itsDownInCell 		= kFalse;
	itsWaitingToEdit 	= kFalse;
	itsDownPt 			= pt;
	itsWaitingToEdit 	= kFalse;
	JTableSelection& s = GetTableSelection();

	JPoint cell;
	JXNamedTreeListWidget::NodePart part;
	if (GetNode(pt, &cell, &part))
		{
		JIndex index 			= cell.y;
		const JPoint newBoat 	= JPoint(2, index);
		const JPoint newAnchor 	= JPoint(2, index);
		if ((part == JXNamedTreeListWidget::kInText) && 
			(!modifiers.shift()) &&
			(!modifiers.meta()) && (!modifiers.control()) &&
			(button == kJXLeftButton))
			{
			itsWaitingToEdit 	= kTrue;
			}

		if ((part == JXNamedTreeListWidget::kInImage))
			{
			itsDownInCell = kTrue;
			}
		if (clickCount == 2 && !IsEditing() && 
			((part == JXNamedTreeListWidget::kInText) || 
			 (part == JXNamedTreeListWidget::kInImage)))
			{
			if (button == kJXLeftButton)
				{
				s.ClearSelection();
				OpenMailbox(index);
				}
			}
		else if ((part == JXNamedTreeListWidget::kInImage) ||
				 (part == JXNamedTreeListWidget::kInText))
			{
			if ((button == kJXLeftButton && modifiers.shift()) ||
				(button == kJXRightButton))
				{
				if (s.OKToExtendSelection())
					{
					s.ExtendSelection(newBoat);
					(GetWindow())->Update();
					}
				}
			else if (button == kJXLeftButton)
				{
				if (modifiers.control())
					{
					if (s.IsSelected(index, 2))
						{
						s.SelectCell(index, 2, kFalse);
						s.ClearBoat();
						s.ClearAnchor();
						(GetWindow())->Update();
						}
					else
						{
						s.SelectCell(index, 2, kTrue);
						s.SetBoat(newBoat);
						s.SetAnchor(newAnchor);
						(GetWindow())->Update();
						}
					}
				else if (!s.IsSelected(index, 2))
					{
					s.ClearSelection();
					s.SelectCell(index, 2);
					s.SetBoat(newBoat);
					s.SetAnchor(newAnchor);
					(GetWindow())->Update();
					}
				}
			}
		else
			{
			s.ClearSelection();
			}
		}
	else
		{
		itsDownInCell = kFalse;
		s.ClearSelection();
		}
	JXNamedTreeListWidget::HandleMouseDown(pt, button, 
		clickCount, buttonStates, modifiers);
}

/******************************************************************************
 HandleMouseDrag (virtual protected)

 ******************************************************************************/

void
GMailboxTreeWidget::HandleMouseDrag
	(
	const JPoint&			pt,
	const JXButtonStates&	buttonStates,
	const JXKeyModifiers&	modifiers
	)
{
	JPoint cell;
	JXNamedTreeListWidget::NodePart part;
	if (GetNode(pt, &cell, &part) && itsDownInCell)
		{
		JPoint p = itsDownPt - pt;
		if (sqrt(p.x*p.x + p.y*p.y) > kDragBeginBuffer)
			{
			itsWaitingToEdit = kFalse;
			if (OkToDND())
				{
				BeginDND(pt, buttonStates, modifiers);
				}
			}
		}
		
	JXNamedTreeListWidget::HandleMouseDrag(pt,buttonStates,modifiers);
}

/******************************************************************************
 HandleMouseUp (virtual protected)

 ******************************************************************************/

void
GMailboxTreeWidget::HandleMouseUp
	(
	const JPoint& pt, 
	const JXMouseButton button,
	const JXButtonStates& buttonStates,
	const JXKeyModifiers& modifiers
	)
{
	JPoint cell;
	if (GetCell(pt, &cell) && (itsWaitingToEdit))
		{
		JXNamedTreeListWidget::HandleMouseUp(pt, button, buttonStates, modifiers);
		GetTableSelection().ClearSelection();
		BeginEditing(cell);
		}
	else
		{
		JXNamedTreeListWidget::HandleMouseUp(pt, button, buttonStates, modifiers);
		}
}

/******************************************************************************
 HandleDNDResponse (virtual protected)

 ******************************************************************************/

void
GMailboxTreeWidget::HandleDNDResponse
	(
	const JXContainer*  target,
	const JBoolean 		dropAccepted, 
	const Atom 			action
	)
{
	DisplayCursor(itsDNDCursor);
}

/******************************************************************************
 HandleDNDHere 

 ******************************************************************************/

void
GMailboxTreeWidget::HandleDNDHere
	(
	const JPoint& 	pt,
	const JXWidget* source
	)
{
	ScrollForDrag(pt);
	JIndex oldIndex = itsCurrentDndHereIndex;
	if (oldIndex != 0)
		{
		TableRefreshRow(oldIndex);
		}
	else if (itsOutsideRoot)
		{
		TableRefreshRow(GetRowCount());
		}

	JPoint cell;
	JXNamedTreeListWidget::NodePart part;
	if (GetNode(pt, &cell, &part))
		{
		itsCurrentDndHereIndex = ClosestSelection(pt, cell.y, part);
		TableRefreshRow(itsCurrentDndHereIndex);
		}
	else
		{
		itsCurrentDndHereIndex = ClosestSelection(pt, 0, part);
		if (itsCurrentDndHereIndex == 0)
			{
			JSize count = GetRowCount();
			if (count > 0)
				{
				TableRefreshRow(count);
				}
			}
		}
}

/******************************************************************************
 HandleDNDLeave 

 ******************************************************************************/

void
GMailboxTreeWidget::HandleDNDLeave()
{
	JIndex oldIndex 		= itsCurrentDndHereIndex;
	itsCurrentDndHereIndex 	= 0;
	if (oldIndex != 0)
		{
		TableRefreshRow(oldIndex);
		}
	else if (itsOutsideRoot)
		{
		TableRefreshRow(GetRowCount());
		}
	itsDraggingFiles 		= kFalse;
	itsOutsideRoot			= kFalse;
}

/******************************************************************************
 HandleDNDDrop 

 ******************************************************************************/

void
GMailboxTreeWidget::HandleDNDDrop
	(
	const JPoint& 		pt,
	const JArray<Atom>& typeList,
	const Atom 			action,
	const Time			time,
	const JXWidget* 	source
	)
{
	JBoolean dropOnSelf = JI2B(source == this);

	Atom realAction = action;
	JXDNDManager* dndMgr  = GetDNDManager();
	if (action == dndMgr->GetDNDActionAskXAtom())
		{
		JArray<Atom> actionList;
		JPtrArray<JString> descriptionList;
		descriptionList.SetCleanUpAction(JPtrArrayT::kDeleteAllAsObjects);
		if (!dndMgr->GetAskActions(&actionList, &descriptionList))
			{
			realAction = dndMgr->GetDNDActionMoveXAtom();;
			}
		else if (!dndMgr->ChooseDropAction(actionList, descriptionList,
										   &realAction))
			{
			return;
			}
		}
	JPoint cell;
	JIndex oldIndex = itsCurrentDndHereIndex;
	itsCurrentDndHereIndex = 0;
	if (oldIndex != 0)
		{
		TableRefreshRow(oldIndex);
		}
//	else if (!dropOnSelf)
//		{
//		return;
//		}
	if (GetNamedTreeList()->GetElementCount() < oldIndex)
		{
		return;
		}

	if (source != this)
		{
		dropOnSelf = kFalse;
		}
	
	if (dropOnSelf)
		{
		JTableSelection& s = GetTableSelection();
		JTableSelectionIterator iter(&s);
		if (itsOutsideRoot)
			{
			JTreeNode* base = itsTree->GetRoot();
			JTreeNode* beforenode = NULL;
			if (oldIndex != 0)
				{
				beforenode = GetNamedTreeList()->GetNode(oldIndex);
				}
			while (iter.Next(&cell))
				{
				JTreeNode* jnode = GetNamedTreeList()->GetNode(cell.y);
				GMailFileTreeNode* dnode = 
					dynamic_cast(GMailFileTreeNode*, jnode);
				assert(dnode != NULL);
				if (oldIndex == 0)
					{
					if (dnode->GetDepth() == 1)
						{
						base->Append(jnode);
						}
					else
						{
						if (dnode->IsOpenable())
							{
							AddDirectory(dnode->GetFullPathAndName());
							}
						else
							{
							AddFile(dnode->GetFullPathAndName());
							}
						}
					}
				else
					{
					if (beforenode != jnode)
						{
						if (dnode->GetDepth() == 1)
							{
							base->InsertBefore(beforenode, jnode);
							}
						else
							{
							JUNIXDirEntry* entry = new JUNIXDirEntry(dnode->GetFullPathAndName());
							assert(entry != NULL);
							GMailFileTreeNode* newnode = 
								new GMailFileTreeNode(itsTree, entry, NULL, 
									entry->GetName(),dnode->IsOpenable());
							assert(newnode != NULL);
							base->InsertBefore(beforenode, newnode);
							}
						}
					}
				}
			}
		else
			{
			JTreeNode* node = GetNamedTreeList()->GetNode(oldIndex);
			GMailFileTreeNode* mnode = 
				dynamic_cast(GMailFileTreeNode*, node);
			assert(mnode != NULL);
			if (mnode->IsOpenable())
				{
				JString dir = mnode->GetFullPathAndName();
				JAppendDirSeparator(&dir);
				JBoolean dropsuccess = kTrue;
				while (iter.Next(&cell))
					{
					JTreeNode* jnode = GetNamedTreeList()->GetNode(cell.y);
					GMailFileTreeNode* dnode = 
						dynamic_cast(GMailFileTreeNode*, jnode);
					assert(dnode != NULL);
					JString fullname = dnode->GetFullPathAndName();
					JString newname;
					if (fullname != "/")
						{
						if (fullname.EndsWith("/"))
							{
							fullname.RemoveSubstring(fullname.GetLength(), fullname.GetLength());
							}
						JString path;
						JString name;
						JSplitPathAndName(fullname, &path, &name);
						newname = dir + name;
						if (newname != fullname)
							{
							JError err = JRenameFile(fullname, newname);
							if (err.OK())
								{
								delete dnode;
								}
							else
								{
								dropsuccess = kFalse;
								}
							}
						}
					}
				if (!dropsuccess)
					{
					JGetUserNotification()->ReportError("Some of the files could not be moved.");
					}
				}
			else
				{
				cout << "This shouldn't have happened!" << endl;
				}
			}
		}
	else
		{
		JString mailfile;
		JBoolean mailboxOk 		= kTrue;
		JBoolean newMail		= kFalse;
		JBoolean createAndAdd	= kFalse;
		if (oldIndex == 0)
			{
			newMail 		= kTrue;
			createAndAdd	= kTrue;
			}
		else
			{
			JTreeNode* node = GetNamedTreeList()->GetNode(oldIndex);
			GMailFileTreeNode* mnode = 
				dynamic_cast(GMailFileTreeNode*, node);
			assert(mnode != NULL);
			mailfile = mnode->GetFullPathAndName();
			if (node->IsOpenable())
				{
				newMail = kTrue;
				JAppendDirSeparator(&mailfile);
				}
			}
		
		if (newMail)
			{
			mailfile += "Untitled";
			JString newfile;
			if (JXGetChooseSaveFile()->SaveFile("Select a mailbox name", "", mailfile, &newfile))
				{
				mailfile = newfile;
				if (createAndAdd)
					{
					GMGetApplication()->NewMailbox(mailfile, kFalse);
					AddFile(mailfile);
					}
				}
			else
				{
				mailboxOk = kFalse;
				}
			}

		unsigned char* data = NULL;
		JSize dataLength;
		Atom returnType;
		JXSelectionManager* selManager = GetSelectionManager();
		JXSelectionManager::DeleteMethod delMethod;
		const Atom dndName = (GetDNDManager())->GetDNDSelectionName();
		if (mailboxOk && selManager->GetSelectionData(dndName, time, GetWindow(), itsMessageXAtom,
										 &returnType, &data, &dataLength, &delMethod))
			{
			jistrstream(selis, reinterpret_cast<char*>(data), dataLength);
			JPtrArray<GMessageHeader> list;
			JString mbox;
			selis >> mbox;
			int count;
			selis >> count;
			for (int index = 1; index <= count; index++)
				{
				GMessageHeader* header = new GMessageHeader();
				assert(header != NULL);
				selis >> *header;
				list.Append(header);
				}
			GBlockUntilFileUnlocked(mailfile);
			if (!GLockFile(mailfile))
				{
				selManager->DeleteSelectionData(&data, delMethod);
				return;
				}
			JString tempname = mailfile + ".tmp";
			JBoolean first 	= kTrue;
			JBoolean ok 	= kTrue;
			mode_t perms, perms2;			

			JError err = JGetPermissions(mailfile, &perms);
			if (!err.OK())
				{
				perms = 0600;
				}
			err = JGetPermissions(mbox, &perms2);
			if (!err.OK())
				{
				perms2 = 0600;
				}
			fstream is(mailfile, ios::in|ios::out, perms);
			fstream mboxis(mbox, ios::in|ios::out, perms2);
			ofstream os(tempname);
			ok = JConvertToBoolean(os.good());
			if (!ok)
				{
				tempname = JGetTempFileName();
				os.close();
				os.open(tempname);
				}
			
			JSize lcount = list.GetElementCount();
			JSize index;
			JString temp;
			JUNIXDirEntry entry(mailfile);
			JSize size = entry.GetSize();
			temp.Read(is, size);
//			JReadAll(is, &temp);
			if ((size != 0) && !temp.EndsWith("\n\n"))
				{
				temp.Append("\n\n");
				}
			temp.Print(os);
			for (index = 1; index <= lcount; index++)
				{
				GMessageHeader* header = list.NthElement(index);
				GSaveMessage(mboxis, os, header, kTrue, kFalse);
				}
			is.close();
			os.close();
			mboxis.close();
				
			JString cmd;
			if (ok)
				{
				cmd = "mv -f \"" + tempname + "\" \"" + mailfile + "\"";
				}
			else
				{
				cmd = "cp -f \"" + tempname + "\" \"" + mailfile + "\"";
				}
			JExecute(cmd, NULL);
			if (!ok)
				{
				JRemoveFile(tempname);
				}
			GUnlockFile(mailfile);
			GUnlockFile(mbox);
			selManager->DeleteSelectionData(&data, delMethod);
			list.DeleteAll();
			if (realAction == dndMgr->GetDNDActionMoveXAtom())
				{
				selManager->SendDeleteSelectionRequest(dndName, time, GetWindow());
				}
			}
		}
	itsDraggingFiles 	= kFalse;
	itsOutsideRoot		= kFalse;
}

/******************************************************************************
 WillAcceptDrop 

 ******************************************************************************/

JBoolean
GMailboxTreeWidget::WillAcceptDrop
	(
	const JArray<Atom>& typeList, 
	Atom*				action,
	const Time			time,
	const JXWidget*		source
	)
{
	JBoolean found 				= kFalse;
	const JSize typeCount 		= typeList.GetElementCount();
	for (JSize i=1; i<=typeCount; i++)
		{
		Atom type 				= typeList.GetElement(i);
		if (type == itsMessageXAtom)
			{
			found 				= kTrue;
			itsDraggingFiles	= kFalse;
			}
		else if (type == itsMailboxXAtom && source == this)
			{
			found 				= kTrue;
			itsDraggingFiles	= kTrue;
			}
		}
	return found;
}

/******************************************************************************
 ConvertSelection 

 ******************************************************************************/

JBoolean 
GMailboxTreeWidget::ConvertSelection
	(
	const Atom 		name, 
	const Atom 		requestType,
	Atom* 			returnType,
	unsigned char**	data,
	JSize* 			dataLength, 
	JSize* 			bitsPerBlock
	)
{
/*	*bitsPerBlock = 8;
	ostrstream os;
	
	JTableSelection& selection = GetTableSelection();
	JTableSelectionIterator* iter = 
		new JTableSelectionIterator(&selection);

	JPoint cell;
	if (itsDraggingBranch)
		{
		JSize count = 0;
		while(iter->Next(&cell))
			{
			JTreeNode* jnode = GetNamedTreeList()->GetNode(cell.y);
			count += jnode->GetChildCount();
			}
		os << count;
		iter->MoveTo(kIteratorStartAtBeginning, cell);
		while(iter->Next(&cell))
			{
			JTreeNode* jnode = GetNamedTreeList()->GetNode(cell.y);
			JSize count = jnode->GetChildCount();
			for (JSize j = 1; j <= count; j++)
				{
				JTreeNode* child = jnode->GetChild(j);
				GSimpleFileTreeNode* node = dynamic_cast(GSimpleFileTreeNode*, child);
				assert(node != NULL);
				node->WriteFileName(os);
				}
			
			}
		}
	else
		{
		os << selection.GetSelectedCellCount();
		while(iter->Next(&cell))
			{
			JTreeNode* jnode = GetNamedTreeList()->GetNode(cell.y);
			GMailboxTreeNode* node = dynamic_cast(GMailboxTreeNode*, jnode);
			assert(node != NULL);
			node->WriteFileName(os);
			}
		}
		
	os << ends;
	delete iter;
	*dataLength = strlen(os.str());
	*data = new unsigned char[ *dataLength ];
	assert (*data != NULL);
	memcpy(*data, os.str(), *dataLength);
	return kTrue;
*/
	return kFalse;
}

/******************************************************************************
 AddFile 

 ******************************************************************************/

void
GMailboxTreeWidget::AddFile
	(
	const JString& path, 
	const JString& file
	)
{
	AddFile(JCombinePathAndName(path, file));
}

/******************************************************************************
 AddFile 

 ******************************************************************************/

void
GMailboxTreeWidget::AddFile
	(
	const JCharacter* fullname 
	)
{
	JTreeNode* base = itsTree->GetRoot();
	JNamedTreeNode* parent = 
		dynamic_cast(JNamedTreeNode*, base);
	assert(parent != NULL);
	JUNIXDirEntry* entry = new JUNIXDirEntry(fullname);
	assert(entry != NULL);
	JString pattern("^From[[:space:]]+.*.{3}[[:space:]]+.{3}[[:space:]]+[[:digit:]]+[[:space:]]+([[:digit:]]+:)+[[:digit:]]+[[:space:]]+(...[[:space:]])?[[:digit:]]{4}");
	if (MatchesCookie(pattern, *entry))
		{
		GMailFileTreeNode* node = 
			new GMailFileTreeNode(itsTree, entry, entry->GetName(),kFalse);
		assert(node != NULL);
		parent->Append(node);
		}
	ClearIncrementalSearchBuffer();
}


/******************************************************************************
 AddDirectory 

 ******************************************************************************/

void
GMailboxTreeWidget::AddDirectory
	(
	const JCharacter* path
	)
{
	JTreeNode* base = itsTree->GetRoot();
	JNamedTreeNode* parent = 
		dynamic_cast(JNamedTreeNode*, base);
	assert(parent != NULL);
	JUNIXDirEntry* entry = new JUNIXDirEntry(path);
	assert(entry != NULL);
	GMailFileTreeNode* node = 
		new GMailFileTreeNode(itsTree, entry, entry->GetName(),kTrue);
	assert(node != NULL); 
	parent->Append(node);
	ClearIncrementalSearchBuffer();
}

/******************************************************************************
 GetImage

******************************************************************************/

JBoolean
GMailboxTreeWidget::GetImage
	(
	const JIndex 	index,
	const JXImage** image
	)
	const
{
	const JTreeNode* jnode = GetNamedTreeList()->GetNode(index);
	if (jnode->IsOpenable())
		{
		if (index == itsCurrentDndHereIndex && !itsOutsideRoot)
			{
			*image = itsSelectedFolderIcon;
			return kTrue;
			}
		*image = itsFolderIcon;
		return kTrue;
		}
	if (index == itsCurrentDndHereIndex && !itsOutsideRoot)
		{
		*image = itsSelectedMailIcon;
		return kTrue;
		}
	GMailFileTreeNode* node = 
		dynamic_cast(GMailFileTreeNode*, jnode);
	if (GFileLocked(node->GetFullPathAndName()))
		{
		*image = itsLockedMailIcon;
		return kTrue;
		}
	*image = itsMailIcon;
	return kTrue;
}

/******************************************************************************
 ReadPrefs (public)

 ******************************************************************************/

void
GMailboxTreeWidget::ReadPrefs
	(
	istream& input
	)
{
	JCoordinate id;
	input >> id;
	assert(id <= kCurrentPrefsVersion);
	JSize count;
	input >> count;
	for (JSize i = 1; i <= count; i++)
		{
		JString dir;
		input >> dir;
		if (JDirectoryExists(dir))
			{
			AddDirectory(dir);
			}
		else if (JFileExists(dir))
			{
			AddFile(dir);
			}
		}
	input >> count;
	for (JSize i = 1; i <= count; i++)
		{
		JString dir;
		input >> dir;
		JBoolean found = kFalse;
		JSize count = GetNamedTreeList()->GetElementCount();
		JIndex index = 1;
		while (!found && (index <= count))
			{
			JTreeNode* jnode = GetNamedTreeList()->GetNode(index);
			GMailFileTreeNode* node = dynamic_cast(GMailFileTreeNode*, jnode);
			assert(node != NULL);
			if (node->GetFullPathAndName() == dir)
				{
				found = kTrue;
				if (jnode->IsOpenable())
					{
					GetNamedTreeList()->Open(index);
					}
				}
			index ++;
			}
		}
}

/******************************************************************************
 WritePrefs (public)

 ******************************************************************************/

void
GMailboxTreeWidget::WritePrefs
	(
	ostream& output
	)
	const
{
	output << kCurrentPrefsVersion << ' ';
	JTreeNode* base = itsTree->GetRoot();
	JSize count = base->GetChildCount();
	output << count << ' ';
	for (JSize i = 1; i <= count; i++)
		{
		JTreeNode* child = base->GetChild(i);
		GMailFileTreeNode* node = 
		dynamic_cast(GMailFileTreeNode*, child);
		assert(node != NULL);
		output << node->GetFullPathAndName() << ' ';
		}
	count = GetNamedTreeList()->GetElementCount();
	JSize realcount = 0;
	for (JSize i = 1; i <= count; i++)
		{
		if (GetNamedTreeList()->IsOpen(i))
			{
			realcount++;
			}
		}
	output << realcount << ' ';
	for (JSize i = 1; i <= count; i++)
		{
		if (GetNamedTreeList()->IsOpen(i))
			{
			const JTreeNode* child = GetNamedTreeList()->GetNode(i);
			GMailFileTreeNode* node = 
			dynamic_cast(GMailFileTreeNode*, child);
			assert(node != NULL);
			output << node->GetFullPathAndName() << ' ';
			}
		}
	
}

/******************************************************************************
 Update (public)

 ******************************************************************************/

void
GMailboxTreeWidget::Update()
{
	JTreeNode* base  = itsTree->GetRoot();
	JSize count 	 = base->GetChildCount();
	JBoolean changed = kFalse;
	for (JSize i = 1; i <= count; i++)
		{
		JTreeNode* child = base->GetChild(i);
		if (GetNamedTreeList()->IsOpen(child))
			{
			GMailFileTreeNode* node = 
			dynamic_cast(GMailFileTreeNode*, child);
			assert(node != NULL);
			changed = node->UpdateDir(GetNamedTreeList());
			}
		}
	if (changed)
		{
		TableRefresh();
		}
}

/******************************************************************************
 OpenMailbox (private)

 ******************************************************************************/

void
GMailboxTreeWidget::OpenMailbox
	(
	const JIndex index
	)
{
	JTreeNode* node = GetNamedTreeList()->GetNode(index);
	if (!node->IsOpenable())
		{
		GMailFileTreeNode* mnode = 
			dynamic_cast(GMailFileTreeNode*, node);
		assert(mnode != NULL);
			
		GMGetApplication()->OpenMailbox(mnode->GetFullPathAndName());
		
		}
	ClearIncrementalSearchBuffer();
}

/******************************************************************************
ClosestSelection (private)

 ******************************************************************************/

JIndex
GMailboxTreeWidget::ClosestSelection
	(
	const JPoint& 							pt,
	const JIndex  							index,
	const JXNamedTreeListWidget::NodePart 	part
	)
{
	JBoolean inNode = kFalse;
	if ((part == JXNamedTreeListWidget::kInText) ||
		(part == JXNamedTreeListWidget::kInImage))
		{
		inNode = kTrue;
		}
	itsOutsideRoot = kFalse;
	if (index == 0)
		{
		if (itsDraggingFiles)
			{
			itsOutsideRoot = kTrue;
			return 0;
			}
		return LastWritableTopLevel();
		}
	JTreeNode* jnode = GetNamedTreeList()->GetNode(index);
	GMailFileTreeNode* node = 
		dynamic_cast(GMailFileTreeNode*, jnode);
	if (itsDraggingFiles)
		{
		if (node->GetDepth() > 1)
			{
			if (inNode && node->IsOpenable() && NodeIsWritable(node))
				{
				return index;
				}
			JIndex tindex = WritableParent(node);
			if (tindex == 0)
				{
				itsOutsideRoot = kTrue;
				}
			return tindex;
			}
		if (inNode)
			{
			if (node->IsOpenable() && NodeIsWritable(node))
				{
				return index;
				}
			itsOutsideRoot = kTrue;
			return index;
			}
		itsOutsideRoot = kTrue;
		return index;
		}
	if (GFileLocked(node->GetFullPathAndName()))
		{
		return WritableParent(node);
		}
	if (!inNode)
		{
		if (node->GetDepth() > 1)
			{
			return WritableParent(node);
			}
		if (NodeIsWritable(node))
			{
			return index;
			}
		return 0;
		}
	if (NodeIsWritable(node))
		{
		return index;
		}
	return 0;
}

/******************************************************************************
 LastWritableTopLevel (private)

 ******************************************************************************/

JIndex
GMailboxTreeWidget::LastWritableTopLevel()
{
	JTreeNode* base = itsTree->GetRoot();
	JSize count = base->GetChildCount();
	if (count == 0)
		{
		return 0;
		}
	for (JSize i = count; i >=1 ; i--)
		{
		JTreeNode* jnode = base->GetChild(i);
		GMailFileTreeNode* node = 
			dynamic_cast(GMailFileTreeNode*, jnode);
		if (NodeIsWritable(node))
			{
			JIndex findex;
			if (GetNamedTreeList()->FindNode(node, &findex))
				{
				return findex;
				}
			}
		}
	return 0;
}

/******************************************************************************
 WritableParent (private)

 ******************************************************************************/

JIndex
GMailboxTreeWidget::WritableParent
	(
	GMailFileTreeNode* node
	)
{
	if (node->GetDepth() == 1)
		{
		return 0;
		}
	JTreeNode* jparent = node->GetParent();
	GMailFileTreeNode* parent = 
		dynamic_cast(GMailFileTreeNode*, jparent);
	if (JDirectoryWritable(parent->GetFullPathAndName()))
		{
			JIndex findex;
			if (GetNamedTreeList()->FindNode(parent, &findex))
				{
				return findex;
				}
			return 0;
		}
	else
		{
		return WritableParent(parent);
		}
}

/******************************************************************************
 NodeIsWritable (private)

 ******************************************************************************/

JBoolean
GMailboxTreeWidget::NodeIsWritable
	(
	GMailFileTreeNode* node
	)
{
	if (node->IsOpenable() && JDirectoryWritable(node->GetFullPathAndName()))
		{
		return kTrue;
		}
	if (!node->IsOpenable() && JFileWritable(node->GetFullPathAndName()))
		{
		return kTrue;
		}
	return kFalse;
}

/******************************************************************************
 OkToDND (private)

 ******************************************************************************/

JBoolean
GMailboxTreeWidget::OkToDND()
{
	return kTrue;
}

/******************************************************************************
 NewNameOK (virtual protected)

 ******************************************************************************/

JBoolean
GMailboxTreeWidget::ExtractInputData
	(
	const JPoint& cell
	)
{
	JXInputField* input;
	JBoolean ok = GetXInputField(&input);
	assert(ok);
	JString newName = input->GetText();
	JIndex index = cell.y;
	JTreeNode* jnode = GetNamedTreeList()->GetNode(index);
	GMailFileTreeNode* node = 
		dynamic_cast(GMailFileTreeNode*, jnode);
	assert(node != NULL);
	if (newName == node->GetName())
		{
		return kTrue;
		}
	JString fullname = node->GetFullPathAndName();
	if (fullname == "/")
		{
		return kFalse;
		}
	if (fullname.EndsWith("/"))
		{
		fullname.RemoveSubstring(fullname.GetLength(), fullname.GetLength());
		}
	JString path;
	JString name;
	JSplitPathAndName(fullname, &path, &name);
	JAppendDirSeparator(&path);
	JString newFullName = path + newName;
	if (fullname == newFullName)
		{
		return kTrue;
		}
	if (newFullName.EndsWith("/"))
		{
		newFullName.RemoveSubstring(newFullName.GetLength(), newFullName.GetLength());
		}
	JError err = JRenameFile(fullname, newFullName);
	if (err.OK())
		{
		node->SetNameAndUpdate(newName);
		if (node->GetDepth() > 1)
			{
			JTreeNode* jparent = node->GetParent();
			GMailFileTreeNode* parent = 
				dynamic_cast(GMailFileTreeNode*, jparent);
			parent->Remove(node);
			parent->InsertSorted(node);
			}
		return kTrue;
		}
	else
		{
		err.ReportError();
		}
	return kFalse;
}

/******************************************************************************
 DeleteSelected (private)

 ******************************************************************************/

void
GMailboxTreeWidget::DeleteSelected()
{
	JTableSelection& s = GetTableSelection();
	JTableSelectionIterator iter(&s);
	JPoint cell;
	JTreeNode* base = itsTree->GetRoot();
	while (iter.Next(&cell))
		{
		JTreeNode* node = GetNamedTreeList()->GetNode(cell.y);
		base->Remove(node);
		delete node;
		}
	ClearIncrementalSearchBuffer();
}

/******************************************************************************
 IsEditable (virtual)

 ******************************************************************************/

JBoolean
GMailboxTreeWidget::IsEditable
	(
	const JPoint& cell
	)
	const
{
	const JTreeNode* jnode = GetNamedTreeList()->GetNode(cell.y);
	JNamedTreeNode* nnode =
		dynamic_cast(JNamedTreeNode*, jnode);
	assert(nnode != NULL);
	if (cell.x == 2)
		{
		return kTrue;
		}
	return kFalse;
	
}

/******************************************************************************
 CheckSelectionForMenus (private)

 ******************************************************************************/

void
GMailboxTreeWidget::CheckSelectionForMenus
	(
	JBoolean* okDir,
	JBoolean* okFile,
	JBoolean* unLock
	)
{
	JTableSelection& s = GetTableSelection();
	JTableSelectionIterator iter(&s);
	JPoint cell;
	*okDir 	= kTrue;
	*okFile	= kTrue;
	*unLock	= kFalse;
	while (iter.Next(&cell))
		{
		JTreeNode* node = GetNamedTreeList()->GetNode(cell.y);
		if (node->GetDepth() != 1)
			{
			*okDir 	= kFalse;
			}
		if (node->IsOpenable())
			{
			*okFile	= kFalse;
			}
		GMailFileTreeNode* mnode = 
			dynamic_cast(GMailFileTreeNode*, node);
		if (GFileLocked(mnode->GetFullPathAndName()))
			{
			*unLock = kTrue;
			}
		}
}

/******************************************************************************
 AddDefaultButtcons (public)

 ******************************************************************************/

void
GMailboxTreeWidget::AddDefaultButtcons
	(
	JXToolBar* toolbar
	)
{
	toolbar->AppendButton(itsMailboxMenu, kNewMBoxCmd);
	toolbar->AppendButton(itsMailboxMenu, kNewDirCmd);
	toolbar->NewGroup();
}
