/////////////////////////////////////////////////////////////////////////////
// Name:        No names yet.
// Purpose:     Contrib. demo
// Author:      Aleksandras Gluchovas
// Modified by:
// Created:     2000/02/10
// RCS-ID:      $Id: dmbrowser.cpp,v 1.10 2001/04/04 12:42:36 aleksandras Exp $
// Copyright:   (c) Aleksandras Gluchovas
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

#ifdef __GNUG__
    #pragma implementation "minimal.cpp"
    #pragma interface "minimal.cpp"
#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 "dmbrowser.h"

#include "wx/awtlay/awt_emul.h"
#include "wx/awtlay/gridbaglayout.h"

#include "wx/pmf/pm.h" // FIMXE:: should not be coupled with PMF!

/***** Implementation for class wxDMPropertySheet *****/

IMPLEMENT_CLASS( wxDMPropertySheet, wxGrid )

BEGIN_EVENT_TABLE( wxDMPropertySheet, wxGrid )


    EVT_GRID_CELL_LEFT_CLICK( wxDMPropertySheet::OnCellLeftClick )
	EVT_GRID_CELL_RIGHT_CLICK( wxDMPropertySheet::OnCellRightClick )
	EVT_GRID_COL_SIZE( wxDMPropertySheet::OnColSize )
    EVT_GRID_CELL_CHANGE( wxDMPropertySheet::OnCellValueChanged )

	EVT_COMMAND_RANGE( -65535, 65535, wxEVT_COMMAND_CHECKBOX_CLICKED, 
					   wxDMPropertySheet::OnCheckBox )

					   
	EVT_COMMAND_RANGE( -65535, 65535, wxEVT_COMMAND_COMBOBOX_SELECTED, 
					   wxDMPropertySheet::OnChoice )

	EVT_IDLE( wxDMPropertySheet::OnIdle )
	EVT_SIZE( wxDMPropertySheet::OnSize )

	EVT_KEY_DOWN( wxDMPropertySheet::OnKeyDown )

END_EVENT_TABLE()

wxDMPropertySheet::wxDMPropertySheet( wxWindow* parent )

	: wxGrid( parent, -1 ),
	  mpAttrGroup( NULL ),
	  mLeftClicked( FALSE ),
	  mApplyPending( FALSE ),
	  mDisablePending( FALSE ),
	  mCreated( FALSE ),
	  mpContainer( NULL )
{
}

wxDMPropertySheet::~wxDMPropertySheet()
{
}

void wxDMPropertySheet::OnCellRightClick( wxGridEvent& event )
{
	int row = event.GetRow();

	mpNode->OnStartEdit();

	wxDMAttrInfo* pAttr = mpAttrGroup->GetAttr( row );

	pAttr->InitValue( mpGroupData );

	SetCellValue( pAttr->GetStringValue( mpGroupData ), row, 1 );

	mpNode->FindCmdProcessor()->SetChangeSender( this );
	mpNode->OnFinishEdit();

	event.Skip();
}

void wxDMPropertySheet::OnCellLeftClick( wxGridEvent& event )
{
	int row = event.GetRow();

	wxDMAttrInfo* pAttr = mpAttrGroup->GetAttr( row );

	if ( pAttr->ShownAsBooleanField() )
	{
		SaveEditControlValue();
		HideCellEditControl();
		MoveCursorLeft( FALSE );

		mpNode->OnStartEdit();

		bool on = !( GetCellValue( row, 1 ) == "1" );

		mpAttrGroup->GetAttr( row )->SetStringValue( on ? "1" : "0", mpGroupData );

		SetCellValue( on ? "1" : "", row, 1 );

		mpNode->FindCmdProcessor()->SetChangeSender( this );

		mpNode->OnFinishEdit();

		return;
	}
	else
	if ( pAttr->HasValueSelectionDialog() )
	{
		SaveEditControlValue();
		HideCellEditControl();

		wxString oldValue = pAttr->GetStringValue( mpGroupData );

		bool ok = pAttr->ShowValueSelectonDialog( mpGroupData );

		if ( ok )
		{
			wxString newValue = pAttr->GetStringValue( mpGroupData );

			pAttr->SetStringValue( oldValue, mpGroupData );

			mpNode->OnStartEdit();

			pAttr->SetStringValue( newValue, mpGroupData );

			SetCellValue( newValue, row, 1 );


			mpNode->FindCmdProcessor()->SetChangeSender( this );
			mpNode->OnFinishEdit();
		}

		MoveCursorLeft( FALSE );

		return; // event was 'eaten'
	}
	else
		mLeftClicked = TRUE;

	event.Skip();
}

