/////////////////////////////////////////////////////////////////////////////
// Name:        No names yet.
// Purpose:     Contrib. demo
// Author:      Aleksandras Gluchovas
// Modified by:
// Created:     2000/02/08
// RCS-ID:      $Id: pm_gui.cpp,v 1.19 2001/04/20 10:17:11 georgetasker Exp $
// Copyright:   (c) Aleksandras Gluchovas
// Licence:   	GPL (version 2.0 or later)
/////////////////////////////////////////////////////////////////////////////

#ifdef __GNUG__
    #pragma implementation "pm_gui.cpp"
    #pragma interface "pm_gui.h"
#endif

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

#include "wx/pmf/pm_gui.h"

#include "wx/laywin.h"
#include "wx/clipbrd.h"
#include "wx/dataobj.h"
#include "wx/image.h"
#include "wx/datetime.h"

// wxNewSashLayoutWindow contrib...
#include "wx/pmf/newsash.h"

#include "mimetypes.h"

/***** Implementation for class wxPMSashLayoutPreference *****/

IMPLEMENT_DYNAMIC_CLASS( wxPMSashLayoutPreference, wxPMLayoutPreference )

wxPMSashLayoutPreference::wxPMSashLayoutPreference()

	: m_Alignment( wxLAYOUT_LEFT ),
	  m_OrderIndex( 0 )
{
}

wxPMSashLayoutPreference::wxPMSashLayoutPreference( int alignment, int orderIndex )

	: m_Alignment( alignment ),
	  m_OrderIndex( orderIndex )
{}

void wxPMSashLayoutPreference::Serialize( wxConfigBase& cfg, const wxString& key, bool isLoading )
{
	wxDateTime dt;
	// TBD::
}

void wxPMSashLayoutPreference::SetAlignment( int alignment )
{
	m_Alignment = alignment;
}

int wxPMSashLayoutPreference::GetAlignment()
{
	return m_Alignment;
}

void wxPMSashLayoutPreference::SetOrderIndex( int index )
{
	m_OrderIndex = index;
}

int wxPMSashLayoutPreference::GetOrderIndex() 
{	
	return m_OrderIndex;
}

void wxPMSashLayoutPreference::SetWidth( int width )
{
	m_Width = width;
}

int wxPMSashLayoutPreference::GetWidth()
{
	return m_Width;
}				   

/***** Implementation for class wxPMSashLayoutPreferenceTemplate *****/

wxPMSashLayoutPreferenceTemplate::
	wxPMSashLayoutPreferenceTemplate( wxClassInfo* pPaneClass,
									  wxPMSashLayoutPreference* pPreference )

	: m_pPaneClass( pPaneClass ),
	  m_pPrefrence( pPreference )
{
}

wxPMSashLayoutPreferenceTemplate::~wxPMSashLayoutPreferenceTemplate()
{
	if ( m_pPrefrence )
		delete m_pPrefrence;
}

/***** Implementation for class wxPMSimpleLayoutAlgorithm *****/

IMPLEMENT_DYNAMIC_CLASS( wxPMSashLayoutAlgorithm, wxEvtHandler )

BEGIN_EVENT_TABLE( wxPMSashLayoutAlgorithm, wxEvtHandler )

	EVT_SIZE( wxPMSashLayoutAlgorithm::OnSize )
	EVT_IDLE( wxPMSashLayoutAlgorithm::OnIdle )
	EVT_SASH_DRAGGED_RANGE( -10000, 60000, wxPMSashLayoutAlgorithm::OnSashDrag )

END_EVENT_TABLE()

wxPMSashLayoutAlgorithm::wxPMSashLayoutAlgorithm()

	: m_RelayoutPending( FALSE ),
	  m_NextWndId( 9000 )
{
	SetRefData( (wxObjectRefData*)(wxPMService*)this );
}

wxPMSashLayoutAlgorithm::~wxPMSashLayoutAlgorithm()
{
	SetRefData( NULL );

	WX_CLEAR_ARRAY( m_PrefTemplates );
}

bool wxPMSashLayoutAlgorithm::Start()
{
	wxPMBootSvc().GetMainWindow()->PushEventHandler( this );
	wxPMBootSvc().AddListener( this );

	return TRUE;
}

bool wxPMSashLayoutAlgorithm::Stop()
{
	// FIXME:: ensure ordering...

	wxPMBootSvc().RemoveListener( this );

	wxASSERT( wxPMBootSvc().GetMainWindow()->GetEventHandler() == this ); // DBG::

	wxPMBootSvc().GetMainWindow()->PopEventHandler();

	return TRUE;
}

wxObject* wxPMSashLayoutAlgorithm::GetWxObject()
{
	return (wxObject*)this;
}

void wxPMSashLayoutAlgorithm::OnPaneShown( wxPMPane& pane )
{
	if ( pane.GetParentPane() == NULL )
	{
		m_ActivePanes.Add( &pane );

		if ( pane.GetPaneWindow() == NULL )
		{
			wxNewSashLayoutWindow* win = 
				new wxNewSashLayoutWindow( wxPMBootSvc().GetMainWindow(), 
										++m_NextWndId, wxDefaultPosition, 
									    wxSize(200, 30), 
										wxNO_BORDER|wxSW_3D|wxSW_CLOSE_BOX|wxSW_DRAG_HINT 
										);

			win->SetDefaultSize(wxSize(200, 1000));
			win->SetOrientation(wxLAYOUT_VERTICAL);
			win->SetAlignment(wxLAYOUT_LEFT);
			//win->SetBackgroundColour(wxColour(0, 255, 0));
			win->SetSashVisible(wxSASH_RIGHT, TRUE);
			win->SetExtraBorderSize(5);

			pane.CreatePaneWindow( win );
		}

		pane.GetPaneWindow()->Show( TRUE );

		m_RelayoutPending = TRUE;
	}
}

void wxPMSashLayoutAlgorithm::OnPaneHidden( wxPMPane& pane )
{
	if ( pane.GetParentPane() == NULL )
	{
		m_ActivePanes.Remove( &pane );

		pane.GetPaneWindow()->Show( FALSE );

		m_RelayoutPending = TRUE;
	}
}

