/*-----------------------------------------------------------------------------
[名称]	ShitarabianViewNormal.cpp
[概要]	Viewクラス（通常編集時）の実装
[備考]	なし
[履歴]	2003-02-25	NC		コメント付加(moralog)
		2003-10-23	b031031	(3178)マルチインデント処理NULLチェック付加
		2003-11-26	b031130 (3145)ATOK16の手書き文字入力文字化け(moralog)
		2003-12-26  b031228 (3331)選択範囲が一行のTAB押下はマルチインデント廃止(dincom)
		2003-12-28  b040111 (3632)キャレット位置の強調(moralog)
		2004-02-09	b031228 (3367)Grep検索(dincom)
-----------------------------------------------------------------------------*/


//-----------------------------------------------------------------------------
// インクルード
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "Common.h"
#include "ExeCommon.h"
#include "Shitarabian.h"
#include "ShitarabianDoc.h"
#include "ShitarabianView.h"
#include "Unicoder.h"
#include "imm.h"
#include "EditDrawer.h"
#include "CommandManager.h"
#include "CommandInput.h"
#include "CommandCaret.h"
#include "CommandDelete.h"
#include "CommandMultiEdit.h"
#include "GeneralSetting.h"
#include <process.h>
#include "Selection.h"
#include "BoxSelection.h"
#include "FloatingSelection.h"
#include "Padding.h"
#include "TokenReader.h"
#include "LinkDefine.h"
#include "MainFrm.h"

//-----------------------------------------------------------------------------
// ファイル内関数
//-----------------------------------------------------------------------------

/*-----------------------------------------------------------------------------
[名称]	描画オブジェクト取得
[機能]	描画オブジェクト取得処理。
[戻値]	CEditDrawer*	描画オブジェクト [-] (-)
[備考]	なし
-----------------------------------------------------------------------------*/
static CEditDrawer*	GetDrawer()
{
	return( CEditDrawer::GetInstance() );
}


//-----------------------------------------------------------------------------
// クラスメンバ関数
//-----------------------------------------------------------------------------