void wxDMPropertySheet::OnColSize( wxGridEvent& event )
{
	AdjustColumnSizes();

	event.Skip();
}

void wxDMPropertySheet::OnCellValueChanged( wxGridEvent& event )
{
	//wxMessageBox( "value changed!" );

	ApplayValuesToFields();

	event.Skip();
}

void wxDMPropertySheet::OnIdle( wxIdleEvent& event )
{
	if ( mDisablePending )
	{
		mDisablePending = FALSE;
		EnableCellEditControl( FALSE );
	}

	if ( mLeftClicked )
	{
		mLeftClicked = TRUE;

		if ( CanEnableCellControl() )
		
			EnableCellEditControl();
	}

	if ( mApplyPending )
	{
		mApplyPending = FALSE;

		//SaveEditControlValue();

		int row = GetCursorRow(), col = GetCursorColumn();
        wxGridCellAttr* attr = GetCellAttr( row, col );
		
		wxGridCellEditor* editor = attr->GetEditor(this, row, col);
		editor->EndEdit(row, col, this);

		SaveEditControlValue();
		HideCellEditControl();
		MoveCursorLeft( FALSE );

		//SetCellValue( GetCellValue(row,col), row, col );
		//Refresh();
		//SetCellValue( "xcvax", row, col );

		//DisableCellEditControl();
	}

	event.Skip();
}

void wxDMPropertySheet::OnSize( wxSizeEvent& event )
{
	AdjustColumnSizes();

	event.Skip();
}

void wxDMPropertySheet::OnCheckBox( wxCommandEvent& event )
{
	//wxMessageBox( "OnCheck" );

	mApplyPending = TRUE;

	event.Skip();
}

void wxDMPropertySheet::OnChoice( wxCommandEvent& event )
{
	//wxMessageBox( "OnChoice" );

	mApplyPending = TRUE;

	event.Skip();
}

void wxDMPropertySheet::OnKeyDown( wxKeyEvent& event )
{
	if ( event.KeyCode() == WXK_RETURN )
	{
		if ( IsCellEditControlEnabled() )
		{
			SaveEditControlValue();
			HideCellEditControl();
			MoveCursorLeft( FALSE );
		}
	}
	else
		event.Skip();
}

void wxDMPropertySheet::AdjustColumnSizes()
{
	if ( GetNumberCols() != 2 ) return;

	int w = 0, h = 0;
	GetClientSize( &w, &h );

	int s1 = GetColSize( 0 );
	int s2 = GetColSize( 0 );

	if ( s1 + 50 > w )

		SetColSize( 1, 50 );
	else
		SetColSize( 1, w - s1 );
}

void wxDMPropertySheet::ReloadPropeties( wxDMNode* pNode, wxDMAttrGroupInfo* pAttrGroup )
{
	mpNode = pNode;
	mpGroupData = pNode->GetAttrGroupData( pAttrGroup );

	if ( !NeedsReloading( pAttrGroup ) )
	{
		mpAttrGroup = pAttrGroup;

		RefreshValueFields();

		return;
	}

	mpAttrGroup = pAttrGroup;


	if ( mCreated )
	{

		DeleteCols( 0, 2 );

		BeginBatch();
		DeleteRows( 0, GetRows() );

		AppendCols( 2 );
		AppendRows( mpAttrGroup->Count() );
	}
	else
	{
		mCreated = TRUE;
		CreateGrid( mpAttrGroup->Count(), 2 );
	
		BeginBatch();
	}


	//SetGridLineColour( *wxGREEN );
	m_gridLineColour = *wxBLACK;

    wxGridCellAttr *captionAttr = new wxGridCellAttr;
    captionAttr->SetTextColour(*wxBLACK);
    captionAttr->SetBackgroundColour( wxColour(224,224,224) );
	SetColAttr( 0, captionAttr );

	SetRowLabelSize( 0 );
	SetColLabelSize( 0 );

	EnableDragRowSize( FALSE );

	// add labels controls for entering field values

	for( size_t i = 0; i != mpAttrGroup->Count(); ++i )
	{
		wxDMAttrInfo& prop = *mpAttrGroup->GetAttr( i );

		if ( !prop.IsVisible() ) continue;

	    SetCellValue( prop.GetDisplayName(), i, 0 );
		SetReadOnly( i, 0 );
		SetCellValue( prop.GetStringValue( mpGroupData ), i, 1 );

		// for fields with restricted values, create wxChoice, and wxTextCtrl for others

		if ( prop.ShownAsBooleanField() )
		{
			wxString val = prop.GetStringValue( mpGroupData );
			SetCellValue( val, i, 1 );

			SetCellRenderer(i, 1, new wxGridCellBoolRenderer);
			SetCellEditor(i, 1, new wxGridCellBoolEditor );
		}
		else
		if ( prop.HasRestrictedValues( mpGroupData ) )
		{
			wxStringList values;
			prop.GetRestrictedValues( values, mpGroupData );

			wxGridCellChoiceEditor* pEditor = new wxGridCellChoiceEditor();
			SetCellRenderer(i, 1, new wxGridCellStringRenderer);
			SetCellEditor(i, 1, pEditor);

			wxString params;
			for( size_t k = 0; k != values.GetCount(); ++k )
			{
				if ( k != 0 ) params += ",";

				params += values[k];
			}

			pEditor->SetParameters( params );
		}
		else
		{
			SetCellRenderer(i, 1, new wxGridCellStringRenderer);
			SetCellEditor(i, 1, new wxGridCellTextEditor);
		}
	}

	AdjustColumnSizes();

	EndBatch();
}