void wxPMSashLayoutAlgorithm::OnServiceStarted( wxPMService& service )
{
	if ( service.GetWxObject()->IsKindOf( CLASSINFO( wxPMPane ) ) )
	{
		wxPMPane* pPane = (wxPMPane*)service.GetWxObject();

		if ( pPane->GetParentPane() == NULL )
		
			m_TopLevelPanes.Add( pPane );
	}
}

void wxPMSashLayoutAlgorithm::OnServiceStopped( wxPMService& service )
{
	if ( service.GetWxObject()->IsKindOf( CLASSINFO( wxPMPane ) ) )
	{
		wxPMPane* pPane = (wxPMPane*)service.GetWxObject();

		if ( pPane->GetParentPane() == NULL )
		
			m_TopLevelPanes.Remove( pPane );
	}
}


wxPMLayoutPreference* wxPMSashLayoutAlgorithm::CreateDefaultLayoutPrefs()
{
	return NULL;
}

void wxPMSashLayoutAlgorithm::Serialize( wxConfigBase& cfg, const wxString& key, bool isLoading )
{
}

void wxPMSashLayoutAlgorithm::AddPreferenceTemplate( wxPMSashLayoutPreferenceTemplate* pTempl )
{
	m_PrefTemplates.Add( pTempl );
}

void wxPMSashLayoutAlgorithm::AddPreferenceTemplate( wxClassInfo* pClass, 
												    wxPMSashLayoutPreference* pPref )
{
	m_PrefTemplates.Add( new wxPMSashLayoutPreferenceTemplate( pClass, pPref ) );
}

/*** event handlers ***/

void wxPMSashLayoutAlgorithm::OnIdle( wxIdleEvent& event )
{
	if ( m_RelayoutPending )
	{
		m_RelayoutPending = FALSE;
		DoRelayout();
	}

	event.Skip();  // allow others do their tasks too
}

void wxPMSashLayoutAlgorithm::OnSashDrag( wxSashEvent& event )
{
	wxObject* pObj = event.GetEventObject();

	wxASSERT( pObj->IsKindOf( CLASSINFO( wxSashLayoutWindow ) ) ); // DBG::

	wxNewSashLayoutWindow* pWnd = (wxNewSashLayoutWindow*)pObj;

	pWnd->HandleSashDrag( event );
}

void wxPMSashLayoutAlgorithm::OnSize( wxSizeEvent& event )
{
	DoRelayout();
}

/*** protected methods ***/

void wxPMSashLayoutAlgorithm::DoRelayout()
{
    wxLayoutAlgorithm layout;
    layout.LayoutMDIFrame( wxPMBootSvc().GetMainWindow() );
}

/***** Implementation for class wxPMWorkplaceBrowserPane *****/

enum { wxPM_PRJ_TREE_ID = 200 };

IMPLEMENT_DYNAMIC_CLASS( wxPMWorkplaceBrowserPane, wxPMPane )

BEGIN_EVENT_TABLE( wxPMWorkplaceBrowserPane, wxPMPane )

	EVT_MENU( ID_REMOVE_PROJECT,      wxPMWorkplaceBrowserPane::OnCmdRemoveProject )
	EVT_MENU( ID_INSERT_PROJECT,      wxPMWorkplaceBrowserPane::OnCmdInsertProject )
	EVT_MENU( ID_NEW_PROJECT,         wxPMWorkplaceBrowserPane::OnCmdNewProject )
	EVT_MENU( ID_MAKE_PROJECT_ACTIVE, wxPMWorkplaceBrowserPane::OnCmdMakeProjectActive )
	EVT_MENU( ID_SAVE_WORKPLACE,      wxPMWorkplaceBrowserPane::OnCmdSaveWorkplace )
	EVT_MENU( ID_CLOSE_WORKPLACE,     wxPMWorkplaceBrowserPane::OnCmdCloseWorkplace )
	EVT_MENU( ID_NEW_WORKPLACE,       wxPMWorkplaceBrowserPane::OnCmdNewWorkplace )

END_EVENT_TABLE()

wxPMWorkplaceBrowserPane::wxPMWorkplaceBrowserPane()

	: m_pTree( NULL ),
	  m_pImageList( NULL ),

	  m_AwaysShowWorkplace( TRUE ),

	  m_WorkplaceBitmapName    ( "browsers/16x16_wxlogo_45_degrees" ),
	  m_RecentItemsBitmapName  ( "browsers/16x16_folder_blue" ),
	  m_ProjectBitmapName	  ( "browsers/16x16_yellow_folder" ),
	  m_ActiveProjectBitmapName( "browsers/16x16_yellow_folder_open" ),
	  m_OtherFilesBitmapName    ( "browsers/16x16_other_files" )
{
	SetRefData( (wxObjectRefData*)(wxPMService*)this );
}

bool wxPMWorkplaceBrowserPane::Start()
{
	SetPaneName( "Workplace Browser" );

	wxPMBootSvc().GetWorkplace()->AddListener( this );

	return TRUE;
}

bool wxPMWorkplaceBrowserPane::Stop()
{
	if ( m_pTree ) 
		
		m_pTree->Destroy();

	if ( m_pImageList )
		delete m_pImageList;

	m_ObjectHash.Clear();

	m_pTree = NULL; m_pImageList = NULL;

	return TRUE;
}

wxWindow* wxPMWorkplaceBrowserPane::GetPaneWindow()

{ 
	return m_pTree; 
}

void wxPMWorkplaceBrowserPane::CreatePaneWindow( wxWindow* pParent )
{
	m_pTree = CreateTree( pParent );

	m_pTree->SetFocus();

	m_pTree->PushEventHandler( this );

	CreateRootItem();

	AddProjectItems();
}

void wxPMWorkplaceBrowserPane::RebuildTree()
{
	m_pTree->DeleteAllItems();

	CreateRootItem();

	AddProjectItems();
}

void wxPMWorkplaceBrowserPane::SetAlwaysShowWorkplace( bool alwaysShown )
{
	m_AwaysShowWorkplace = alwaysShown;
}