/*-----------------------------------------------------------------------------
[名称]	イベントハンドラ
[機能]	主にマウスイベント処理。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL CShitarabianView::PreTranslateNormalMode(
	MSG*	pMsg,				// I  :メッセージ [-] (-)
	BOOL	bShift,				// I  :シフト状態 [-] (TRUE:押下、FALSE:なし)
	BOOL	bCtrl,				// I  :Ctrl状態 [-] (TRUE:押下、FALSE:なし)
	BOOL	bAlt				// I  :Alt状態 [-] (TRUE:押下、FALSE:なし)
)
{
	// warning C4100:警告の無視
	bAlt; bCtrl; bShift;

	CEditDrawer*		pDrawer = GetDrawer();
	CShitarabianDoc*	pDoc = GetDocument();
	CSelection*			pSelection = pDoc->GetSelection();

	BOOL	bBreak = FALSE;
	BOOL	bRedraw = FALSE;
	BOOL	bSelectedModify = FALSE;

	int idxOldSelectedStartRow = pSelection->GetSelectedStartRow();
	int idxOldSelectedEndRow = pSelection->GetSelectedEndRow();
	int idxOldSelectedStartColumn = pSelection->GetSelectedStartColumn();
	int idxOldSelectedEndColumn = pSelection->GetSelectedEndColumn();

	int	nRow = pDoc->GetLineCount();

	switch( pMsg->message )
	{
	case WM_LBUTTONUP:
		ReleaseCapture();
		m_bDrag = FALSE;
		bRedraw = TRUE;
		bBreak = TRUE;
		break;

	case WM_MOUSEMOVE:

		// 入力操作時に消えていたマウスカーソルはマウス移動で現れる
		m_bInputMode = FALSE;
		DrawStatusBar();

		if ( !m_bVisibleCaret )
		{
			break;
		}
		if ( !(GetAsyncKeyState( VK_LBUTTON ) &0x8000) )
		{
			m_bDrag = FALSE;
		}
		if ( m_bDrag )
		{
			CPaintDC dc(this); // 描画用のデバイス コンテキスト
			int idxOldStartColumn = pSelection->GetSelectedStartColumn();
			int idxOldEndColumn = pSelection->GetSelectedEndColumn();

			// ピクセル座標を得る
			POINTS	pt = MAKEPOINTS( pMsg->lParam );
			CPoint posCursor( pt.x, pt.y );
			posCursor = ScrollBoxToPixel( posCursor );
			posCursor.y = max( posCursor.y, 0 );

			// 該当行計算
			int idxRow = pDrawer->PixelToCaretRow( posCursor.y, pDoc );
			idxRow = min( idxRow, pDoc->GetLineCount()-1 );

			CString*	pstrCurrentLine = pDoc->GetLine( idxRow );
			if ( pstrCurrentLine != NULL )
			{
				int	idxColumn = 0;
				CEmphasisLine*	pEmphasisLine = pDoc->GetEmphasisLine( idxRow );
				if ( pEmphasisLine != NULL )
				{
					idxColumn = pEmphasisLine->PixelToCaretColumn( posCursor.x );
				}

				// 選択範囲を変更
				pSelection->SetSelectedEnd(
					idxRow,
					idxColumn
				);

				// キャレットの移動
				CCommandCaret	cmdCaret;
				cmdCaret.SetAttribute( 0x00, idxRow, idxColumn );
				cmdCaret.Execute( pDoc );

				// 選択中にちらつかないように、選択範囲が変化しない間は再描画しない
				if(	( idxOldSelectedStartRow != pSelection->GetSelectedStartRow() ) ||
					( idxOldStartColumn != pSelection->GetSelectedStartColumn() ) ||
					( idxOldSelectedEndRow != pSelection->GetSelectedEndRow() ) ||
					( idxOldEndColumn != pSelection->GetSelectedEndColumn() ) )
				{
					bSelectedModify = TRUE;
					bRedraw = TRUE;
				}
			}
		}
		break;

	case WM_LBUTTONDBLCLK:
		{
			POINTS	pt = MAKEPOINTS( pMsg->lParam );
			CPoint posWindow( pt.x, pt.y );

			// 単語一発選択
			SelectMagicRod( posWindow );
			bSelectedModify = TRUE;
		}
		break;

	case WM_LBUTTONDOWN:
		{
			// ピクセル座標を得る
			POINTS	pt = MAKEPOINTS( pMsg->lParam );
			CPoint posWindow( pt.x, pt.y );
			CPoint posCursor( pt.x, pt.y );
			posCursor = ScrollBoxToPixel( posCursor );

			int idxRow = pDoc->GetCaretRow();
			int idxColumn = pDoc->GetCaretColumn();
			idxRow = pDrawer->PixelToCaretRow( posCursor.y, pDoc );

			// 行位置決定
			if ( CGeneralSetting::GetInstance()->GetFreeCursor() )
			{
				// フリーカーソルモードのとき行・カラムを拡張する
				pDoc->AppendRow( idxRow );
				pDoc->AppendColumn( idxRow, posCursor.x );
			}
			else
			{
				idxRow = min( idxRow, pDoc->GetLineCount()-1 );
			}
			idxRow = max( 0, idxRow );


			CEmphasisLine*	pEmphasisLine = pDoc->GetEmphasisLine( idxRow );
			if ( pEmphasisLine != NULL )
			{
				idxColumn = pEmphasisLine->PixelToCaretColumn( posCursor.x );

				// キャレットの移動
				CCommandCaret	cmdCaret;
				cmdCaret.SetAttribute( 0x00, idxRow, idxColumn );
				cmdCaret.Execute( pDoc );

				if ( GetAsyncKeyState( VK_CONTROL ) &0x8000 )
				{
					//Ctrl押しながらクリックした場合、単語選択する
					// 単語一発選択
					SelectMagicRod( posWindow );
					bSelectedModify = TRUE;
				}
				else
				{
					if ( GetAsyncKeyState( VK_SHIFT ) &0x8000 )
					{
						// Shift押しながらなら選択範囲を変更
						pSelection->SetSelectedEnd(
							pDoc->GetCaretRow(),
							pDoc->GetCaretColumn()
						);
						bSelectedModify = TRUE;
					}
					else
					{
						// 選択状態の解除
						if ( pSelection->IsSelected() )
						{
							bSelectedModify = TRUE;
						}
						pSelection->SetSelectedNutral();
					}

					// ドラッグの開始
					m_bDrag = TRUE;
					SetCapture( );

// ▼ (3632) BGN 2003.12.28 (moralog) キャレット位置の表示
					// キャレット位置再描画させるため選択情報変更扱いにする
					bSelectedModify = TRUE;
// ▲ (3632) END
				}
			}
			else
			{
//				ASSERT( FALSE );
			}
		}
		bRedraw = TRUE;
		bBreak = TRUE;
		break;

	default:
		break;
	}

	if ( bSelectedModify )
	{
		int	iStart = min( idxOldSelectedStartRow, pSelection->GetSelectedStartRow() );
		int	iEnd = max( idxOldSelectedEndRow, pSelection->GetSelectedEndRow() );

		if ( idxOldSelectedStartRow == pSelection->GetSelectedStartRow() )
		if ( idxOldSelectedStartColumn == pSelection->GetSelectedStartColumn() )
		{
			iStart = min( idxOldSelectedEndRow, pSelection->GetSelectedEndRow() );
			iEnd = max( idxOldSelectedEndRow, pSelection->GetSelectedEndRow() );
		}

		if ( idxOldSelectedEndRow == pSelection->GetSelectedEndRow() )
		if ( idxOldSelectedEndColumn == pSelection->GetSelectedEndColumn() )
		{
			iStart = min( idxOldSelectedStartRow, pSelection->GetSelectedStartRow() );
			iEnd = max( idxOldSelectedStartRow, pSelection->GetSelectedStartRow() );
		}

		pDoc->SetUpdateStartRow( iStart );
		pDoc->SetUpdateEndRow( iEnd );
	}

	if ( nRow != pDoc->GetLineCount() )
	{
		ResetHScroll();
	}

	if ( bRedraw )
	{
		// スクロールできそうであればスクロールバーを制御
		ScrollToCaret();

		// 再描画
		pDoc->ReDraw();

		// ここでDrawCaret()すると描画が全くされない。
		// キャレットの描画はDrawPage()内でする。
	}

	if( bBreak )
	{
		GetDocument()->SetMainView( this );
		return( TRUE );
	}
	else
	{
		return( FALSE );
	}
}


/*-----------------------------------------------------------------------------
[名称]	キー押下ハンドラ
[機能]	押下されたキーに応じた処理。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL CShitarabianView::PreTranslateKeyDownNormalMode(
	UCHAR	unKey,				// I  :キー [仮想キーコード] (-)
	BOOL	bShift,				// I  :シフト状態 [-] (TRUE:押下、FALSE:なし)
	BOOL	bCtrl,				// I  :Ctrl状態 [-] (TRUE:押下、FALSE:なし)
	BOOL	bAlt				// I  :Alt状態 [-] (TRUE:押下、FALSE:なし)
)
{
	// warning C4100:警告の無視
	bAlt;

	CEditDrawer*		pDrawer = GetDrawer();
	CShitarabianDoc*	pDoc = GetDocument();
	CSelection*			pSelection = pDoc->GetSelection();

	BOOL	bBreak = FALSE;
	BOOL	bSelectedModify = FALSE;

	int idxOldSelectedStartRow = pSelection->GetSelectedStartRow();
	int idxOldSelectedEndRow = pSelection->GetSelectedEndRow();

	int	nRow = pDoc->GetLineCount();


	switch( unKey )
	{
	case VK_F4:
		OnEditModeselect();
		break;

	case VK_INSERT:
		pDoc->OverwriteMode( !pDoc->IsOverwriteMode() );
		if ( pDoc->IsOverwriteMode() )
		{
//				HideCaret();
		}
		else
		{
			// キャレットの再描画
			// （HideCaretの回数をかぞえるのが面倒なので手っ取り早く作り直す）
			ShowCaret();
			pDoc->SetAllUpdate();
		}
		bSelectedModify = TRUE;
		bBreak = TRUE;
		break;

	case VK_LEFT:
	case VK_RIGHT:
	case VK_UP:
	case VK_DOWN:
	case VK_HOME:
	case VK_END:
	case VK_PRIOR:
	case VK_NEXT:
		if ( pDoc != NULL )
		{
			// まず、追加選択でないならキャレット位置を更新する
			if ( !bShift )
			{
				// 選択状態からの移動の場合、キャレット位置を調整する
				BOOL	bSelected;
				bSelected = pDoc->GetSelection()->IsSelected();

				// （上書きモードで単文字選択の場合は選択状態とみなさない）
				if ( pDoc->GetSelection()->GetSelectedStartRow() == pDoc->GetSelection()->GetSelectedEndRow() )
				if ( pDoc->GetSelection()->GetSelectedStartColumn()+1 == pDoc->GetSelection()->GetSelectedEndColumn() )
				if ( pDoc->IsOverwriteMode() )
				{
					bSelected = FALSE;
				}

				if ( bSelected )
				{
					CCommandCaret	cmdCaret;
					BOOL	bValid = TRUE;

					int		iOver = 0;
					if ( pDoc->IsOverwriteMode() )
					{
						iOver = 1;
					}

					switch( unKey )
					{
					case VK_LEFT:
						cmdCaret.SetAttribute(
							0x00,
							pDoc->GetSelection()->GetSelectedStartRow(),
							pDoc->GetSelection()->GetSelectedStartColumn()
						);
						break;
					case VK_UP:
						cmdCaret.SetAttribute(
							0x00,
							pDoc->GetSelection()->GetSelectedStartRow(),
							pDoc->GetSelection()->GetSelectedStartColumn()
						);
						break;
					case VK_RIGHT:
						cmdCaret.SetAttribute(
							0x00,
							pDoc->GetSelection()->GetSelectedEndRow(),
							pDoc->GetSelection()->GetSelectedEndColumn() - iOver
						);
						break;
					case VK_DOWN:
						cmdCaret.SetAttribute(
							0x00,
							pDoc->GetSelection()->GetSelectedEndRow(),
							pDoc->GetSelection()->GetSelectedEndColumn() - iOver
						);
						break;
					default:
						bValid = FALSE;
						break;
					}

					if ( bValid )
					{
						// キャレットの基準位置移動
						cmdCaret.Execute( pDoc );
					}

					// 選択状態の解除
					bSelectedModify = TRUE;
					pSelection->SetSelectedNutral();

					if ( bValid )
					{
						bBreak = TRUE;
						break;
					}
				}
			}

			// Ctrl押してるならそれなりに動く
			if ( bCtrl )
			{
				int idxRow = pDoc->GetCaretRow();
				int idxColumn = pDoc->GetCaretColumn();

				CString*	pstrLine = pDoc->GetLine( idxRow );

				CArray< TToken, TToken& >	aTokenz;
				CTokenReader::StringToCharTypez(
					*pstrLine,
					&aTokenz
				);

				int		idxToken = CTokenReader::TokenIndex(
					aTokenz,
					idxColumn
				);

				if ( idxToken == InvalidTokenIndex )
				{
					idxToken = aTokenz.GetSize()-1;
				}
				if ( idxToken >= 0 )
				{
					switch( unKey )
					{
					case VK_LEFT:
						{
							if ( idxColumn == aTokenz[ idxToken ].idxStartColumn )
							{
								if( idxToken > 0 )
								{
									idxColumn = aTokenz[ idxToken-1 ].idxStartColumn;
								}
							}
							else
							{
								idxColumn = aTokenz[ idxToken ].idxStartColumn;
							}

							// キャレットの移動
							CCommandCaret	cmdCaret;
							cmdCaret.SetAttribute(
								0x00,
								idxRow,
								idxColumn
							);
							cmdCaret.Execute( pDoc );
						}
						break;

					case VK_RIGHT:
						{
							if ( idxColumn == aTokenz[ idxToken ].idxStartColumn + aTokenz[ idxToken ].nColumn )
							{
								if( idxToken < aTokenz.GetSize()-1 )
								{
									idxColumn = aTokenz[ idxToken+1 ].idxStartColumn + + aTokenz[ idxToken+1 ].nColumn;
								}
							}
							else
							{
								idxColumn = aTokenz[ idxToken ].idxStartColumn + aTokenz[ idxToken ].nColumn;
							}
							// キャレットの移動
							CCommandCaret	cmdCaret;
							cmdCaret.SetAttribute(
								0x00,
								idxRow,
								idxColumn
							);
							cmdCaret.Execute( pDoc );
						}
						break;

					default:
						break;
					}
				}

				switch( unKey )
				{
				case VK_PRIOR:
					// スクロール位置を上に
					{
						CPoint	ptOld = GetDeviceScrollPosition();
						CPoint	ptNew = ptOld;
						ptNew.y -= pDrawer->CaretRowToPixelZoomed( 1 );

						// キャレットの移動
						CCommandCaret	cmdCaret;
						cmdCaret.SetAttribute( VK_UP, 0, 0 );
						cmdCaret.Execute( pDoc );

						// スクロールボックス内の画像をずらす＆必要な領域を再描画
						ManualVScroll( ptNew.y );
					}
					break;

				case VK_NEXT:
					// スクロール位置を下に
					{
						CPoint	ptOld = GetDeviceScrollPosition();
						CPoint	ptNew = ptOld;
						ptNew.y += pDrawer->CaretRowToPixelZoomed( 1 );

						// キャレットの移動
						CCommandCaret	cmdCaret;
						cmdCaret.SetAttribute( VK_DOWN, 0, 0 );
						cmdCaret.Execute( pDoc );

						// スクロールボックス内の画像をずらす＆必要な領域を再描画
						ManualVScroll( ptNew.y );
					}
					break;

				default:
					break;
				}
			}
			else
			{
			// Ctrl押してないなら普通に動く
				CCommandCaret	cmdCaret;
				cmdCaret.SetAttribute(
					unKey, 0, 0
				);
				cmdCaret.Execute( pDoc );
			}

			// 追加選択なら選択範囲変更
			if ( bShift )
			{
				pSelection->SetSelectedEnd(
					pDoc->GetCaretRow(),
					pDoc->GetCaretColumn()
				);
				bSelectedModify = TRUE;
			}
			else
			{
				pSelection->SetSelectedNutral();
				bSelectedModify = TRUE;
			}
		}
		bBreak = TRUE;
		break;

	case VK_BACK:
	case VK_DELETE:
		if ( pDoc != NULL )
		{
			// コマンドの登録
			CCommandDelete	cmdDelete;

			if ( !pSelection->IsSelected() )
			{
			// 単文字削除のとき
				if ( unKey == VK_BACK )
				{
					CCommandCaret	cmdCaret;
					int idxRow = pDoc->GetCaretRow();
					int idxColumn = pDoc->GetCaretColumn();
					// 文書の先頭ではBSできない
					if ( idxRow == 0 )
					if ( idxColumn == 0 )
					{
						break;
					}

					// 削除前にキャレットを左（または上の上）へ移動する
					// その際、Unicode内のカラムへの移動もありうる。
					CUnicoder*	pUnicoder = CUnicoder::GetInstance();
					BOOL	bUnicode = pUnicoder->GetEnable();
					pUnicoder->SetEnable( FALSE );
					cmdCaret.SetAttribute( VK_LEFT, idxRow, idxColumn );
					cmdCaret.Execute( pDoc );
					pUnicoder->SetEnable( bUnicode );
				}

				int idxRow = pDoc->GetCaretRow();
				int idxColumn = pDoc->GetCaretColumn();
				cmdDelete.SetAttribute( idxRow, idxColumn, idxRow, idxColumn+1 );
			}
			else
			{
			// 選択範囲削除
				cmdDelete.SetAttribute(
					pSelection->GetSelectedStartRow(),
					pSelection->GetSelectedStartColumn(),
					pSelection->GetSelectedEndRow(),
					pSelection->GetSelectedEndColumn()
				);
			}
			cmdDelete.Execute( pDoc );

			CCommandManager*	pCmd = CCommandManager::GetInstance();
			pCmd->Add( cmdDelete );

			// 選択状態の解除
			if ( pSelection->IsSelected() )
			{
				bSelectedModify = TRUE;
			}
			pSelection->SetSelectedNutral();
		}

		bBreak = TRUE;
		break;

	case ' ':
		if ( bShift )
		{
			// 空白の全角半角読み替え機能
			CString		strWord;
			strWord = _T("　");

			// 選択範囲の削除
			if ( pSelection->IsSelected() )
			{
				pDoc->SelectedDelete();
				bSelectedModify = TRUE;
			}

			// コマンドの登録
			CCommandInput	cmdInput;
			int idxRow = pDoc->GetCaretRow();
			int idxColumn = pDoc->GetCaretColumn();
			cmdInput.SetAttribute( strWord, idxRow, idxColumn );
			cmdInput.Execute( pDoc );

			CCommandManager*	pCmd = CCommandManager::GetInstance();
			pCmd->Add( cmdInput );

			// 選択範囲の初期化
			pSelection->SetSelectedNutral();
			bBreak = TRUE;
		}
		break;

	default:
		return( FALSE );
		break;
	}

	if ( bSelectedModify )
	{
		pDoc->SetUpdateStartRow( min( idxOldSelectedStartRow, pSelection->GetSelectedStartRow() ) );
		pDoc->SetUpdateEndRow( max( idxOldSelectedEndRow, pSelection->GetSelectedEndRow() ) );
	}

	if ( nRow != pDoc->GetLineCount() )
	{
		ResetHScroll();
	}

	if( bBreak )
	{
		// ここでDrawCaret()すると描画が全くされない。
		// キャレットの描画はDrawPage()内でする。

		GetDocument()->SetMainView( this );
		return( TRUE );
	}
	else
	{
		return( FALSE );
	}
}


/*-----------------------------------------------------------------------------
[名称]	文字入力ハンドラ
[機能]	入力された文字に応じた処理。
[戻値]	なし
[備考]	VK_ESCAPE:	選択の解除
		VK_RETURN:	選択範囲の削除、改行の入力
		VK_TAB:		タブ文字の入力もしくはマルチインデント
		その他:		文字入力
		文字入力であればマウスカーソルを消す。

		(3178) 2003.10.23	マルチインデント対象行が無い場合は処理しない(moralog)
-----------------------------------------------------------------------------*/
BOOL CShitarabianView::PreTranslateCharNormalMode(
	CString	strChar,			// I  :入力文字列　[-] (-)
	BOOL	bShift,				// I  :シフト状態 [-] (TRUE:押下、FALSE:なし)
	BOOL	bCtrl,				// I  :Ctrl状態 [-] (TRUE:押下、FALSE:なし)
	BOOL	bAlt				// I  :Alt状態 [-] (TRUE:押下、FALSE:なし)
)
{
	// warning C4100:警告の無視
	bAlt; bCtrl;

	CShitarabianDoc*	pDoc = GetDocument();
	CSelection*			pSelection = pDoc->GetSelection();

	BOOL	bBreak = FALSE;
	BOOL	bSelectedModify = FALSE;

	int idxOldSelectedStartRow = pSelection->GetSelectedStartRow();
	int idxOldSelectedEndRow = pSelection->GetSelectedEndRow();

	int	nRow = pDoc->GetLineCount();

// ▼ (3145) BGN 2003.11.26 (moralog) ATOK16の手書き文字入力文字化け
	// マルチバイト文字リードバイトのみ来たときは、後続バイトが来るまで処理を保留する
	static CString	s_strLeadByte;
	if ( strChar.GetLength() == 1 )
	{
		if ( !s_strLeadByte.IsEmpty() )
		{
			// 先行するリードバイトが存在するので今回来たバイトを後続バイトと見なす
			// 連結して１文字とする。
			CString	str;
			str.Format( "%s%s", s_strLeadByte, strChar );
			strChar = str;
			s_strLeadByte.Empty();
		}
		else
		{
			// リードバイトであれば先行バイトと見なして保存する
			if ( _istleadbyte( strChar[0] ) )
			{
				s_strLeadByte = strChar;
				return( FALSE );
			}
			else
			{
				// リードバイトでなければただの1バイト文字
			}
		}
	}
	else
	{
		// 文字として完成した文字列が来たようなので、リードバイト情報を破棄する
		s_strLeadByte.Empty();
	}
// ▲ (3145) END

	if ( strChar == (CString)VK_ESCAPE )
	{
		// 選択状態の解除
		if ( pSelection->IsSelected() )
		{
			bSelectedModify = TRUE;
		}
		pSelection->SetSelectedNutral();
		bBreak = TRUE;
	}
	else if( strChar == VK_RETURN )
	{
		if ( pDoc != NULL )
		{
			// 選択範囲の削除
			pDoc->SelectedDelete();

			// コマンドの登録
			CCommandInput	cmdInput;
			int idxRow = pDoc->GetCaretRow();
			int idxColumn = pDoc->GetCaretColumn();
			cmdInput.SetAttribute( pDoc->ReturnChar(), idxRow, idxColumn );
			cmdInput.Execute( pDoc );

			CCommandManager*	pCmd = CCommandManager::GetInstance();
			pCmd->Add( cmdInput );

			// 選択状態の解除
			if ( pSelection->IsSelected() )
			{
				bSelectedModify = TRUE;
			}
			pSelection->SetSelectedNutral();
			bBreak = TRUE;
		}
	}
	else if( strChar == (CString)VK_TAB )
	{
		// タブ文字生成
		CString		strTabString;
		if ( CGeneralSetting::GetInstance()->GetTabConvert() )
		{
			strTabString = CGeneralSetting::GetInstance()->GetTabString();
		}
		else
		{
			strTabString = strChar;
		}

		if ( pDoc != NULL )
		{
			// ▼ (3331) BGN 2003.12.26 (dincom) 
			// 複数行選択中のときはマルチインデントする
			BOOL	bMultiIndent( TRUE );
			bMultiIndent &= pDoc->GetSelection()->IsSelected();
			bMultiIndent &= pDoc->GetSelection()->GetSelectedStartRow() != pDoc->GetSelection()->GetSelectedEndRow();
			if ( !bMultiIndent )
			// ▽ Original BGN
			//if ( !pDoc->GetSelection()->IsSelected() )
			// △ Original END
			// ▲ (3331) END
			{
			// 単一文字の挿入
			// ▼ (3331) BGN 2003.12.26 (dincom) 
				// 選択範囲の削除
				pDoc->SelectedDelete();
			// ▲ (3331) END
				
				// 入力コマンドの実行
				CCommandInput	cmdInput;
				int idxRow = pDoc->GetCaretRow();
				int idxColumn = pDoc->GetCaretColumn();
				cmdInput.SetAttribute( strTabString, idxRow, idxColumn );
				cmdInput.Execute( pDoc );

				// コマンドマネージャに登録
				CCommandManager*	pCmd = CCommandManager::GetInstance();
				pCmd->Add( cmdInput );


				// 選択状態の解除
				if ( pSelection->IsSelected() )
				{
					bSelectedModify = TRUE;
				}
				pSelection->SetSelectedNutral();
			}
			else
			{
			// マルチインデントの実行
				int		idxStartRow = pDoc->GetSelection()->GetSelectedStartRow();
				int		idxEndRow = pDoc->GetSelection()->GetSelectedEndRow();
				int		idxEffectedStartRow = idxEndRow;
				int		idxEffectedEndRow = -1;
				{
					CArray<TSelectColumn,TSelectColumn&>* paSelectColumnz = pDoc->GetSelection()->GetSelectedLinez();

					CCommandMultiEdit	cmdEdit;
					for( int idxLine=0 ; idxLine<=idxEndRow-idxStartRow ; idxLine++ )
					{
						// 選択範囲のない行が含まれていたら、選択範囲を狭める
						if ( paSelectColumnz->GetAt(idxLine).idxStart == paSelectColumnz->GetAt(idxLine).idxEnd )
						{
							continue;
						}
						if( idxEffectedStartRow > idxStartRow+idxLine )
						{
							idxEffectedStartRow = idxStartRow+idxLine;
						}
						idxEffectedEndRow = idxStartRow+idxLine;


						CString* pstrLine = pDoc->GetLine( idxStartRow+idxLine );
						if ( pstrLine != NULL )
						{
							if ( bShift )
							{
							// マルチ逆インデント
								CWhitespaceDefine*	pWhiteSpace = CGeneralSetting::GetInstance()->GetWhitespace();
								int		nByte;
								BOOL	bWhiteSpace = pWhiteSpace->IsWhitespace(
									(LPCTSTR)(*pstrLine),
									&nByte
								);
								if( bWhiteSpace )
								{
									// 入力コマンドの登録
									CCommandDelete	cmdDelete;
									cmdDelete.SetAttribute(
										idxStartRow+idxLine, 0,
										idxStartRow+idxLine, 1
									);
									cmdEdit.Add( cmdDelete );
								}
							}
							else
							{
							// マルチインデント
								if ( !pstrLine->IsEmpty() )
								{
									// 入力コマンドの登録
									CCommandInput	cmdInput;
									cmdInput.SetAttribute( strTabString, idxStartRow+idxLine, 0 );
									cmdEdit.Add( cmdInput );
								}
							}
						}
					// please! Addしてから設定したほうがよさげ
					}
					cmdEdit.Execute( pDoc );

					// コマンドマネージャに登録
					CCommandManager*	pCmd = CCommandManager::GetInstance();
					pCmd->Add( cmdEdit );
					// please! Addしてから設定したほうがよさげ
				}

				// 選択範囲を変更。選択行全てを選択する
// ▼ (3178) BGN 2003.10.23 (moralog) マルチインデント対象行が無い場合は処理しない
				long	nEffectedRow = idxEffectedEndRow - idxEffectedStartRow +1;
				if ( nEffectedRow > 0 )
// ▲ (3178) END
				{
					pSelection->SetSelectedStart(
						idxEffectedStartRow,
						0
					);
					CString* pstrCurrentLine = pDoc->GetLine( idxEffectedEndRow );
// ▼ (3178) BGN 2003.10.23 (dincom) NULLアクセスチェック付加
					if( pstrCurrentLine != NULL )
					{
						long	idxEffectedEndColumn = ::ByteColumnToCaretColumn( *pstrCurrentLine, pstrCurrentLine->GetLength() );
						pSelection->SetSelectedEnd(
							idxEffectedEndRow,
							idxEffectedEndColumn
						);
						bSelectedModify = TRUE;
					}
// ▽ oridinal BGN
//					long	idxEffectedEndColumn = ::ByteColumnToCaretColumn( *pstrCurrentLine, pstrCurrentLine->GetLength() );
//					pSelection->SetSelectedEnd(
//						idxEffectedEndRow,
//						idxEffectedEndColumn
//					);
//					bSelectedModify = TRUE;
// △ oridinal END
// ▲ (3178) END
				}
			}

			bBreak = TRUE;
		}
	}
	else
	{
		if ( pDoc != NULL )
		if ( !strChar.IsEmpty() )
		if ( strChar[0] >= (DWORD)' ' )
		{
			CString		strWord = strChar;

			// 選択範囲の削除
			if ( pSelection->IsSelected() )
			{
				pDoc->SelectedDelete();
				bSelectedModify = TRUE;
			}

			// コマンドの登録
			CCommandInput	cmdInput;
			int idxRow = pDoc->GetCaretRow();
			int idxColumn = pDoc->GetCaretColumn();
			cmdInput.SetAttribute( strWord, idxRow, idxColumn );
			cmdInput.Execute( pDoc );

			CCommandManager*	pCmd = CCommandManager::GetInstance();
			pCmd->Add( cmdInput );

			// 選択範囲の初期化
			pSelection->SetSelectedNutral();
			bBreak = TRUE;
		}
	}

	// 入力操作時はマウスカーソルを消す
	// ▼ (3367) BGN 2004.02.09 (dincom)
	// ▽ Original BGN
	//m_bInputMode = TRUE;
	//SetCursor( NULL );
	// △ Original END
	if ( !IsProgress() )
	{
		// プログレスダイアログが表示されているときは
		// 自動処理中なのでカーソル制御の必要は無い。
		m_bInputMode = TRUE;
		SetCursor( NULL );
	}
	// ▲ (3367) END

	if ( bSelectedModify )
	{
		pDoc->SetUpdateStartRow( min( idxOldSelectedStartRow, pSelection->GetSelectedStartRow() ) );
		pDoc->SetUpdateEndRow( max( idxOldSelectedEndRow, pSelection->GetSelectedEndRow() ) );
	}

	if ( nRow != pDoc->GetLineCount() )
	{
		ResetHScroll();
	}

	// ここでDrawCaret()すると描画が全くされない。
	// キャレットの描画はDrawPage()内でする。

	if( bBreak )
	{
		GetDocument()->SetMainView( this );
		return( TRUE );
	}
	else
	{
		return( FALSE );
	}
}