bool wxDMPropertySheet::ValidateAllFields()
{

	return TRUE;
}

void wxDMPropertySheet::ApplayValuesToFields()
{
	mpNode->OnStartEdit();

	for( size_t i = 0; i != mpAttrGroup->Count(); ++i )
	{
		wxDMAttrInfo& prop = *mpAttrGroup->GetAttr( i );

		if ( !prop.IsVisible() ) continue;

		wxString val = GetCellValue( i, 1 );

		// if ( prop.ShownAsBooleanField() )
		// {
		//   if ( val == "1" ) val = "true";
		//   else val = "false";
		// }

		prop.SetStringValue( val, mpGroupData );
	}

	mpNode->FindCmdProcessor()->SetChangeSender( this );
	mpNode->OnFinishEdit();
}

bool wxDMPropertySheet::NeedsReloading( wxDMAttrGroupInfo* pAttrGroup )
{
	return pAttrGroup != mpAttrGroup;
}

void wxDMPropertySheet::RefreshValueFields()
{
	mpGroupData = mpNode->GetAttrGroupData( mpAttrGroup );

	for( size_t i = 0; i != mpAttrGroup->Count(); ++i )
	{
		wxDMAttrInfo& prop = *mpAttrGroup->GetAttr( i );

		wxString value = prop.GetStringValue( mpGroupData );

		//if ( prop.ShownAsBooleanField() )
		//{
		//	if ( value == "true" ) value = "1";
		//					  else value = "";
		//}

		SetCellValue( value, i, 1 );
	}
}

/***** Implementation for class wxDMNodePropertyGroupEditor *****/

wxDMNodePropertyGroupEditor::wxDMNodePropertyGroupEditor( wxWindow* parent )

	: wxTabbedWindow( parent, -1 )
{
}

wxDMNodePropertyGroupEditor::~wxDMNodePropertyGroupEditor()
{}

void wxDMNodePropertyGroupEditor::OnFocusChanged( wxDMNode& node )
{
	mpFocusedNode = &node;

	if ( GetTabCount() != (signed)node.GetGroupCount() )
	{
		RemoveAll();
		RecreateTabs();
	}

	RefreshProperties();
}

void wxDMNodePropertyGroupEditor::OnNodeChanged( wxDMNode& node )
{
	if ( &node == mpFocusedNode )
	{
		wxObject* pSender = node.FindCmdProcessor()->GetChangeSender();

		if ( pSender == NULL || !pSender->IsKindOf( CLASSINFO(wxDMPropertySheet) ) )

			RefreshProperties();
	}
}

void wxDMNodePropertyGroupEditor::OnFocusRemoved( wxDMNode& node )
{
	RemoveAll();
}

void wxDMNodePropertyGroupEditor::RemoveAll()
{
	while( GetTabCount() )

		RemoveTab(0);
}