bool wxPMWorkplaceBrowserPane::GetAlwaysShowWorkplace()
{
	return m_AwaysShowWorkplace;
}

void wxPMWorkplaceBrowserPane::SetWorkplaceBitmap( const wxString& name )
{
	m_WorkplaceBitmapName = name;
}

void wxPMWorkplaceBrowserPane::SetRecentItemsBitmap( const wxString& name )
{
	m_RecentItemsBitmapName = name;
}

void wxPMWorkplaceBrowserPane::SetProjectBitmap( const wxString& name )
{
	m_ProjectBitmapName = name;
}

void wxPMWorkplaceBrowserPane::SetActiveProjectBitmap( const wxString& name )
{
	m_ActiveProjectBitmapName = name;
}

void wxPMWorkplaceBrowserPane::SetOtherFilesBitmap( const wxString& name )
{
	m_OtherFilesBitmapName = name;
}

wxTreeItemId wxPMWorkplaceBrowserPane::AppendItem( wxTreeItemId parent, const wxString& text,
										   int image, int selImage,
										   wxPMBrowserTreeData* pData )
{
	wxTreeItemId id = m_pTree->AppendItem( parent, text, image, selImage, pData );

	if ( pData && pData->GetObject() )

		m_ObjectHash.Put( (long)pData->GetObject(), (wxObject*)(long)id );

	return id;
}

void wxPMWorkplaceBrowserPane::DeleteItem( wxTreeItemId item )
{
	wxPMBrowserTreeData* pData = (wxPMBrowserTreeData*)m_pTree->GetItemData( item );

	if ( pData ) 
	{
		if ( pData->GetObject() )

			m_ObjectHash.Delete( (long)pData->GetObject() );
	}

	m_pTree->Delete( item );
}

void wxPMWorkplaceBrowserPane::DeleteBranch( wxTreeItemId item )
{
	wxASSERT_MSG( item.IsOk(), "DeleteBranch() called with invalid item!" );

	wxTreeItemId child;
	long cookie = 0;

	m_pTree->GetFirstChild( child, cookie );

	while( child.IsOk() )
	{
		DeleteBranch( child );

		m_pTree->GetNextChild( child, cookie );
	}

	DeleteItem( item ); // delete item itself, after all of it's children deleted
}

wxPMBrowserTreeData* wxPMWorkplaceBrowserPane::FindDataForObject( wxObject* pObj )
{
	long id = (long)m_ObjectHash.Get( (long)pObj );

	if ( id == 0 )
		return NULL;

	return (wxPMBrowserTreeData*)m_pTree->GetItemData( wxTreeItemId(id) );
}

wxPMBrowserTreeData* wxPMWorkplaceBrowserPane::GetDataForObject( wxObject* pObj )
{
	wxPMBrowserTreeData* pData = FindDataForObject( pObj );

	wxASSERT_MSG( pData != NULL, "wxPMBrowserTreeData instance was not found for the given object!" );

	return pData;
}


wxTreeItemId wxPMWorkplaceBrowserPane::FindTreeItemForObject( wxObject* pObj )
{
	return wxTreeItemId( (long)m_ObjectHash.Get( (long)pObj ) );
}

wxPMProject* wxPMWorkplaceBrowserPane::GetProjectForItem( wxTreeItemId item )
{
	while( item.IsOk() )
	{
		wxPMBrowserTreeData* pData = (wxPMBrowserTreeData*)m_pTree->GetItemData( item );

		if ( pData->GetType() == wxPM_PROJECT_ITEM )
		
			return (wxPMProject*)pData->GetObject();

		item = m_pTree->GetParent( item );
	}

	int *avoidCompilerWarning = NULL;
	wxASSERT_MSG( avoidCompilerWarning, "GetProjectForItem() failed to find project object of the given item!" );

	return NULL;
}

wxPMProject* wxPMWorkplaceBrowserPane::GetSelectedProject()
{
	return GetProjectForItem( m_pTree->GetSelection() );
}

wxTreeCtrl* wxPMWorkplaceBrowserPane::GetTree()
{
	return m_pTree;
}

wxObject* wxPMWorkplaceBrowserPane::GetSelectedObject()
{
	wxPMBrowserTreeData* pData = 
		(wxPMBrowserTreeData*)m_pTree->GetItemData( m_pTree->GetSelection() );

	wxASSERT( pData );
	wxASSERT( pData->GetObject() );

	return pData->GetObject();
}

// overriden notifications of wxPMWorkplaceListener

void wxPMWorkplaceBrowserPane::OnProjectAdded( wxPMProject& project )
{
	if ( !m_pTree )
		return;

	AddProjectItem( &project );

	m_pTree->Expand( m_pTree->GetRootItem() );

	m_pTree->Refresh();
}

void wxPMWorkplaceBrowserPane::OnProjectRemoved( wxPMProject& project )
{
	if ( !m_pTree )
		return;

	wxTreeItemId item = FindTreeItemForObject( &project );

	wxASSERT_MSG( item.IsOk(), "ERROR:: cannot find tree item corresponding to given project!" );

	DeleteBranch( item );
}

void wxPMWorkplaceBrowserPane::OnProjectActivated( wxPMProject& project, 
												   wxPMProject* pPrevProject )
{
	if ( !m_pTree )
		return;

	// label of active is marked with BOLD font

	if ( pPrevProject != NULL )
	{
		wxPMBrowserTreeData* pData = GetDataForObject( pPrevProject );

		m_pTree->SetItemBold( pData->GetId(), FALSE ); // unmark

		m_pTree->SetItemImage( pData->GetId(), PROJECT_ITEM_IMAGE );
		m_pTree->SetItemSelectedImage( pData->GetId(), PROJECT_ITEM_IMAGE );
	}

	wxPMBrowserTreeData* pData = GetDataForObject( &project );

	m_pTree->SetItemBold( pData->GetId(), TRUE ); // mark

	m_pTree->SetItemImage( pData->GetId(), ACTIVE_PROJECT_ITEM_IMAGE );
	m_pTree->SetItemSelectedImage( pData->GetId(), ACTIVE_PROJECT_ITEM_IMAGE );
}