/*-----------------------------------------------------------------------------
[名称]	キャレット位置取得
[機能]	Pixel座標からキャレット位置を取得する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CShitarabianView::PixelToCaret(
	CPoint		posCursor,		// I  :指定座標 [Doc上Pixel座標] (-) :-
	long*		pidxRow,		//   O:行 [-] (-) :-
	long*		pidxColumn		//   O:カラム [-] (-) :-
)
{
	CShitarabianDoc*	pDoc = GetDocument();
	int idxRow = pDoc->GetCaretRow();
	int idxColumn = pDoc->GetCaretColumn();

	// 行位置計算
	{
		// EOFより下をクリックしたときにはEOFにカーソルをやる
		CEditDrawer*		pDrawer = GetDrawer();
		idxRow = min( pDrawer->PixelToCaretRow( posCursor.y, pDoc ), pDoc->GetLineCount()-1 );
		idxRow = max( 0, idxRow );
	}

	CEmphasisLine*	pEmphasisLine = pDoc->GetEmphasisLine( idxRow );
	if ( pEmphasisLine != NULL )
	{
		// カラム位置計算
		idxColumn = pEmphasisLine->PixelToCaretColumnZoomed( posCursor.x );
	}

	*pidxRow = idxRow;
	*pidxColumn = idxColumn;
}


/*-----------------------------------------------------------------------------
[名称]	ポップアップメニュー表示
[機能]	Normal編集時の右クリックポップアップメニュー表示。
[戻値]	なし
[備考]	キャレット位置がURLやファイル名ならリンク用メニュー項目を用意する。
-----------------------------------------------------------------------------*/
void CShitarabianView::NormalPopUp(
	CPoint		posCursor		// I  :指定座標 [クライアントPixel座標] (-)
)
{
	CShitarabianDoc*	pDoc = GetDocument();

	// カーソル座標からカラム位置割り出し
	long	iClickRow;
	long	iClickColumn;
	{
		CPoint posScreen;
		posScreen = ScrollBoxToPixel( posCursor );

		PixelToCaret(
			posScreen,
			&iClickRow,
			&iClickColumn
		);
	}

	// リンク判別
	CString		strLink;		// リンク名称 [ファイル名など] (-)
	ELinkType	eLink;			// リンク動作種類 [-] (-)
	{
		long	idxStartColumn = 0;
		long	nColumn = 0;
		long	idxRow = 0;

		BOOL		bExist;
		CSelection*	pSelection = pDoc->GetSelection();
		if ( pSelection->IsSelected() )
		{
			strLink = pSelection->GetSelectedText();
			eLink = LinkOpenAction;
			idxStartColumn = pSelection->GetSelectedStartColumn();
			nColumn = ::StringToColumn( pSelection->GetSelectedText() );
			idxRow = pSelection->GetSelectedStartRow();
			bExist = TRUE;
		}
		else
		{
			bExist = CLinkDefine::GetInstance()->IsLink(
				iClickRow,
				iClickColumn,
				&strLink,
				&eLink,
				&idxStartColumn,
				&nColumn
			);
			idxRow = iClickRow;
		}

		// 対象リンクの登録
		TLinkTarget	Link;
		Link.eLinkType = eLink;
		Link.strTarget = ::DeQuoteString( strLink );
		Link.idxRow = idxRow;
		Link.idxColumn = idxStartColumn;
		Link.nColumn = nColumn;
		Link.bEnable = bExist;
		CLinkDefine::GetInstance()->TargetLink(
			Link
		);
	}

	// リンク文字列が長すぎれば適当に削る
	CString	strLinkMes;
	{
		long	nByte = ::CaretColumnToByteColumn( strLink, 64 );	// ←please! 適当な閾値
		if ( strLink.GetLength() > nByte )
		{
			strLinkMes = strLink.Left( nByte ) + "...";
		}
		else
		{
			strLinkMes = strLink;
		}
	}

	// メニューのロード
	CMenu menu;
	VERIFY(menu.LoadMenu(IDR_POPUP));

	// ポップアップメニュー項目文字列の変更
	CMenu* pPopup = menu.GetSubMenu(0);
	{
		// 〜を開く
		CString		strMenuLink;
		if ( strLink.IsEmpty() )
		{
			strMenuLink.Format( "ﾄﾞｷｭﾒﾝﾄを開く" );
		}
		else
		{
			// メニュー項目の変更
			switch( eLink )
			{
			case LinkOpenAction:		// ShellExecute "open"アクションで開く
				strMenuLink.Format( "\"%s\"を開く", strLinkMes );
				break;
			case LinkTxt:				// したらびあんで新規ウィンドウを開く
				strMenuLink.Format( "\"%s\"をしたらびあんで開く", strLinkMes );
				break;
			case LinkJump:				// リンク行へジャンプ
				strMenuLink.Format( "\"%s\"にジャンプ", strLinkMes );
				break;
			default:
				break;
			}
		}
		ASSERT(pPopup != NULL);
		pPopup->DeleteMenu( IDM_MAGIC_LINK, MF_BYCOMMAND );
		pPopup->InsertMenu(
			0,
			MF_BYPOSITION | MF_STRING,
			IDM_MAGIC_LINK,
			strMenuLink
		);

		// 〜を選択
		CString		strMenuSelect;
		if ( strLink.IsEmpty() )
		{
			strMenuSelect.Format( "文字列を選択" );
		}
		else
		{
			// メニュー項目の変更
			strMenuSelect.Format( "\"%s\"を選択", strLinkMes );
		}
		ASSERT(pPopup != NULL);
		pPopup->DeleteMenu( IDM_MAGIC_SELECT, MF_BYCOMMAND );
		pPopup->InsertMenu(
			1,
			MF_BYPOSITION | MF_STRING,
			IDM_MAGIC_SELECT,
			strMenuSelect
		);

		// 〜をコピー
		CString		strMenuCopy;
		if ( strLink.IsEmpty() )
		{
			strMenuCopy.Format( "文字列をコピー" );
		}
		else
		{
			// メニュー項目の変更
			strMenuCopy.Format( "\"%s\"をコピー", strLinkMes );
		}
		ASSERT(pPopup != NULL);
		pPopup->DeleteMenu( IDM_MAGIC_COPY, MF_BYCOMMAND );
		pPopup->InsertMenu(
			2,
			MF_BYPOSITION | MF_STRING,
			IDM_MAGIC_COPY,
			strMenuCopy
		);

	}

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


/*-----------------------------------------------------------------------------
[名称]	単語選択
[機能]	キャレット位置の単語全体を選択する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CShitarabianView::SelectToken()
{

	CShitarabianDoc*	pDoc = GetDocument();
	CSelection*			pSelection = pDoc->GetSelection();

	int idxRow = pDoc->GetCaretRow();
	int idxColumn = pDoc->GetCaretColumn();

	CString*	pstrLine = pDoc->GetLine( idxRow );

	CArray< TToken, TToken& >	aTokenz;
	CTokenReader::StringToCharTypez(
		*pstrLine,
		&aTokenz
	);

	int		idxToken = CTokenReader::TokenIndex(
		aTokenz,
		idxColumn
	);
	if ( idxToken != InvalidTokenIndex )
	{
		pSelection->SetSelectedStart(
			idxRow,
			aTokenz[ idxToken ].idxStartColumn
		);
		pSelection->SetSelectedEnd(
			idxRow,
			aTokenz[ idxToken ].idxStartColumn + aTokenz[ idxToken ].nColumn
		);
	}
}


/*-----------------------------------------------------------------------------
[名称]	いきなり選択
[機能]	キャレット位置の単語全体を選択する。
[戻値]	なし
[備考]	ポイント位置によって、左余白なら行全体選択する。
		でなければキャレット位置の単語を選択する。
-----------------------------------------------------------------------------*/
void CShitarabianView::SelectMagicRod(
	CPoint	ptCursor			// [クライアント座標]
)
{
	CShitarabianDoc*	pDoc = GetDocument();
	CSelection*			pSelection = pDoc->GetSelection();

	{
		int idxRow = pDoc->GetCaretRow();

		CString*	pstrLine = pDoc->GetLine( idxRow );
		BOOL	bLineAll;
		{
			bLineAll = ptCursor.x < CGeneralSetting::GetInstance()->GetLeftMargin();
		}
		if ( !bLineAll )
		{
			// 単語の選択
			SelectToken();
		}
		else
		{
			// 行全体を選択する
			pSelection->SetSelectedStart(
				idxRow,
				0
			);
			pSelection->SetSelectedEnd(
				idxRow,
				::StringToColumn( *pstrLine )
			);
		}
	}
}


/*-----------------------------------------------------------------------------
[名称]	いきなり検索
[機能]	キャレット位置の単語を検索する。
[戻値]	なし
[備考]	ポイント位置によって、左余白なら行全体選択する。
		でなければキャレット位置の単語を自動選択する。
-----------------------------------------------------------------------------*/
void CShitarabianView::FindMagicRod()
{
	CShitarabianDoc*	pDoc = GetDocument();
	CSelection*			pSelection = pDoc->GetSelection();

	// 選択範囲確認
	if ( !pSelection->IsSelected() )
	{
		// 選択範囲がなければ単語を自動選択
		SelectToken();
	}

	// 選択文字列を検索対象にし、検索する
	CString		strSelect;
	strSelect = pSelection->GetSelectedText();
	if ( !strSelect.IsEmpty() )
	{
		// 検索対象登録
		::GetMainFrame()->AddSubString( strSelect, NULL );

		// 検索
		::GetMainFrame()->m_dlgFinder.FindNext();
	}
}