void wxDMNodePropertyGroupEditor::RecreateTabs()
{
    size_t i;
	for( i = 0; i != mpFocusedNode->GetGroupCount(); ++i )
	{
	  // FOR NOW::HACK:: hardcoded icons..
		wxBitmap& bmp = wxPMBmpMgr().FindBitmap( i == 0 ? "misc/16x16_properties" 
														: "misc/16x16_layout" );

		AddTab( new wxDMPropertySheet( this ), 
			    mpFocusedNode->GetAttrGroupInfo(i)->GetName(), -1, &bmp );
	}

	SetActiveTab( 0 );

	RecalcLayout( TRUE );
	Refresh();
}

void wxDMNodePropertyGroupEditor::RefreshProperties()
{
    size_t i;
	for( i = 0; i != (unsigned)GetTabCount(); ++i )
	{
		wxDMPropertySheet* pSheet = (wxDMPropertySheet*)GetTab(i);

		pSheet->ReloadPropeties( mpFocusedNode, mpFocusedNode->GetAttrGroupInfo(i) );
	}
}

void wxDMNodePropertyGroupEditor::ReloadProperties()
{
	RemoveAll();

	RefreshProperties();
}

void wxDMNodePropertyGroupEditor::Update( wxDMNode* pRootNode )
{
	wxDMNode* pFocused = pRootNode->GetFocus();

	if ( pFocused == NULL )
	{
		if ( GetTabCount() )  //glt - there was a semicolon on the end of this line, which I think was wrong
			RemoveAll();
		return;
	}

	mpFocusedNode = pFocused;

	if ( GetTabCount() != (signed)pFocused->GetGroupCount() )
	{
		RemoveAll();
		RecreateTabs();
	}

	RefreshProperties();
}

/***** Implementation for class wxDMNodeCommandHandler *****/

BEGIN_EVENT_TABLE( wxDMNodeCommandHandler, wxEvtHandler )

	EVT_MENU( ID_MOVE_TOP,		wxDMNodeCommandHandler::OnMoveTop )
	EVT_MENU( ID_MOVE_BOTTOM,	wxDMNodeCommandHandler::OnMoveBottom )
	EVT_MENU( ID_MOVE_DOWN,		wxDMNodeCommandHandler::OnMoveDown )
	EVT_MENU( ID_MOVE_UP,		wxDMNodeCommandHandler::OnMoveUp )
	EVT_MENU( ID_COPY,			wxDMNodeCommandHandler::OnCopy )
	EVT_MENU( ID_PASTE,			wxDMNodeCommandHandler::OnPaste )
	EVT_MENU( ID_CUT,			wxDMNodeCommandHandler::OnCut )
	EVT_MENU( ID_DELETE,		wxDMNodeCommandHandler::OnDelete )
	EVT_MENU( ID_DUPLICATE,		wxDMNodeCommandHandler::OnDuplicate )
	EVT_MENU( ID_SELECT_ALL,	wxDMNodeCommandHandler::OnSelectAll )
	EVT_MENU( ID_UNDO,			wxDMNodeCommandHandler::OnUndo )
	EVT_MENU( ID_REDO,			wxDMNodeCommandHandler::OnRedo )

END_EVENT_TABLE()


wxDMNodeCommandHandler::wxDMNodeCommandHandler( wxDMNode* pRoot )

	: mpRoot( pRoot )
{}

/* event handlers */

void wxDMNodeCommandHandler::OnMoveUp( wxCommandEvent& event )
{
	wxDMNode* pNode = mpRoot->GetFocus();

	if ( !pNode || ( pNode && pNode->GetParent() == NULL ) ) return;

	size_t order = pNode->GetOrderNo();

	if ( order != 0 )
	{
		pNode->NotifyWillChange( pNode );

		pNode->SetOrderNo( order-1 );
	}
}

void wxDMNodeCommandHandler::OnMoveDown( wxCommandEvent& event )
{
	wxDMNode* pNode = mpRoot->GetFocus();

	if ( !pNode || ( pNode && pNode->GetParent() == NULL ) ) return;

	size_t order = pNode->GetOrderNo();

	if ( order + 1 < pNode->GetParent()->GetChildCount() )
	{
		pNode->NotifyWillChange( pNode );

		pNode->SetOrderNo( order+1 );
	}
}

void wxDMNodeCommandHandler::OnMoveTop( wxCommandEvent& event )
{
	wxDMNode* pNode = mpRoot->GetFocus();

	if ( !pNode || ( pNode && pNode->GetParent() == NULL ) ) return;

	size_t order = pNode->GetOrderNo();

	if ( order != 0 )
	{
		pNode->NotifyWillChange( pNode );

		pNode->SetOrderNo( 0 );
	}
}