wxPMBrowserTreeCtrl* wxPMWorkplaceBrowserPane::CreateTree( wxWindow* pParent )
{
	m_pImageList = CreateImageList();

	wxPMBrowserTreeCtrl* pTree = 
		new wxPMBrowserTreeCtrl( pParent, this );

	if ( m_pImageList )

		pTree->SetImageList( m_pImageList );

	return pTree;
}

wxImageList* wxPMWorkplaceBrowserPane::CreateImageList()
{
	wxImageList* pLst = new wxImageList( 16,16, TRUE );

	pLst->Add( wxPMBmpMgr().FindAndCopyBitmap( m_WorkplaceBitmapName     ), *wxRED ); // 0
	pLst->Add( wxPMBmpMgr().FindAndCopyBitmap( m_RecentItemsBitmapName   ), *wxRED ); // 1
	pLst->Add( wxPMBmpMgr().FindAndCopyBitmap( m_ProjectBitmapName       ), *wxRED ); // 2
	pLst->Add( wxPMBmpMgr().FindAndCopyBitmap( m_ActiveProjectBitmapName ), *wxRED ); // 3
	pLst->Add( wxPMBmpMgr().FindAndCopyBitmap( m_OtherFilesBitmapName    ), *wxRED ); // 4

	return pLst;
}

// event-handlers for commands received from context-popup menu

void wxPMWorkplaceBrowserPane::OnCmdRemoveProject( wxCommandEvent& event )
{
//glt	wxPMBootSvc().GetWorkplace()->ProcessEvent( event );
	wxPMProject* pPrj = GetSelectedProject();

	wxASSERT( pPrj ); // DBG::

	wxPMBootSvc().GetWorkplace()->RemoveProject( pPrj );
}

void wxPMWorkplaceBrowserPane::OnCmdInsertProject( wxCommandEvent& event )
{
	wxPMBootSvc().GetWorkplace()->ProcessEvent( event );
}

void wxPMWorkplaceBrowserPane::OnCmdNewProject( wxCommandEvent& event )
{
	wxPMBootSvc().GetWorkplace()->ProcessEvent( event );
}

void wxPMWorkplaceBrowserPane::OnCmdMakeProjectActive( wxCommandEvent& event )
{
	wxPMProject* pPrj = GetSelectedProject();

	wxASSERT( pPrj ); // DBG::

	wxPMBootSvc().GetWorkplace()->SetActiveProject( pPrj );
}


void wxPMWorkplaceBrowserPane::OnCmdNewWorkplace( wxCommandEvent& event )
{
	wxPMBootSvc().GetWorkplace()->ProcessEvent( event );
}


void wxPMWorkplaceBrowserPane::OnCmdSaveWorkplace( wxCommandEvent& event )
{
	//@@@ to be done
}


void wxPMWorkplaceBrowserPane::OnCmdCloseWorkplace( wxCommandEvent& event )
{
	wxPMBootSvc().GetWorkplace()->ProcessEvent( event );
}

// overridables for concrete subclasses

void wxPMWorkplaceBrowserPane::OnItemExpanding( wxTreeItemId item, 
											    wxPMBrowserTreeData* pData  )
{ /* nothing by default */ }

void wxPMWorkplaceBrowserPane::OnItemCollapsed( wxTreeItemId item, 
											    wxPMBrowserTreeData* pData  )
{ /* nothing by default */ }

void wxPMWorkplaceBrowserPane::OnItemActivated( wxTreeItemId item, 
											    wxPMBrowserTreeData* pData )
{ /* nothing by default */ }

bool wxPMWorkplaceBrowserPane::OnSelectionChanging( wxTreeItemId item, 
												    wxPMBrowserTreeData* pData )

{ return TRUE; // return FALSE, if you wish to verto this event
}

void wxPMWorkplaceBrowserPane::OnSelectionChanged( wxTreeItemId item, 
												   wxPMBrowserTreeData* pData )
{ /* nothing by default */ }

void wxPMWorkplaceBrowserPane::OnDeleteRequested( wxTreeItemId item, 
												  wxPMBrowserTreeData* pData )
{ /* nothing by default */ }

void wxPMWorkplaceBrowserPane::OnContextMenuRequested( wxTreeItemId item, 
													   wxPMBrowserTreeData* pData,
													   int x, int y )
{
	wxMenu* pMenu = new wxMenu();

	// allow derived classes add their specific commands
	OnAddItemsToContextMenu( *pMenu, pData );

	m_pTree->PopupMenu( pMenu, x, y );

	// FIXME:: should we delete pMenu afterwards?
}

void wxPMWorkplaceBrowserPane::OnAddItemsToContextMenu( wxMenu& menu, 
													    wxPMBrowserTreeData* pData )
{
	if ( pData->GetType() == wxPM_ROOT_ITEM )
	{
		menu.Append( ID_SAVE_WORKPLACE, "Save workplace" );
		menu.Append( ID_CLOSE_WORKPLACE, "Close workplace" );
		menu.Append( ID_INSERT_PROJECT, "Insert existing project..." );
		menu.Append( ID_NEW_PROJECT,    "Insert new project..." );
	}
	else
	if ( pData->GetType() == wxPM_PROJECT_ITEM )
	{
		menu.Append( ID_REMOVE_PROJECT, "Remove project" );
		menu.Append( ID_MAKE_PROJECT_ACTIVE, "Make project active" );
	}
	else
	{
		menu.Append( 1000, "DBG:: Do nothing... (unknown type)" ); // DBG::
	}
}

/*** protected methods ***/

void wxPMWorkplaceBrowserPane::AddProjectItems()
{
	wxPMWorkplace& wp = *wxPMBootSvc().GetWorkplace();

	size_t i;
	for( i = 0; i != wp.GetProjectCount(); ++i )
	
		AddProjectItem( &wp.GetProject(i) );

	m_pTree->SortChildren(m_pTree->GetRootItem());
}

