/*-----------------------------------------------------------------------------
[名称]	CategoryTreeView.cpp
[概要]	カテゴリツリービューの実装
[備考]	なし
[履歴]	2003-03-18	NC		新規作成(moralog)
-----------------------------------------------------------------------------*/


// Ｔｉｐｓ１３　ＯＬＥによるＤｎＤ
// http://hp.vector.co.jp/authors/VA007799/tips/tips13.htm


//-----------------------------------------------------------------------------
// インクルード
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "hebope.h"
#include "CategoryTreeView.h"
#include "AAListView.h"
#include "AAHanger.h"
#include "HebopeDoc.h"
#include "ExeCommon.h"
#include "MainFrm.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CCategoryTreeView

IMPLEMENT_DYNCREATE(CCategoryTreeView, CTreeView)

CCategoryTreeView::CCategoryTreeView()
: m_bUIReflect( TRUE )
{
}

CCategoryTreeView::~CCategoryTreeView()
{
}


BEGIN_MESSAGE_MAP(CCategoryTreeView, CTreeViewEx)
	//{{AFX_MSG_MAP(CCategoryTreeView)
	ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged)
	ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnEndlabeledit)
	ON_NOTIFY_REFLECT(TVN_DELETEITEM, OnDeleteitem)
	ON_WM_RBUTTONDOWN()
	ON_COMMAND(IDM_TREE_ADDNODE, OnTreeAddnode)
	ON_COMMAND(IDM_TREE_DELETENODE, OnTreeDeletenode)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCategoryTreeView 描画

void CCategoryTreeView::OnDraw(CDC* pDC)
{
	CDocument* pDoc = GetDocument();
	// TODO: この位置に描画用のコードを追加してください
}

/////////////////////////////////////////////////////////////////////////////
// CCategoryTreeView 診断

#ifdef _DEBUG
void CCategoryTreeView::AssertValid() const
{
	CTreeViewEx::AssertValid();
}

void CCategoryTreeView::Dump(CDumpContext& dc) const
{
	CTreeViewEx::Dump(dc);
}
#endif //_DEBUG