void wxDMNodeCommandHandler::OnMoveBottom( wxCommandEvent& event )
{
	wxDMNode* pNode = mpRoot->GetFocus();

	if ( !pNode || ( pNode && pNode->GetParent() == NULL ) ) return;

	size_t order = pNode->GetOrderNo();

	if ( order != pNode->GetParent()->GetChildCount()-1 )
	{
		pNode->NotifyWillChange( pNode );

		pNode->SetOrderNo( pNode->GetParent()->GetChildCount()-1 );
	}
}

void wxDMNodeCommandHandler::OnCopy( wxCommandEvent& event )
{
	mpRoot->FindCmdProcessor()->Copy();
}

void wxDMNodeCommandHandler::OnPaste( wxCommandEvent& event )
{
	mpRoot->FindCmdProcessor()->Paste();
}

void wxDMNodeCommandHandler::OnCut( wxCommandEvent& event )
{
	mpRoot->FindCmdProcessor()->Copy();
	mpRoot->FindCmdProcessor()->Delete();
}

void wxDMNodeCommandHandler::OnDelete( wxCommandEvent& event )
{
	wxDMNode* pNode = mpRoot->GetFocus();

	if ( !pNode || ( pNode && pNode->GetParent() == NULL ) ) return;

	pNode->FindCmdProcessor()->Delete();
}

void wxDMNodeCommandHandler::OnDuplicate( wxCommandEvent& event )
{
	// TBD::
}

void wxDMNodeCommandHandler::OnSelectAll( wxCommandEvent& event )
{
	// TBD::
}

void wxDMNodeCommandHandler::OnUndo( wxCommandEvent& event )
{
	if ( !mpRoot->FindCmdProcessor()->CanUndo() )

		return;

	mpRoot->FindCmdProcessor()->Undo();
}

void wxDMNodeCommandHandler::OnRedo( wxCommandEvent& event )
{
	if ( !mpRoot->FindCmdProcessor()->CanRedo() )

		return;

	mpRoot->FindCmdProcessor()->Redo();
}

/*** UI-updates ***/

void wxDMNodeCommandHandler::OnCopyUI( wxUpdateUIEvent& event )
{
}

void wxDMNodeCommandHandler::OnPasteUI( wxUpdateUIEvent& event )
{
}

void wxDMNodeCommandHandler::OnCutUI( wxUpdateUIEvent& event )
{
}

void wxDMNodeCommandHandler::OnDeleteUI( wxUpdateUIEvent& event )
{
}

void wxDMNodeCommandHandler::OnDuplicateUI( wxUpdateUIEvent& event )
{
}

void wxDMNodeCommandHandler::OnSelectAllUI( wxUpdateUIEvent& event )
{
}

void wxDMNodeCommandHandler::OnUndoUI( wxUpdateUIEvent& event )
{
	event.Enable( mpRoot->FindCmdProcessor()->CanUndo() );
}

void wxDMNodeCommandHandler::OnRedoUI( wxUpdateUIEvent& event )
{
	event.Enable( mpRoot->FindCmdProcessor()->CanRedo() );
}

void wxDMNodeCommandHandler::SetRoot( wxDMNode* pRoot )
{
	mpRoot = pRoot;
}

void wxDMNodeCommandHandler::AddMenuCommands( wxMenu* pMenu )
{
	pMenu->Append( wxDMNodeCommandHandler::ID_MOVE_UP, "Move &Up" );
	pMenu->Append( wxDMNodeCommandHandler::ID_MOVE_DOWN, "Move &Down" );
	pMenu->AppendSeparator();

	pMenu->Append( wxDMNodeCommandHandler::ID_MOVE_TOP, "Move &Top" );
	pMenu->Append( wxDMNodeCommandHandler::ID_MOVE_BOTTOM, "Move &Bottom" );
	pMenu->AppendSeparator();

	pMenu->Append( wxDMNodeCommandHandler::ID_COPY,		 "&Copy" );
	pMenu->Append( wxDMNodeCommandHandler::ID_PASTE,	 "&Paste" );
	pMenu->Append( wxDMNodeCommandHandler::ID_CUT,	 "&Cut" );
	pMenu->Append( wxDMNodeCommandHandler::ID_DELETE,	 "De&lete" );
	pMenu->AppendSeparator();

	pMenu->Append( wxDMNodeCommandHandler::ID_DUPLICATE, "Duplica&te" );
}

/*** protected methods ***/