void wxPMWorkplaceBrowserPane::AddProjectItem( wxPMProject* pPrj )
{
	wxPMBrowserTreeData* pData = new wxPMBrowserTreeData( pPrj, wxPM_PROJECT_ITEM );	

	bool isActive = wxPMBootSvc().GetWorkplace()->IsActiveProject( pPrj );

	wxTreeItemId id = AppendItem( m_pTree->GetRootItem(), pPrj->GetTitle(), 
								  isActive ? ACTIVE_PROJECT_ITEM_IMAGE
										   : PROJECT_ITEM_IMAGE,
								  -1, pData );

	if ( !m_pTree->IsExpanded( m_pTree->GetRootItem() ) )

		m_pTree->Expand( m_pTree->GetRootItem() );

	if ( isActive ) 
	{	
		// auto-expand items of active project

		m_pTree->SetItemBold( id, TRUE );
		this->OnItemExpanding( id, pData );
		m_pTree->Expand( id );
	}

	m_pTree->SetItemHasChildren( id, TRUE );
}

void wxPMWorkplaceBrowserPane::RemoveProjectItem( wxPMProject* pPrj )
{
	wxTreeItemId id = FindTreeItemForObject( pPrj );

	DeleteBranch( id );
}

void wxPMWorkplaceBrowserPane::RemoveAllProjectItems()
{
	// TBD::
}

wxTreeItemId wxPMWorkplaceBrowserPane::CreateRootItem()
{
	wxPMBrowserTreeData* pData = 
		new wxPMBrowserTreeData( wxPMBootSvc().GetWorkplace(), 
								 wxPM_ROOT_ITEM );

	wxTreeItemId item = m_pTree->AddRoot( wxPMBootSvc().GetWorkplace()->GetTitle() + " workplace", 
									     WORKPLACE_ITEM_IMAGE, -1, pData );

	m_ObjectHash.Put( (long)pData->GetObject(), (wxObject*)(long)item );

	m_pTree->Expand( item );

	return item;
}

/***** Implementation for class wxPMBrowserTreeData *****/

wxPMBrowserTreeData::wxPMBrowserTreeData( wxObject* pObject, int itemType )

	: m_ItemType( itemType ),
	  m_pObject( pObject )
{}

wxPMBrowserTreeData::~wxPMBrowserTreeData()
{}

wxPMBrowserTreeData* wxPMBrowserTreeData::Clone()
{
	wxPMBrowserTreeData* pCopy = new wxPMBrowserTreeData( m_pObject, m_ItemType );

	return pCopy;
}

void wxPMBrowserTreeData::SetType( int itemType )
{
	m_ItemType = itemType;
}

int wxPMBrowserTreeData::GetType()
{
	return m_ItemType;
}

void wxPMBrowserTreeData::SetObject( wxObject* pObj )
{
	m_pObject = pObj;
}

wxObject* wxPMBrowserTreeData::GetObject()
{
	return m_pObject;
}

/***** Implementation for class wxPMBrowserTreeCtrl *****/

BEGIN_EVENT_TABLE( wxPMBrowserTreeCtrl, wxTreeCtrl )

	EVT_TREE_SEL_CHANGED   ( wxPM_PRJ_TREE_ID, wxPMBrowserTreeCtrl::OnSelectionChanged )
	EVT_TREE_KEY_DOWN      ( wxPM_PRJ_TREE_ID, wxPMBrowserTreeCtrl::OnKeyDown )
	EVT_TREE_BEGIN_DRAG    ( wxPM_PRJ_TREE_ID, wxPMBrowserTreeCtrl::OnBeginDrag )
	EVT_TREE_ITEM_EXPANDING( wxPM_PRJ_TREE_ID, wxPMBrowserTreeCtrl::OnItemExpanding )

	EVT_TREE_SEL_CHANGING( wxPM_PRJ_TREE_ID, wxPMBrowserTreeCtrl::OnSelectionChanging )

	EVT_RIGHT_DOWN ( wxPMBrowserTreeCtrl::OnRightClick  )
	EVT_LEFT_UP    ( wxPMBrowserTreeCtrl::OnLeftMouseUp )
	EVT_LEFT_DCLICK( wxPMBrowserTreeCtrl::OnDblClick    )
	EVT_MIDDLE_DOWN( wxPMBrowserTreeCtrl::OnMiddleClick )

END_EVENT_TABLE()

wxPMBrowserTreeCtrl::wxPMBrowserTreeCtrl( wxWindow* pParent, 
										  wxPMWorkplaceBrowserPane* pPane )

	 : wxTreeCtrl( pParent, wxPM_PRJ_TREE_ID, wxPoint(10,10), wxSize(200,300) ),
	   m_pPane( pPane )
{}

/*** tree-events ***/

void wxPMBrowserTreeCtrl::OnKeyDown( wxTreeEvent& event )
{
	if ( event.GetCode() == WXK_RETURN )
	{
		wxTreeItemId sel = this->GetSelection();

		if ( sel.IsOk() )

			m_pPane->OnItemActivated( sel, 
									  (wxPMBrowserTreeData*)GetItemData( sel ) );
	}

	event.Skip();
}

void wxPMBrowserTreeCtrl::OnBeginDrag( wxTreeEvent& event )
{
}

void wxPMBrowserTreeCtrl::OnItemExpanding( wxTreeEvent& event )
{
	m_pPane->OnItemExpanding( event.GetItem(), 
							 (wxPMBrowserTreeData*)GetItemData( event.GetItem() ) );
}

void wxPMBrowserTreeCtrl::OnSelectionChanging( wxTreeEvent& event )
{
	m_pPane->OnSelectionChanging( event.GetItem(), 
							     (wxPMBrowserTreeData*)GetItemData( event.GetItem() ) );
}

void wxPMBrowserTreeCtrl::OnSelectionChanged( wxTreeEvent& event )
{
	m_pPane->OnSelectionChanged( event.GetItem(), 
							    (wxPMBrowserTreeData*)GetItemData( event.GetItem() ) );
}

/*** mouse-events ***/

void wxPMBrowserTreeCtrl::OnDblClick( wxMouseEvent& event )
{
	wxTreeItemId sel = this->GetSelection();

	if ( sel.IsOk() )
		m_pPane->OnItemActivated( sel, (wxPMBrowserTreeData*)GetItemData( sel ) );
	else
		event.Skip();
}