/*-----------------------------------------------------------------------------
[名称]	ペイン内容更新
[機能]	ドキュメント内容をビューに反映する
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CCategoryTreeView::ReflectView()
{
	CHebopeDoc*		pDoc = (CHebopeDoc*)(::GetMainFrame()->GetActiveDocument());
	if ( pDoc != NULL )
	{
		CCategoryTree*	pCategoryTree = pDoc->GetCategoryTree();

		SetUIReflect( FALSE );
		GetTreeCtrl().DeleteAllItems();

		// カテゴリツリーの内容を反映する
		// ツリーに追加してみるテスト
		HTREEITEM	RootNode = TVI_ROOT;
		CCategoryNode*	pNode = pCategoryTree->Node();
		pNode->Reflect(
			&GetTreeCtrl(),
			RootNode
		);

		SetUIReflect( TRUE );
	}
}


/*-----------------------------------------------------------------------------
[名称]	選択項目変更ハンドラ
[機能]	ノードの選択変更に伴って、リスト内容を変更する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CCategoryTreeView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

	// リストビューの内容更新
	::GetMainFrame()->ReflectListView();

	*pResult = 0;
}


/*-----------------------------------------------------------------------------
[名称]	ノード名称変更ハンドラ
[機能]	ノードの名称を変更する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CCategoryTreeView::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult) 
{
	TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;

	// データのノード名称を変更する
	BOOL		bModified = FALSE;
	CString		strNewNodeName(pTVDispInfo->item.pszText);
	if( !strNewNodeName.IsEmpty() )
	{
		CCategoryNode*	pCategoryNode;
		pCategoryNode = (CCategoryNode*)(GetTreeCtrl().GetItemData( pTVDispInfo->item.hItem ));
		pCategoryNode->SetNodeName( strNewNodeName );

		bModified = TRUE;
	}
	
	*pResult = bModified;
}


/*-----------------------------------------------------------------------------
[名称]	ノード削除ハンドラ
[機能]	ノードを削除する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CCategoryTreeView::OnDeleteitem(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

	// UIと連動の設定であれば元データのノードも削除
	if ( IsUIReflect() )
	{
		CCategoryNode*	pCategoryNode = (CCategoryNode*)(pNMTreeView->itemOld.lParam);
		CCategoryNode*	pParent = pCategoryNode->GetParent();
		if ( pParent != NULL )
		{
			pParent->DeleteNode( pCategoryNode );
		}
		else
		{
			// 親のないノードの削除？
			// ルートでないならノード追加時に親の設定を忘れている可能性
//			ASSERT( FALSE );
		}
	}
	*pResult = TRUE;
}


/*-----------------------------------------------------------------------------
[名称]	初期化ハンドラ
[機能]	ツリーコントロール、イメージリストを初期化する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL CCategoryTreeView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) 
{
	BOOL	bResult = CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);

	CBitmap bitmap;

	// イメージリストの初期化
	// ４番目の引数はリストが保持するイメージの数。５番目はリストを拡張するときの拡張イメージ数
	m_imageList.Create(16, 16, ILC_MASK, 3, 2);

	// ビットマップイメージをイメージリストに追加する
	// Add関数の２番目の引数は透過色（マスク）を表す
	bitmap.LoadBitmap(IDB_CLOSEFOLDER);
	m_imageList.Add(&bitmap, RGB(0,255,0));
	bitmap.DeleteObject();

	bitmap.LoadBitmap(IDB_OPENFOLDER);
	m_imageList.Add(&bitmap, RGB(0,255,0));
	bitmap.DeleteObject();

	bitmap.LoadBitmap(IDB_AA);
	m_imageList.Add(&bitmap, RGB(0,255,0));
	bitmap.DeleteObject();

	// ツリーコントロールにイメージリストを設定
	GetTreeCtrl().SetImageList(&m_imageList, TVSIL_NORMAL);

	// ノードをドロップしてネストさせることを許可する
	SetKeepIndentLevel( FALSE );


	m_DropTarget.Register( this );

	return( bResult );
}


/*-----------------------------------------------------------------------------
[名称]	アイテムのコピー開始ハンドラ
[機能]	コピー操作の許可不許可判断。
[戻値]	BOOL	コピー許可(TRUE:許可、FLSE:不許可)
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL CCategoryTreeView::OnCopyItem(
	HTREEITEM	hSrcNode,		// I :コピー元ノード [-] (-) :-
	HTREEITEM	hNewParent,		// I :コピー先親ノード [-] (-) :-
	HTREEITEM	hAfter			// I :コピー先兄ノード [-] (-) :-
)
{
	return( TRUE );
}


/*-----------------------------------------------------------------------------
[名称]	アイテムのコピーハンドラ
[機能]	コピー処理。
[戻値]	BOOL	処理結果(TRUE:成功、FLSE:失敗)
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL CCategoryTreeView::OnCopiedItem(
	HTREEITEM	hNewNode,		// I :コピー先ノード [-] (-) :-
	HTREEITEM	hSrcNode,		// I :コピー元ノード [-] (-) :-
	HTREEITEM	hNewParent,		// I :コピー先親ノード [-] (-) :-
	HTREEITEM	hAfter			// I :コピー先兄ノード [-] (-) :-
)
{
	CCategoryNode*	pSrcNode;
	pSrcNode = (CCategoryNode*)(GetTreeCtrl().GetItemData( hSrcNode ));

	CCategoryNode*	pParentNode;
	pParentNode = (CCategoryNode*)(GetTreeCtrl().GetItemData( hNewParent ));

	// ノードを追加位置の確認
	CCategoryNode*	pAfterNode = NULL;
	if ( hAfter != TVI_LAST )
	{
		pAfterNode = (CCategoryNode*)(GetTreeCtrl().GetItemData( hAfter ));
	}

	// ソースノードのコピーを親ノードに追加する
	CCategoryNode*	pNewNode = pParentNode->AddNode( *pSrcNode, pAfterNode );

	// ツリーノードのデータを設定
	GetTreeCtrl().SetItemData( hNewNode, (LPARAM)pNewNode );

	return( TRUE );
}


/*-----------------------------------------------------------------------------
[名称]	右クリックハンドラ
[機能]	ポップアップの表示。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CCategoryTreeView::OnRButtonDown(UINT nFlags, CPoint point) 
{
	// 該当ノードを選択
	UINT	uiWhere;
	HTREEITEM	Node = GetTreeCtrl().HitTest( point, &uiWhere );
	GetTreeCtrl().Select( Node, TVGN_CARET );

	// メニューのロード
	CMenu menu;
	VERIFY(menu.LoadMenu(IDR_TREEPOPUP));
	CMenu* pPopup = menu.GetSubMenu(0);

	// ポップアップメニューの表示
	CPoint posCursor( point );
	ClientToScreen( &posCursor );
	pPopup->TrackPopupMenu(
		TPM_LEFTALIGN | TPM_RIGHTBUTTON,
		posCursor.x, posCursor.y,
		::AfxGetMainWnd()
	);
}


/*-----------------------------------------------------------------------------
[名称]	ノード新規追加ハンドラ
[機能]	選択されているノードに子ノードを追加する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CCategoryTreeView::OnTreeAddnode() 
{
	// ツリービューで選択されているノードを得る
	CCategoryNode*	pCategoryNode = NULL;
	HTREEITEM ParentNode = GetTreeCtrl().GetSelectedItem();
	if ( ParentNode != NULL )
	{
		pCategoryNode = (CCategoryNode*)(GetTreeCtrl().GetItemData( ParentNode ));
	}

	// 新規ノードの追加
	if( pCategoryNode != NULL )
	{
		// 内部データにノード追加
		CCategoryNode*	pNewNode = pCategoryNode->AddNode( (CString)"(新規)" );

		// ツリービューにノード追加
		HTREEITEM NewNode = GetTreeCtrl().InsertItem( pNewNode->GetNodeName(), 0, 1, ParentNode );
		GetTreeCtrl().SetItemData( NewNode, (LPARAM)pNewNode );

		// 親ノードを開いて、新規追加ノードを選択する
		GetTreeCtrl().Select( NewNode, TVGN_CARET );

		// 新規ノード名称の編集開始
		GetTreeCtrl().EditLabel( NewNode );
	}
}


/*-----------------------------------------------------------------------------
[名称]	ノード削除ハンドラ
[機能]	選択されているノードを削除する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CCategoryTreeView::OnTreeDeletenode() 
{
	// ツリービューで選択されているノードを得る
	CCategoryNode*	pCategoryNode = NULL;
	HTREEITEM DeleteNode = GetTreeCtrl().GetSelectedItem();
	if ( DeleteNode != NULL )
	{
		// ノード削除
		GetTreeCtrl().DeleteItem( DeleteNode );
	}
}


/*-----------------------------------------------------------------------------
[名称]	ドラッグEnterハンドラ
[機能]	可能操作の通知。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
DROPEFFECT CCategoryTreeView::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) 
{
	UINT	uiFormat = ::RegisterClipboardFormat( g_strAADataFormat );
	if( pDataObject->IsDataAvailable( uiFormat ) )
	{
		// ctrl押下状態により、コピーかどうかを通知
        return (dwKeyState & MK_CONTROL) ? DROPEFFECT_COPY : DROPEFFECT_MOVE;
    }

	return CTreeViewEx::OnDragEnter(pDataObject, dwKeyState, point);
}


/*-----------------------------------------------------------------------------
[名称]	ドラッグOverハンドラ
[機能]	可能操作の通知。ドロップノードのハイライト再描画。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
DROPEFFECT CCategoryTreeView::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) 
{
	UINT	uiFormat = ::RegisterClipboardFormat( g_strAADataFormat );
	if( pDataObject->IsDataAvailable( uiFormat ) )
	{
		// 該当ノード割り出し
		UINT	uiWhere;
		HTREEITEM	DropNode = GetTreeCtrl().HitTest( point, &uiWhere );

		// ドロップ位置のノード先を描画
		GetTreeCtrl().SelectDropTarget( DropNode );

		// ctrl押下状態により、コピーかどうかを通知
		return (dwKeyState & MK_CONTROL) ? DROPEFFECT_COPY : DROPEFFECT_MOVE;
	}
	
	return CTreeViewEx::OnDragOver(pDataObject, dwKeyState, point);
}


/*-----------------------------------------------------------------------------
[名称]	ドロップハンドラ
[機能]	リストからのドロップ処理。インデクスの追加。
[戻値]	なし
[備考]	ソースデータは無視してリストの選択状態を見に行く。
-----------------------------------------------------------------------------*/
BOOL CCategoryTreeView::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point) 
{
	UINT	uiFormat = ::RegisterClipboardFormat( g_strAADataFormat );
	if( pDataObject->IsDataAvailable( uiFormat ) )
	{
		// 該当ノード割り出し
		UINT	uiWhere;
		HTREEITEM	DropNode = GetTreeCtrl().HitTest( point, &uiWhere );

		// ノードに対してAAデータを追加
		if( DropNode != NULL )
		{
			// リストビューに選択されている要素すべてをドロップされたものとみなす
			CListCtrl*	pList = &(::GetMainFrame()->GetListView()->GetListCtrl());
			CCategoryNode* pDropNode = (CCategoryNode*)(GetTreeCtrl().GetItemData( DropNode  ));

			POSITION pos = pList->GetFirstSelectedItemPosition();
			while( pos != NULL )
			{
				long idxLine = pList->GetNextSelectedItem( pos );				// リスト内番号
				long idxItem = (long)(pList->GetItemData( idxLine ));			// ノード内番号
				long idxAA = ::GetMainFrame()->GetListView()->Node()->GetIndex( idxItem );	// AA番号

				pDropNode->AddIndex( idxAA );
			}
		}

		// ドロップターゲットの初期化
		GetTreeCtrl().SelectDropTarget( NULL );
		return TRUE;
	}
	
	return CTreeViewEx::OnDrop(pDataObject, dropEffect, point);
}
