/******************************************************************************
 GNBTreeWidget.cc

	<Description>

	BASE CLASS = public JXNamedTreeListWidget

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

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

#include <GNBTreeWidget.h>
#include <GNBTreeDir.h>
#include <GNBCategoryNode.h>
#include <GNBNoteNode.h>
#include <GNBToDoNode.h>
#include <GNBGlobals.h>
#include "GNBApp.h"
#include "GNBTrashDir.h"

#include "GNBFolderIcon.xpm"
#include <GNBTrashIcon.xpm>
#include <tododone.xpm>
#include <markdone.xpm>
#include <todonotedone.xpm>
#include <todourgent.xpm>

#include <JTree.h>
#include <JNamedTreeList.h>
#include <JNamedTreeNode.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 <JXDisplay.h>
#include <JXColormap.h>
#include <JXImage.h>
#include <JXInputField.h>

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

#include <jXCSFIcons.h>

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

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

static const JCharacter* kGNBMenuTitleStr = "Notebook";
static const JCharacter* kGNBMenuStr = 
	"Edit tool bar... %i \"EditToolBar::Notebook\""
	"%l|New note %k Meta-N %i \"NewNote::Notebook\""
	"| New category %k Meta-Shift-N %i \"NewCategory::Notebook\""
	"|New to-do %k Meta-T %i \"NewToDo::Notebook\" "
	"| Add note %k Meta-Shift-T  %i \"AddNote::Notebook\""
	"| Remove note %i \"RemoveNote::Notebook\""
	"| Toggle Urgency %k Meta-U %i \"ToggleUrgency::Notebook\""
	"| Mark selected as done %k Meta-M %i \"MarkDone::Notebook\""
	"| Mark selected as not done %k Meta-Shift-M %i \"MarkUnDone::Notebook\""
	"%l| Export selected notes... %k Meta-U %i \"ExportSelected::Notebook\""
	"| Print selected notes... %k Meta-U %i \"PrintSelected::Notebook\""
	"%l|Remove selected %k Meta-R %i \"RemoveSelected::Notebook\""
	"|View discards  %i \"ViewDiscards::Notebook\""
	"| Flush discards %i \"FlushDiscards::Notebook\""
	"%l|Quit %k Meta-Q %i \"Quit::Notebook\"";

enum
{
	kEditToolBarCmd = 1,
	kNewNoteCmd,
	kNewCategoryCmd,
	kNewToDoCmd,
	kAddNoteCmd,
	kRemoveNoteCmd,
	kToggleUrgentCmd,
	kMarkDoneCmd,
	kMarkUnDoneCmd,
	kExportSelCmd,
	kPrintSelCmd,
	kRemoveCmd,
	kViewDiscardsCmd,
	kFlushCmd,
	kQuitCmd
};

static const JIndex kGNBMainTreePrefsIndex = 1;

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

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

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

	widget->JXTreeListWidgetX();

	widget->itsToolBar->LoadPrefs();

	if (widget->itsToolBar->IsEmpty())
		{
		widget->itsToolBar->AppendButton(widget->itsNBMenu, kNewNoteCmd);
		widget->itsToolBar->AppendButton(widget->itsNBMenu, kNewCategoryCmd);
		widget->itsToolBar->AppendButton(widget->itsNBMenu, kNewToDoCmd);
		widget->itsToolBar->AppendButton(widget->itsNBMenu, kAddNoteCmd);
		widget->itsToolBar->AppendButton(widget->itsNBMenu, kToggleUrgentCmd);
		widget->itsToolBar->NewGroup();
		widget->itsToolBar->AppendButton(widget->itsNBMenu, kViewDiscardsCmd);
		}
		
	widget->ReadSetup();

	return widget;	
}

GNBTreeWidget::GNBTreeWidget
	(
	JTree*				tree,
	JNamedTreeList* 	treeList, 
	JXMenuBar* 			menuBar,
	JXToolBar* 			toolBar,
	JXScrollbarSet* 	scrollbarSet, 
	JXContainer* 		enclosure,
	const HSizingOption	hSizing, 
	const VSizingOption vSizing,
	const JCoordinate 	x, 
	const JCoordinate 	y,
	const JCoordinate 	w, 
	const JCoordinate 	h
	)
	:
   GNBTreeWidgetBase(kGNBMainTreePrefsIndex, tree, treeList, 
   					  scrollbarSet,	enclosure, hSizing, vSizing, x, y, w, h),
   itsToolBar(toolBar)
{
	itsNBMenu = menuBar->AppendTextMenu(kGNBMenuTitleStr);
	itsNBMenu->SetMenuItems(kGNBMenuStr);
	itsNBMenu->SetUpdateAction(JXMenu::kDisableAll);
	ListenTo(itsNBMenu);

	JXImage* image = new JXImage(GetDisplay(), GetColormap(), JXGetPlainFileIcon());
	assert(image != NULL);
	itsNBMenu->SetItemImage(kNewNoteCmd, image, kTrue);

	image = new JXImage(GetDisplay(), GetColormap(), JXPM(GNBFolderIcon));
	assert(image != NULL);
	itsNBMenu->SetItemImage(kNewCategoryCmd, image, kTrue);

	image = new JXImage(GetDisplay(), GetColormap(), JXPM(tododone));
	assert(image != NULL);
	itsNBMenu->SetItemImage(kNewToDoCmd, image, kTrue);

	image = new JXImage(GetDisplay(), GetColormap(), JXPM(todonotedone));
	assert(image != NULL);
	itsNBMenu->SetItemImage(kAddNoteCmd, image, kTrue);

	image = new JXImage(GetDisplay(), GetColormap(), JXPM(todourgent));
	assert(image != NULL);
	itsNBMenu->SetItemImage(kToggleUrgentCmd, image, kTrue);

	image = new JXImage(GetDisplay(), GetColormap(), JXPM(markdone));
	assert(image != NULL);
	itsNBMenu->SetItemImage(kMarkDoneCmd, image, kTrue);

	image = new JXImage(GetDisplay(), GetColormap(), JXPM(kfm_trash));
	assert(image != NULL);
	itsNBMenu->SetItemImage(kViewDiscardsCmd, image, kTrue);

}

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

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

GNBTreeWidget::~GNBTreeWidget()
{
}

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


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

void
GNBTreeWidget::Receive
	(
	JBroadcaster*	sender,
	const Message&	message
	)
{
	if (sender == itsNBMenu && message.Is(JXMenu::kItemSelected))
		{
		 const JXMenu::ItemSelected* selection =
			dynamic_cast(const JXMenu::ItemSelected*, &message);
		assert( selection != NULL );
		HandleNBMenu(selection->GetIndex());
		}
	else if (sender == itsNBMenu && message.Is(JXMenu::kNeedsUpdate))
		{
		UpdateNBMenu();
		}
	else
		{
		GNBTreeWidgetBase::Receive(sender, message);
		}
}

/******************************************************************************
 UpdateNBMenu 


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

void
GNBTreeWidget::UpdateNBMenu()
{
	JTableSelection& s = GetTableSelection();
	JSize count = s.GetSelectedCellCount();
	GNBTreeWidgetBase::SelectionType seltype = GetSelectionType();
	if (seltype == GNBTreeWidgetBase::kNoneSelected)
		{
		itsNBMenu->EnableItem(kNewNoteCmd);
		itsNBMenu->EnableItem(kNewToDoCmd);
		itsNBMenu->EnableItem(kNewCategoryCmd);
		JPoint cell;
		if (GetEditedCell(&cell))
			{
			JTreeNode* jnode = GetTreeList()->GetNode(cell.y);
			GNBBaseNode* bnode = dynamic_cast(GNBBaseNode*, jnode);
			assert(bnode != NULL);
			GNBBaseNode::Type type = bnode->GetType();
			if (type == GNBBaseNode::kToDoNode)
				{
				itsNBMenu->EnableItem(kToggleUrgentCmd);
				itsNBMenu->EnableItem(kMarkDoneCmd);
				itsNBMenu->EnableItem(kMarkUnDoneCmd);
				GNBToDoNode* tdnode = dynamic_cast(GNBToDoNode*, jnode);
				assert(tdnode != NULL);
				if (!tdnode->HasNote())
					{
					itsNBMenu->EnableItem(kAddNoteCmd);
					}
				else
					{
					itsNBMenu->EnableItem(kRemoveNoteCmd);
					}
				}
			itsNBMenu->EnableItem(kRemoveCmd);
			}
		}
	else if (seltype == GNBTreeWidgetBase::kCategoriesSelected)
		{
		if (count == 1)
			{
			itsNBMenu->EnableItem(kNewNoteCmd);
			itsNBMenu->EnableItem(kNewToDoCmd);
			itsNBMenu->EnableItem(kNewCategoryCmd);
			}
		itsNBMenu->EnableItem(kRemoveCmd);
		}
	else
		{
		itsNBMenu->EnableItem(kNewNoteCmd);
		itsNBMenu->EnableItem(kNewToDoCmd);
		itsNBMenu->EnableItem(kNewCategoryCmd);
		itsNBMenu->EnableItem(kRemoveCmd);
		itsNBMenu->EnableItem(kExportSelCmd);
		itsNBMenu->EnableItem(kPrintSelCmd);

		if (seltype == GNBTreeWidgetBase::kToDosSelected)
			{
			itsNBMenu->EnableItem(kToggleUrgentCmd);
			itsNBMenu->EnableItem(kAddNoteCmd);
			itsNBMenu->EnableItem(kRemoveNoteCmd);
			itsNBMenu->EnableItem(kMarkDoneCmd);
			itsNBMenu->EnableItem(kMarkUnDoneCmd);
			}
		else if (seltype == GNBTreeWidgetBase::kItemsSelected)
			{
			JTableSelectionIterator iter(&s);
			JPoint cell;
			JBoolean ok = kTrue;
			while (iter.Next(&cell) && ok)
				{
				JTreeNode* iternode = GetTreeList()->GetNode(cell.y);
				GNBBaseNode* bnode = dynamic_cast(GNBBaseNode*, iternode);
				assert(bnode != NULL);
				GNBBaseNode::Type type = bnode->GetType();
				if (type != GNBBaseNode::kToDoNode)
					{
					ok = kFalse;
					}
				}
			if (ok)
				{
				itsNBMenu->EnableItem(kToggleUrgentCmd);
				itsNBMenu->EnableItem(kAddNoteCmd);
				itsNBMenu->EnableItem(kRemoveNoteCmd);
				}
			}
		}

	itsNBMenu->EnableItem(kViewDiscardsCmd);
	itsNBMenu->EnableItem(kFlushCmd);
	itsNBMenu->EnableItem(kQuitCmd);
	itsNBMenu->EnableItem(kEditToolBarCmd);
}

/******************************************************************************
 HandleNBMenu 


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

void
GNBTreeWidget::HandleNBMenu
	(
	const JIndex index
	)
{
	JTableSelection& s 		= GetTableSelection();
	JPoint cell;
	JBoolean ok 			= s.GetLastSelectedCell(&cell);
	if (!ok)
		{
		ok = GetEditedCell(&cell);
		}
	JTreeNode* jnode 		= NULL;
	JNamedTreeNode* parent	= NULL;
	JTreeNode* jsibling 	= NULL;
	JBoolean afterSibling 	= kFalse;	
	if (ok)
		{
		jnode = GetTreeList()->GetNode(cell.y);
		assert(jnode != NULL);
		if (jnode->IsOpenable())
			{
			parent = dynamic_cast(JNamedTreeNode*, jnode);
			assert(parent != NULL);
			}
		else
			{
			afterSibling 	= kTrue;
			parent			= dynamic_cast(JNamedTreeNode*, jnode->GetParent());
			jsibling		= jnode;
			}
		}
	else
		{
		parent = dynamic_cast(JNamedTreeNode*, GetTreeList()->GetTree()->GetRoot());
		assert(parent != NULL);
		}
	if (index == kEditToolBarCmd)
		{
		itsToolBar->Edit();
		}
	else if (index == kNewNoteCmd)
		{
		JFAID_t id = GNBGetApplication()->NewNote();
		GNBNoteNode* node = new GNBNoteNode(GetTreeList()->GetTree(), "", id);
		PlaceNewNode(parent, node, jsibling, afterSibling);
		}
	else if (index == kNewCategoryCmd)
		{
		GNBCategoryNode* node = new GNBCategoryNode(GetTreeList()->GetTree(), "");
		assert(node != NULL);
		PlaceNewNode(parent, node, jsibling, afterSibling, kTrue);
		}
	else if (index == kNewToDoCmd)
		{
		GNBToDoNode* node = new GNBToDoNode(GetTreeList()->GetTree(), "");
		assert(node != NULL);
		PlaceNewNode(parent, node, jsibling, afterSibling, kTrue);
		}
	else if (index == kAddNoteCmd)
		{
		if (IsEditing())
			{
			GNBToDoNode* tdnode = dynamic_cast(GNBToDoNode*, jnode);
			assert(tdnode != NULL);
			tdnode->AddNote();
			GetTreeList()->GetTree()->BroadcastChange(jnode);
			}
		else
			{
			JTableSelectionIterator iter(&s);
			JPoint cell;
			while (iter.Next(&cell))
				{
				JTreeNode* iternode = GetTreeList()->GetNode(cell.y);
				GNBToDoNode* tdnode = dynamic_cast(GNBToDoNode*, iternode);
				assert(tdnode != NULL);
				if (!tdnode->HasNote())
					{
					tdnode->AddNote();
					GetTreeList()->GetTree()->BroadcastChange(iternode);
					}
				}
			}
		}
	else if (index == kRemoveNoteCmd)
		{
		if (IsEditing())
			{
			GNBToDoNode* tdnode = dynamic_cast(GNBToDoNode*, jnode);
			assert(tdnode != NULL);
			tdnode->RemoveNote();
			GetTreeList()->GetTree()->BroadcastChange(jnode);
			}
		else
			{
			JTableSelectionIterator iter(&s);
			JPoint cell;
			while (iter.Next(&cell))
				{
				JTreeNode* iternode = GetTreeList()->GetNode(cell.y);
				GNBToDoNode* tdnode = dynamic_cast(GNBToDoNode*, iternode);
				assert(tdnode != NULL);
				if (tdnode->HasNote())
					{
					tdnode->RemoveNote();
					GetTreeList()->GetTree()->BroadcastChange(iternode);
					}
				}
			}
		}
	else if (index == kToggleUrgentCmd)
		{
		if (IsEditing())
			{
			GNBBaseNode* bnode = dynamic_cast(GNBBaseNode*, jnode);
			assert(bnode != NULL);
			GNBBaseNode::Type type = bnode->GetType();
			if (type == GNBBaseNode::kToDoNode)
				{
				GNBToDoNode* tdnode = dynamic_cast(GNBToDoNode*, jnode);
				assert(tdnode != NULL);
				tdnode->ToggleUrgency();
				GetTreeList()->GetTree()->BroadcastChange(jnode);
				}
			}
		else
			{
			JTableSelectionIterator iter(&s);
			JPoint cell;
			while (iter.Next(&cell))
				{
				JTreeNode* iternode = GetTreeList()->GetNode(cell.y);
				GNBToDoNode* tdnode = dynamic_cast(GNBToDoNode*, iternode);
				assert(tdnode != NULL);
				tdnode->ToggleUrgency();
				GetTreeList()->GetTree()->BroadcastChange(iternode);
				}
			}
		}
	else if (index == kMarkDoneCmd)
		{
		MarkSelectedAsDone(kTrue);
		}
	else if (index == kMarkUnDoneCmd)
		{
		MarkSelectedAsDone(kFalse);
		}
	else if (index == kExportSelCmd)
		{
		ExportSelected();
		}
	else if (index == kPrintSelCmd)
		{
		PrintSelected();
		}
	else if (index == kRemoveCmd)
		{
		if (IsEditing())
			{
			CancelEditing();
			GNBGetTrashDir()->DiscardNode(jnode);
			}
		else
			{
			JTableSelectionIterator iter(&s);
			JPoint cell;
			while (iter.Next(&cell))
				{
				JTreeNode* node = GetTreeList()->GetNode(cell.y);
				GNBGetTrashDir()->DiscardNode(node);
				}
			}
		SelectedFlushed();
		}
	else if (index == kViewDiscardsCmd)
		{
		GNBGetTrashDir()->Activate();
		}
	else if (index == kFlushCmd)
		{
		GNBGetTrashDir()->FlushDiscards();
		}
	else if (index == kQuitCmd)
		{
		GNBGetApplication()->Quit();
		}
}