void wxPMBrowserTreeCtrl::OnRightClick( wxMouseEvent& event )
{
	wxTreeItemId sel = this->GetSelection();

	if ( sel.IsOk() )
	
		m_pPane->OnContextMenuRequested( GetSelection(), 
										(wxPMBrowserTreeData*)GetItemData( sel ),
										event.GetX(), event.GetY() 
									  );
	else
		event.Skip();
}

void wxPMBrowserTreeCtrl::OnMiddleClick( wxMouseEvent& event )
{
	// FOR NOW:: nothing...
}

void wxPMBrowserTreeCtrl::OnMouseMove( wxMouseEvent& event )
{
	// FOR NOW:: nothing...
}

void wxPMBrowserTreeCtrl::OnLeftMouseUp( wxMouseEvent& event )
{
	// FOR NOW:: nothing...
}

#if 1
/***** Implementation for class wxPMFileBrowserPane *****/

static wxCommandInfo _gFileBrowserCommands[] = {

	wxCommandInfo( wxPMFileBrowserPane::ID_TOGGLE_BROWSER, "&Toggle Workplace Browser", "", "Alt+1" ),

	wxCommandInfo( 0, "" ) // terminator
};

static wxPMMergableMenuChain _gFileBrowserChains[] = {

	wxPMMergableMenuChain( "/&View/",  _gFileBrowserCommands ),

	wxPMMergableMenuChain( "", NULL ) // list-terminator
};

IMPLEMENT_DYNAMIC_CLASS( wxPMFileBrowserPane, wxPMWorkplaceBrowserPane )

BEGIN_EVENT_TABLE( wxPMFileBrowserPane, wxPMWorkplaceBrowserPane )

	EVT_MENU( ID_OPEN_FILE,       wxPMFileBrowserPane::OnCmdOpenFile )
	EVT_MENU( ID_ADD_FILE,        wxPMFileBrowserPane::OnCmdAddFile )
//	EVT_MENU( ID_ADD_FILES,       wxPMFileBrowserPane::OnCmdAddFiles )
	EVT_MENU( ID_ADD_FILES_RECURSIVELY, wxPMFileBrowserPane::OnCmdFilesRecursively )
	EVT_MENU( ID_REMOVE_FILE,     wxPMFileBrowserPane::OnCmdRemoveFile )
	EVT_MENU( ID_REMOVE_ALL,      wxPMFileBrowserPane::OnCmdRemoveAllFiles )
	EVT_MENU( ID_NEW_FILE,        wxPMFileBrowserPane::OnCmdNewFile )
	EVT_MENU( ID_COPY_NAME,       wxPMFileBrowserPane::OnCmdCopyName )
	EVT_MENU( ID_COPY_FULL_NAME,  wxPMFileBrowserPane::OnCmdCopyFullName )
	EVT_MENU( ID_SHOW_PROPERTIES, wxPMFileBrowserPane::OnCmdShowProperties )

	EVT_MENU( ID_TOGGLE_BROWSER, wxPMFileBrowserPane::OnCmdToggleBrowser )

END_EVENT_TABLE()

wxPMFileBrowserPane::wxPMFileBrowserPane()

	: wxPMWorkplaceBrowserPane()
{}

wxPMFileBrowserPane::~wxPMFileBrowserPane()
{}

wxPMMergableMenuChain* wxPMFileBrowserPane::GetMergableMenuChain()
{
	return _gFileBrowserChains;
}

// overriden notifications of wxPMWorkplaceListener

void wxPMFileBrowserPane::OnFileAdded( wxPMFileInfo& file, wxPMProject* pToProject )
{
	wxTreeItemId parent = FindTreeItemForObject( pToProject );

	AddFileItem( parent, file );

	if ( !m_pTree->IsExpanded( parent ) )
	{
		//OnItemExpanding( parent, (wxPMBrowserTreeData*)m_pTree->GetItemData(parent) );
		m_pTree->Expand( parent );
	}
}

void wxPMFileBrowserPane::OnFileRemoved( wxPMFileInfo& file, wxPMProject* pFromProject )
{
	DeleteItem( FindTreeItemForObject( &file ) );
}

// overriden notifications of wxPMWorkplaceBrowserPane

void wxPMFileBrowserPane::OnItemExpanding( wxTreeItemId item, wxPMBrowserTreeData* pData )
{
	if ( pData->GetType() == wxPM_PROJECT_ITEM &&
		 m_pTree->GetChildrenCount( item ) == 0 )
	{
		PMFileInfoListT& lst = ((wxPMProject*)pData->GetObject())->GetFiles();

		size_t i;
		for( i = 0; i != lst.Count(); ++i )
			AddFileItem( item, *lst[i] );
	}
	m_pTree->SortChildren(item);  //glt
}

void wxPMFileBrowserPane::OnDeleteRequested( wxTreeItemId item, wxPMBrowserTreeData* pData )
{
	if ( pData->GetType() == wxPM_FILE_ITEM_TYPE )
	{
		wxPMProject* pPrj = GetProjectForItem( item );

		pPrj->RemoveFile( (wxPMFileInfo*)pData->GetObject() );
	}
	else
		wxPMWorkplaceBrowserPane::OnDeleteRequested( item, pData );
}

void wxPMFileBrowserPane::OnAddItemsToContextMenu( wxMenu& menu, wxPMBrowserTreeData* pData )
{
	if ( pData->GetType() == wxPM_FILE_ITEM_TYPE ||
		 pData->GetType() == wxPM_PROJECT_ITEM 
	   )
	{
		if ( pData->GetType() == wxPM_FILE_ITEM_TYPE )
		{
			menu.Append( ID_OPEN_FILE, "&Open" );
			menu.AppendSeparator();
		}

		menu.Append( ID_ADD_FILE,              "Insert &file(s)" );
		menu.Append( ID_ADD_FILES_RECURSIVELY, "Insert files recur&sively..." );
		menu.AppendSeparator();
	}
    
   if ( pData->GetType() == wxPM_FILE_ITEM_TYPE )
   {
       menu.Append( ID_REMOVE_FILE,     "&Remove file" );
       menu.Append( ID_COPY_NAME,       "&Copy name" );
       menu.Append( ID_COPY_FULL_NAME,  "Copy f&ull path" );
       menu.Append( ID_SHOW_PROPERTIES, "Show &properties..." );
       menu.AppendSeparator();
	}
	else
	if ( pData->GetType() == wxPM_PROJECT_ITEM )
	{
		menu.Append( ID_REMOVE_ALL, "Remove &all files" );
		menu.Append( ID_NEW_FILE,   "&New file..." );
		menu.AppendSeparator();
	}

	wxPMWorkplaceBrowserPane::OnAddItemsToContextMenu( menu, pData );
}

// overriden "factory-methods" of wxPMWorkplaceBrowserPane
wxImageList* wxPMFileBrowserPane::CreateImageList()
{
	wxImageList* pLst = wxPMWorkplaceBrowserPane::CreateImageList();

	if ( msFileIcons.Count() == 0 ) // nothing's registered yet? try again...

		RegisterDefaultFileTypeIcons();

	size_t i;
	for( i = 0; i != msFileIcons.Count(); ++i )
	
		pLst->Add( *msFileIcons[i], *wxRED );

	// TBD::
	return pLst;
}

void wxPMFileBrowserPane::OnItemActivated( wxTreeItemId item, 
										   wxPMBrowserTreeData* pData )
{ 
	if ( pData->GetType() == wxPM_FILE_ITEM_TYPE )
    {
		wxPMDocument *pDocument = 
            wxPMBootSvc().GetDocManager()->OpenDocument(
                            *(wxPMFileInfo*)pData->GetObject(),
						    GetSelectedProject());

        if (pDocument)
        {
            // Check if the file location changed while opening the file
            // This can happen if the files original name or directory
            // path was modified after the project/workspace was originally
            // created, and when opening it this time, the user chose
            // to replace the original location/filename with a
            // different file or location.
            wxPMFileInfo *finfo = ((wxPMFileInfo*)pData->GetObject());
            if (pDocument->GetFilename() != finfo->GetPath())
            {
                finfo->SetPath(pDocument->GetFilename());
                pDocument->GetParentDocument()->Modify(TRUE);
            }
        }
    }
}  // wxPMFileBrowserPane::OnItemActivated()


// handlers for context-popup commands

void wxPMFileBrowserPane::OnCmdOpenFile( wxCommandEvent& event )
{
	wxPMBrowserTreeData* pData = 
		(wxPMBrowserTreeData*)m_pTree->GetItemData( m_pTree->GetSelection() );

	wxPMBootSvc().GetDocManager()->
		OpenDocument( *(wxPMFileInfo*)pData->GetObject(), GetSelectedProject() );
}

void wxPMFileBrowserPane::OnCmdAddFile( wxCommandEvent& event )
{
	GetSelectedProject()->ProcessEvent( event );
}
/*
void wxPMFileBrowserPane::OnCmdAddFiles( wxCommandEvent& event )
{
	GetSelectedProject()->ProcessEvent( event );
}
*/
void wxPMFileBrowserPane::OnCmdFilesRecursively( wxCommandEvent& event )
{
	GetSelectedProject()->ProcessEvent( event );
}

void wxPMFileBrowserPane::OnCmdRemoveFile( wxCommandEvent& event )
{
	wxPMBrowserTreeData* pData = 
		(wxPMBrowserTreeData*)m_pTree->GetItemData( m_pTree->GetSelection() );

	wxASSERT( pData->GetType() == wxPM_FILE_ITEM_TYPE );

	GetSelectedProject()->RemoveFile( (wxPMFileInfo*)pData->GetObject() );
}

void wxPMFileBrowserPane::OnCmdRemoveAllFiles( wxCommandEvent& event )
{
	wxPMProject* pPrj   = GetSelectedProject();
	PMFileInfoListT lst = pPrj->GetFiles();

	size_t i;
	for( i = 0; i != lst.Count(); ++i )

		pPrj->RemoveFile( lst[i] );
}

void wxPMFileBrowserPane::OnCmdNewFile( wxCommandEvent& event )
{
	// TBD:: how give a concrete project to which
	//       the created file should be inserted?

	wxPMBootSvc().GetDocManager()->ProcessEvent( event );
}

void wxPMFileBrowserPane::OnCmdCopyName( wxCommandEvent& event )
{
	wxObject* pObj = GetSelectedObject();

	wxASSERT( pObj->IsKindOf( CLASSINFO(wxPMFileInfo) ) ); // DBG::

	DoCopyToClipboard( ((wxPMFileInfo*)pObj)->GetNameWithoutPath() );
}

void wxPMFileBrowserPane::OnCmdCopyFullName( wxCommandEvent& event )
{
	wxObject* pObj = GetSelectedObject();

	wxASSERT( pObj->IsKindOf( CLASSINFO(wxPMFileInfo) ) ); // DBG::

	DoCopyToClipboard( ((wxPMFileInfo*)pObj)->GetPath() );
}

void wxPMFileBrowserPane::OnCmdShowProperties( wxCommandEvent& event )
{
	wxObject* pObj = GetSelectedObject();

	wxASSERT( pObj->IsKindOf( CLASSINFO(wxPMFileInfo) ) ); // DBG::

	wxPMFileInfo& file = *(wxPMFileInfo*)pObj;

	wxMessageBox( "TBD:: properties for file: \"" + file.GetPath() +
				  "\"\ntype: " + file.GetType() + "\n of project " +
				  GetSelectedProject()->GetTitle()
				);
				
}

void wxPMFileBrowserPane::OnCmdToggleBrowser( wxCommandEvent& event )
{
	if ( this->IsShown() )

		wxPMBootSvc().HidePane( this );
	else
		wxPMBootSvc().ShowPane( this );
}

/*** static methods ***/

// FIXME:: when these things will be destroyed??

wxStringList  wxPMFileBrowserPane::msMimeTypes;
PMBitmapListT wxPMFileBrowserPane::msFileIcons;

void wxPMFileBrowserPane::RegisterBitmapForMimeType( const wxString& bmpName, 
													 const wxString& mimeType )
{
	wxBitmap bmp = wxPMBmpMgr().FindAndCopyBitmap( bmpName );
	msFileIcons.Add( new wxBitmap( bmp ) );
	msMimeTypes.Add( mimeType );
}

void wxPMFileBrowserPane::RegisterBitmapForMimeType( const wxBitmap& bmp, 
													 const wxString& mimeType )
{
	msFileIcons.Add( new wxBitmap( bmp ) );
	msMimeTypes.Add( mimeType );
}

bool wxPMFileBrowserPane::FindBitmapForMimeType( const wxString& mimeType, wxBitmap& bmp )
{
	size_t i;
	for( i = 0; i != msMimeTypes.GetCount(); ++i )
	{
		if ( msMimeTypes[i] == mimeType )
		{
			bmp = *msFileIcons[i];
			return TRUE;
		}
	}
	return FALSE;
}

int wxPMFileBrowserPane::FindBitmapIndexForMimeType( const wxString& mimeType )
{
	size_t i;
	for( i = 0; i != msMimeTypes.GetCount(); ++i )
	{	
		if ( msMimeTypes[i] == mimeType )

			return i + FIRST_FILE_TYPE_IMAGE;
	}

	return FIRST_FILE_TYPE_IMAGE; // default unknown file-type
}

void wxPMFileBrowserPane::RegisterDefaultFileTypeIcons()
{
	// defaults:
	RegisterBitmapForMimeType( "filetypes/16x16_unknown_type", "" );

	RegisterBitmapForMimeType( "filetypes/16x16_bitmap_type", "image/bitmap" );
	RegisterBitmapForMimeType( "filetypes/16x16_bitmap_type", "image/bmp" );
	RegisterBitmapForMimeType( "filetypes/16x16_bitmap_type", "image/png" );
	RegisterBitmapForMimeType( "filetypes/16x16_bitmap_type", "image/xpm" );
	RegisterBitmapForMimeType( "filetypes/16x16_gif_type",    "image/gif" );
	RegisterBitmapForMimeType( "filetypes/16x16_jpeg_type",   "image/jpeg" );
	RegisterBitmapForMimeType( "filetypes/16x16_jpeg_type",   "image/pjpeg" );
	RegisterBitmapForMimeType( "filetypes/16x16_jpeg_type",   "image/jpg" );
	RegisterBitmapForMimeType( "filetypes/16x16_ico_type",    "image/icon" );

	RegisterBitmapForMimeType( "filetypes/16x16_mpeg_type",   "video/mpeg" );
	RegisterBitmapForMimeType( "filetypes/16x16_mpeg_type",   "video/avi" );

	RegisterBitmapForMimeType( "filetypes/16x16_txt_type",    wxwMIME_PLAIN_TEXT );

	RegisterBitmapForMimeType( "filetypes/16x16_html_type",   wxwMIME_HTML );
	RegisterBitmapForMimeType( "filetypes/16x16_h_type",      wxwMIME_C_HEADER );
	RegisterBitmapForMimeType( "filetypes/16x16_c_type",      wxwMIME_C_SOURCE );
	RegisterBitmapForMimeType( "filetypes/16x16_cpp_type",    wxwMIME_CPP_SOURCE );
	RegisterBitmapForMimeType( "filetypes/16x16_py_type",     wxwMIME_PYTHON );
	RegisterBitmapForMimeType( "filetypes/16x16_java_type",   wxwMIME_JAVA );

	RegisterBitmapForMimeType( "filetypes/16x16_wrs_type",   wxwMIME_WX_RESOURCE );
	RegisterBitmapForMimeType( "filetypes/16x16_wlk_type",   wxwMIME_WIDGET_LOOK );
	RegisterBitmapForMimeType( "filetypes/16x16_wrs_type",   wxwMIME_WIDGET_RESOURCE );

	RegisterBitmapForMimeType( "filetypes/16x16_class_type",  "application/x-java-class-file" );
	RegisterBitmapForMimeType( "filetypes/16x16_dll_type",    "application/x-windows-dll" );
	
	RegisterBitmapForMimeType( "filetypes/16x16_help_type",   "application/x-windows-help" );
	RegisterBitmapForMimeType( "filetypes/16x16_chm_type",    "application/x-chm-help" );
	RegisterBitmapForMimeType( "filetypes/16x16_zip_type",    "application/x-zip" );

	RegisterBitmapForMimeType( "filetypes/16x16_pyc_type",    "application/x-python-compiled" );
	RegisterBitmapForMimeType( "filetypes/16x16_unknown_type","application/unknown" );
}

/*** protected methods ***/

void wxPMFileBrowserPane::AddFileItem( wxTreeItemId parent, wxPMFileInfo& file )
{
	int img = wxPMFileBrowserPane::FindBitmapIndexForMimeType( file.GetType() );

	wxPMBrowserTreeData* pData = new wxPMBrowserTreeData( &file, wxPM_FILE_ITEM_TYPE );

	AppendItem( parent, file.GetNameWithoutPath(), img, img, pData );
	m_pTree->SortChildren(parent);
}

void wxPMFileBrowserPane::DoCopyToClipboard( const wxString& text )
{
#if !defined(__HACK_MY_MSDEV40__)

		// normal case

		if ( !wxTheClipboard->Open() )
			return;

	    wxTheClipboard->AddData( new wxTextDataObject( text ) );
		wxTheClipboard->Close();
#else

		// just to fix problems with my local 2.0.1 that i'm using:

		bool alreadyOpen=wxClipboardOpen();
		if (!alreadyOpen)
		{
			wxOpenClipboard();
			if (!wxEmptyClipboard()) 
			{
				wxCloseClipboard();
				return;
			}
		}

		bool success = ::wxEmptyClipboard();

		success = wxSetClipboardData( wxDF_TEXT, 
									  (wxObject*)text.c_str(), 0,0 );

		wxCloseClipboard();
#endif
}

#endif

