////////////////////////////////////////////////////////////////////////////
// CTaEditShell クラスのインプリメンテーション
//
////////////////////////////////////////////////////////////////////////////

#include "TaEditShell.h"
#include "TaEditDraw.h"
#include "TaEditVScroll.h"
#include "TaEditHScroll.h"
#include "lang/TxtColorMgr.h"
#include "Thread.h"
#include "CmdEnv.h"
#include "CompoundStr.h"
#include "Consruction.h"
#include "ProcStart.h"
#include <locale.h>
#include <sys/wait.h>


////////////////////////////////////////////////////////////////////////////
// 構築/破棄
////////////////////////////////////////////////////////////////////////////

CTaEditShell::CTaEditShell() :
	pLangConfig( NULL ),
	IconPixmap( NULL ),
	CursorTimerID( 0 ),
	pConstruction( NULL )
{
	//foo.start();
}

CTaEditShell::~CTaEditShell()
{

}

////////////////////////////////////////////////////////////////////////////
// メソッド
////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
// 初期化

// 構築されるとき呼ばれる （注 OnCreateより早い）
void CTaEditShell::create( Display *display, char *app_name, int app_argc, char **app_argv, char *app_class_name )
{
	// コマンドラインのオプションを解釈する
	m_CmdOption.SetOption( app_argc, app_argv );

	CAppShell::create( display, app_name, app_argc, app_argv, app_class_name );
}

// 通称：構築
void CTaEditShell::OnCreate( Widget argWgt, XtPointer client_data )
{
	int ac = 0;
	Arg al[20];
	Widget wWgt;
	CCompoundStr TitleStr( "Syuhitu" );
	XtAppContext appContext = XtWidgetToApplicationContext( m_TaEditShell );

	// 設定情報オブジェクトを構築・情報を取得
	pConfigInfo = new CConfigInfo( argWgt );
	if ( !pConfigInfo ) {
		fprintf( stderr, "Syuhitu : Out of memory.\n" );
		ExitProcess( 1 );
	}
	pConfigInfo->Initialize();

	// 言語別情報オブジェクトを構築する
	pLangConfig = new NLangExt::CLangConfig( pConfigInfo );

	// メッセージボックス管理オブジェクトの初期化
	MsgBoxMgr.Initialize( argWgt, (*pConfigInfo) );

	ResetTitle();
	theDocument.Initialize();

	// 左右のパディングの幅を取得
	unsigned int LeftPadding = pConfigInfo->GetLeftPadding();
	unsigned int RightPadding = pConfigInfo->GetRightPadding();
	m_HScroll->SetPadding( LeftPadding, RightPadding );

	// ドローウィジットを管理するクラスを、
	// スクロールバーのイベントハンドラとして登録。
	m_HScroll->SetEventHandler( m_Draw );
	m_VScroll->SetEventHandler( m_Draw );

	// ドローウィジットに、スクロールバーの管理オブジェクトを通知
	m_Draw->SetScrollMgr( m_HScroll, m_VScroll );

	// タイマを設定
	CursorTimerID = XtAppAddTimeOut( appContext, 500, CTaEditShell::OnTimer, this );

	// 自動保存用のタイマを設定
	if ( pConfigInfo->GetAutoSaveInterval() > 0 )
		XtAppAddTimeOut( appContext, pConfigInfo->GetAutoSaveInterval() * 1000,
			CTaEditShell::OnAutoSaveTimer, this );

	// ウインドウが消去されるときのデフォルトの処理を停止する
	ac = 0;
	XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING ); ac++;
	XtSetValues( m_TaEditShell, al, ac );

	// プロセスが起動されるときのコマンドを実行
	const string &rProcUpScript = pConfigInfo->RefProcUpScript();
	if ( !rProcUpScript.empty() ) {
		if ( system( rProcUpScript.c_str() ) < 0 )
			ProcErrorMsg( pConfigInfo->RefRunScriptErrnoMsg( errno ) );
	}

	// アイコンを設定
	if ( !pConfigInfo->RefIconImageName().empty() ) {
		// アイコン用イメージを読み込む
		const string& rIconImageName = pConfigInfo->RefIconImageName();
		Display *pDisplay = XtDisplay( m_TaEditShell );
		Window window = XtWindow( m_TaEditShell );
		Screen *screen = XtScreen( m_TaEditShell );
		Pixel black = BlackPixelOfScreen( screen );
		Pixel white = WhitePixelOfScreen( screen );
		IconPixmap = XmGetPixmap( screen, const_cast< char* >( rIconImageName.c_str() ), black, white );
		if ( IconPixmap != XmUNSPECIFIED_PIXMAP ) {
			// イメージの読み込みに成功したら、アイコンを設定する
			ac = 0;
			XtSetArg( al[ac], XmNiconPixmap, IconPixmap ); ac++;
			XtSetValues( m_TaEditShell, al, ac );
		}
		else
			IconPixmap = NULL;
	}
}

// 初めて画面に表示されるとき呼ばれる
void CTaEditShell::OnFirstExpose()
{
	int ac = 0;
	Arg al[20];
	CErrorBool r;
	Dimension x, y;
	int sw, sh;	// スクリーンの幅
	int cw, ch;	// ウインドウの幅と高さの設定

	if ( m_CmdOption.IsConstructionMode() )
		// コンストラクション・モードにする
		ProcErrorMsg( SetConstructionMode() );
	else
		SetCSModeMenu();	// メニュー表示だけ設定する

	// プラグインの初期化
	r = m_Plugin.ConfigurePlugin( pConfigInfo->RefPluginConfigFileName(), m_cascadeTool, m_menuTool, m_Draw );
	ProcErrorMsg( r );

	// 現在のウインドウの位置を取得
	XtSetArg(al[ac], XmNx, &x ); ac++;
	XtSetArg(al[ac], XmNy, &y ); ac++;
	XtGetValues( m_TaEditShell, al, ac );

	// スクリーンのサイズを取得
	sw = WidthOfScreen( XtScreen( m_TaEditShell ) );
	sh = HeightOfScreen( XtScreen( m_TaEditShell ) );

	// 設定された幅と高さを取得
	cw = pConfigInfo->GetWindowWidth();
	ch = pConfigInfo->GetWindowHeight();

	// ウインドウの位置・幅・高さを設定
	if ( cw < 100 ) cw = 100;
	if ( ch < 100 ) ch = 100;
	if ( cw >= sw - 50 ) cw = sw - 50;
	if ( ch >= sh - 50 ) ch = sh - 50;
	if ( x + cw >= sw ) x = 0;
	if ( y + ch >= sh ) y = 0;
	if ( x < 0 ) x = 0;
	if ( y < 0 ) y = 0;
	ac = 0;
	XtSetArg(al[ac], XmNwidth, cw ); ac++;
	XtSetArg(al[ac], XmNheight, ch ); ac++;
	XtSetArg(al[ac], XmNx, x ); ac++;
	XtSetArg(al[ac], XmNy, y ); ac++;
	XtSetValues( m_TaEditShell, al, ac );
}

////////////////////////////////////////////////////////////////////////////
// メニューのイベントハンドラ

// 名前を付けて保存
void CTaEditShell::OnWriteFile( Widget argWgt, XtPointer client_data )
{
	WriteFileProcedure();
}

// 上書き保存
void CTaEditShell::OnSaveFile( Widget argWgt, XtPointer client_data )
{
	SaveFileProcedure();
}

// 開く
void CTaEditShell::OnOpenFile( Widget argWgt, XtPointer client_data )
{
	OpenFile( "" );
}

// 新規作成
void CTaEditShell::OnNewFile( Widget argWgt, XtPointer client_data )
{
	// 更新の保存の有無を確認
	if ( !MakeSure_FileSave() ) return ;

	// サーバに、新規作成が行われることを通知する
	if ( pConstruction ) {
		bool cf = false;
		CErrorBool sr = pConstruction->NewFile( &cf );
		if ( !sr ) ProcErrorMsg( sr );
		if ( cf ) return ;
	}

	// 今までのファイルが破棄されるため、
	// ファイルが閉じられるときのコマンドを実行する。
	if ( !RunFileCloseScript() ) return ;

	// 初期化
	theDocument.Initialize();
	ResetTitle();

	// ビューの表示を更新
	m_Draw->OnReadDocument();
}

// 終了メニュー
void CTaEditShell::OnCloseAppMenu( Widget argWgt, XtPointer client_data )
{
	OnClose( argWgt, client_data );	// 終了する
}

// Textモードに変更
void CTaEditShell::SetFileTypeTXT( Widget argWgt, XtPointer client_data )
{
	if ( theDocument.SetTxtColorMgr( LANGTYPE_TEXT ) )
		m_Draw->OnReadDocument();
}

// C/C++モードに変更
void CTaEditShell::SetFileTypeCPP( Widget argWgt, XtPointer client_data )
{
	if ( theDocument.SetTxtColorMgr( LANGTYPE_CPP ) )
		m_Draw->OnReadDocument();
}

// Javaモードに変更
void CTaEditShell::SetFileTypeJAVA( Widget argWgt, XtPointer client_data )
{
	if ( theDocument.SetTxtColorMgr( LANGTYPE_JAVA ) )
		m_Draw->OnReadDocument();
}

// COBOLモードに変更
void CTaEditShell::SetFileTypeCBL( Widget argWgt, XtPointer client_data )
{
	if ( theDocument.SetTxtColorMgr( LANGTYPE_CBL ) )
		m_Draw->OnReadDocument();
}

// VBScriptモードに変更
void CTaEditShell::SetFileTypeVBS( Widget argWgt, XtPointer client_data )
{
	if ( theDocument.SetTxtColorMgr( LANGTYPE_VBS ) )
		m_Draw->OnReadDocument();
}

// JavaScriptモードに変更
void CTaEditShell::SetFileTypeJS( Widget argWgt, XtPointer client_data )
{
	if ( theDocument.SetTxtColorMgr( LANGTYPE_JS ) )
		m_Draw->OnReadDocument();
}

// C#モードに変更
void CTaEditShell::SetFileTypeCS( Widget argWgt, XtPointer client_data )
{
	if ( theDocument.SetTxtColorMgr( LANGTYPE_CS ) )
		m_Draw->OnReadDocument();
}

// コンストラクションモードに変更
void CTaEditShell::OnConstruction( Widget argWgt, XtPointer client_data )
{
	int ac = 0;
	Arg al[2];
	Boolean flg;

	// トグルの値を取得
	ac = 0;
	XtSetArg( al[ac], XmNset, &flg ); ac++;
	XtGetValues( m_menuCSModeConstruction, al, ac );

	// トグルがoffにされたときは何もしない
	if ( !flg ) return ;

	// コンストラクション・モードへ変更
	ProcErrorMsg( SetConstructionMode() );
}

// スタンドアロンモードに変更
void CTaEditShell::OnStandalone( Widget argWgt, XtPointer client_data )
{
	int ac = 0;
	Arg al[2];
	Boolean flg;

	// トグルの値を取得
	ac = 0;
	XtSetArg( al[ac], XmNset, &flg ); ac++;
	XtGetValues( m_menuCSModeStandalone, al, ac );

	// トグルがoffにされたときは何もしない
	if ( !flg ) return ;

	// スタンドアロン・モードへ変更
	ProcErrorMsg( SetStandaloneMode() );
}

// 編集メニューが表示される
void CTaEditShell::OnEditMenuShow( Widget argWgt, XtPointer client_data )
{
}

// リドゥメニュー
void CTaEditShell::OnEditRedo( Widget argWgt, XtPointer client_data )
{
	if ( !theDocument.EnableRedo() )
		return ;
	m_Draw->GetTextEditor()->Redo();
}

// アンドゥメニュー
void CTaEditShell::OnEditUndo( Widget argWgt, XtPointer client_data )
{
	// メニューは無効になっても、Ctrl+Zにより呼ばれる可能性がある
	if ( !theDocument.EnableUndo() ) return ;
	m_Draw->GetTextEditor()->Undo();
}

// 切り取りメニュー
void CTaEditShell::OnEditCut( Widget argWgt, XtPointer client_data )
{
	m_Draw->GetTextEditor()->Cut();
}

// コピーメニュー
void CTaEditShell::OnEditCopy( Widget argWgt, XtPointer client_data )
{
	m_Draw->GetTextEditor()->Copy();
}

// 張り付けメニュー
void CTaEditShell::OnEditPaste( Widget argWgt, XtPointer client_data )
{
	m_Draw->GetTextEditor()->Paste();
}

// 全て選択メニュー
void CTaEditShell::OnEditFullSelect( Widget argWgt, XtPointer client_data )
{
	m_Draw->GetTextEditor()->FullSelect();
}

// 検索・置換メニュー
void CTaEditShell::OnEditFind( Widget argWgt, XtPointer client_data )
{
	m_FindShell->ShowDlg();
}

// 指定行へ移動
void CTaEditShell::OnEditMoveto( Widget argWgt, XtPointer client_data )
{
	m_Draw->GetTextEditor()->OnMoveto();
}

// ウインドウが閉じられる
void CTaEditShell::OnClose( Widget argWgt, XtPointer client_data )
{
	int r = 0;

	// Shellが無効になっているとき（例えばメッセージボックスを表示している時）は、
	// 終了処理を行わない。
	if ( !XtIsSensitive( m_TaEditShell ) ) return ;

	// ファイルの保存状況を確認してから終了する
	if ( MakeSure_FileSave() ) {
		// ファイルが閉じられるときのコマンドを実行する。
		RunFileCloseScript();

		// プロセスが終了するときに実行するコマンドを実行する。
		const string &rProcDownScript = pConfigInfo->RefProcDownScript();

		if ( !rProcDownScript.empty() ) {
			CCmdEnv cmdenv;
			r = cmdenv.Run( rProcDownScript.c_str() );
			if ( r < 0 )
				ProcErrorMsg( pConfigInfo->RefRunScriptErrnoMsg( errno ) );
		}

		// とりあえず、アイコン用イメージを解放する
		if ( IconPixmap )
			XmDestroyPixmap( XtScreen( m_TaEditShell ), IconPixmap );

		// 終了する
		ExitProcess( r );
	}
}

// ドラッグアンドドロップされたファイルを開く
void CTaEditShell::OpenDnDFiles( int cnt, char **pFileName )
{
	assert( this );

	int idx;
	int r;
	int NewWndLine = pConfigInfo->GetLineNumberOrigin();

	// Shellが無効になっているとき（例えばメッセージボックスを表示している時）は、
	// ドラッグアンドドロップを受け入れない。
	if ( !XtIsSensitive( m_TaEditShell ) ) return ;

	if ( cnt <= 0 ) return ;

	if ( pConfigInfo->GetDropFileOpenMethod() == DFOM_CURRENT_WINDOW ) {
		// 最初のファイルを、カレントのウインドウで開く場合
		OpenFile( pFileName[0] );	// 最初のファイルを開く
		idx = 1;
	}
	else
		idx = 0;

	for (; idx < cnt; idx++ ) {
		// 以降のファイルは、設定に関わらず新しいウインドウで開く
		if ( !OpenFileInNewWindow( pFileName[idx], NewWndLine ) )
			return ;
	}
}

////////////////////////////////////////////////////////////////////////////
// メッセージボックスの処理

// 情報
void CTaEditShell::ShowInformationMsgBox( const CCompoundStr &rStr ) const
{
	MsgBoxMgr.ShowInformationMsgBox( rStr );
}

// 質問
int CTaEditShell::ShowQuestionMsgBox( const CCompoundStr &rStr, bool ShowCancel ) const
{
	return MsgBoxMgr.ShowQuestionMsgBox( rStr, ShowCancel );
}

// エラー
void CTaEditShell::ShowErrorMsgBox( const CCompoundStr &rStr ) const
{
	MsgBoxMgr.ShowErrorMsgBox( rStr );
}

////////////////////////////////////////////////////////////////////////////
// ファイル入出力処理

// ファイルを保存する必要があるか否か確認する
// 処理を中止する場合は偽を返す。
bool CTaEditShell::MakeSure_FileSave()
{
	if ( !theDocument.GetIsModify() )
		return true;	// 保存する必要はない

	// 確認する
	int r = ShowQuestionMsgBox( pConfigInfo->RefPreservationCheckMsg(), true );
	assert( r >= 1 && r <= 3 );

	switch ( r ) {
	case 1:	// Yes
		return SaveFileProcedure();	// 上書き保存する。
	case 2:	// No
		return true;	// 保存する必要はない
	case 3:	// Cancel
		return false;	// 処理を中止する
	}
	return true;
}

// ファイルの上書き保存の処理
bool CTaEditShell::SaveFileProcedure()
{
	bool ColChanged;
	CErrorBool r;

	if ( theDocument.GetFileName() == "" ) {
		// 名前が付いていない場合は、「名前を付けて保存」の処理を行う。
		return WriteFileProcedure();
	}

	// ファイル書き込み前に実行するコマンドを実行する
	if ( !RunFileBeforeWriteScript( theDocument.GetFileName() ) );

	string OldFileName = theDocument.GetFileName();	// 出力される前のファイル名を待避しておく

	// 出力する
	r = theDocument.OnSaveDocument( theDocument.GetFileName(), &ColChanged );
	if ( !r ) {
		ProcErrorMsg( r );
		return false;
	}

	// 色情報が更新されたら、ビューにそのことを通知する
	if ( ColChanged ) m_Draw->OnReadDocument();

	// ファイルを書き込むときのコマンドを実行
	RunFileWriteScript( OldFileName );
	return true;
}

// ファイルに名前を付けて保存する処理
bool CTaEditShell::WriteFileProcedure()
{
	bool ColChanged;
	CErrorBool r;
	string SelectedFile;
	string OldFileName = theDocument.GetFileName();	// 出力される前のファイル名を待避しておく

	m_FileSelectShell->SetDlgTitle( pConfigInfo->RefFileSaveDlgTitle() );

	// ダイアログを表示
	if ( !m_FileSelectShell->ShowDlg( &SelectedFile ) )
		return false;

	// サーバに、名前を付けて保存が行われることを通知する
	if ( pConstruction ) {
		bool cf = false;
		CErrorBool sr = pConstruction->WriteFile( SelectedFile, &cf );
		if ( !sr ) ProcErrorMsg( sr );
		if ( cf ) return true;
	}

	// ファイル読み込み前のコマンドを実行する
	if ( !RunFileBeforeWriteScript( SelectedFile ) ) return false;

	// 保存
	r = theDocument.OnSaveDocument( SelectedFile, &ColChanged );
	if ( !r ) {
		ProcErrorMsg( r );
		return false;
	}

	// 保存できたらタイトルを設定する。
	ResetTitle();

	// ファイルを書き込み後のコマンドを実行
	RunFileWriteScript( OldFileName );

	// ファイル名の変更とともに、
	// 言語依存情報オブジェクトが更新される可能性があるため。
	if ( ColChanged )m_Draw->OnReadDocument();

	return true;
}

// ファイルを開く
// ただし、ファイル名が指定されなかった場合は、ダイアログを表示してファイル名を取得する
bool CTaEditShell::OpenFile( const string &rFileName, enumLANGTYPE LangType )
{
	string SelectedFile;
	bool IsChanged = false;

	// 更新の保存の有無を確認
	if ( !MakeSure_FileSave() ) return false;

	if ( rFileName.empty() ) {
		m_FileSelectShell->SetDlgTitle( pConfigInfo->RefFileOpenDlgTitle() );

		// ダイアログを表示
		if ( !m_FileSelectShell->ShowDlg( &SelectedFile ) )
			return false;
	}
	else
		SelectedFile = rFileName;

	// 新しいファイルを開くことをサーバに通知する
	if ( pConstruction ) {
		bool cf = false;
		CErrorBool sr = pConstruction->OpenFile( SelectedFile, &cf );
		if ( !sr ) ProcErrorMsg( sr );
		if ( cf ) return true;
	}

	// 今までのファイルが破棄されるため、ファイルが閉じられるときのコマンドを実行する。
	if ( !RunFileCloseScript() ) return false;

	// ファイルを読み込むときのコマンドを実行
	if ( !RunFileReadScript( SelectedFile ) ) return false;

	// ファイル開く
	CErrorBool r = theDocument.OnOpenDocument( SelectedFile, &IsChanged, LangType );

	// 正常に読み込めたら、ファイル読み込み後に実行するコマンドを実行する。
	if ( r ) RunFileAfterReadScript( SelectedFile );

	// 何らかの理由でドキュメントの内容に変化がなければ、このまま処理を終了する。
	if ( !IsChanged ) {
		ProcErrorMsg( r );
		return false;
	}

	// ファイルを読み込んだらタイトルを設定して、ビューを更新する。
	// （ドキュメントに変更があった場合は、
	// 　下記の処理が終了するまでメッセージボックスを表示してはいけない）
	ResetTitle();
	m_Draw->OnReadDocument();

	// 必要に応じてメッセージを表示する
	return ProcErrorMsg( r );
}

// ファイルが読み込まれるときのコマンドを実行
bool CTaEditShell::RunFileReadScript( const string& rFileName ) const
{
	const string &rScr = pConfigInfo->RefFileReadScript();
	CCmdEnv cmdenv;
	if ( rScr.empty() ) return true;

	// 環境変数を設定
	cmdenv.AddEnvironment( "TAEDIT_FILE_NAME", rFileName.c_str() );

	// コマンドを実行
	int r = cmdenv.Run( rScr.c_str() );

	// 負の値が返ってきた場合は、エラーとする。
	if ( r < 0 ) {
		ProcErrorMsg( pConfigInfo->RefRunScriptErrnoMsg( errno ) );
		return true;	// とりあえずこのまま進める
	}

	// スクリプトの実行結果が正の場合は読み込みをキャンセルする
	if ( r >= 1 ) {
		if ( pConfigInfo->GetShowCancelOpenMsg() )
			ProcErrorMsg( pConfigInfo->RefRunScriptCancelOpenMsg() );
		return false;
	}
	return true;
}

// ファイルが読み込まれたときのコマンドを実行
bool CTaEditShell::RunFileAfterReadScript( const string& rFileName ) const
{
	const string &rScr = pConfigInfo->RefFileAfterReadScript();
	CCmdEnv cmdenv;
	if ( rScr.empty() ) return true;

	// 環境変数を設定
	cmdenv.AddEnvironment( "TAEDIT_FILE_NAME",rFileName.c_str() );

	// コマンドを実行
	int r = cmdenv.Run( rScr.c_str() );

	// 負の値が返ってきた場合は、エラーとする。
	if ( r >= 0 ) return true;
	ProcErrorMsg( pConfigInfo->RefRunScriptErrnoMsg( errno ) );
	return false;
}

// ファイルが閉じられるときのコマンドを実行
bool CTaEditShell::RunFileCloseScript() const
{
	const string &rScr = pConfigInfo->RefFileCloseScript();
	CCmdEnv cmdenv;
	if ( rScr.empty() ) return true;

	// 環境変数を設定
	cmdenv.AddEnvironment( "TAEDIT_FILE_NAME", theDocument.GetFileName().c_str() );
	cmdenv.AddEnvironment( "TAEDIT_FILE_MODIFIED", theDocument.GetIsModify() ? "TRUE" : "FALSE" );

	// コマンドを実行
	int r = cmdenv.Run( rScr.c_str() );

	// 負の値が返ってきた場合は、エラーとする。
	if ( r >= 0 ) return true;

	ProcErrorMsg( pConfigInfo->RefRunScriptErrnoMsg( errno ) );
	return false;
}

// ファイルが出力されるときのコマンドを実行
bool CTaEditShell::RunFileBeforeWriteScript( const string& NewFileName ) const
{
	const string &rScr = pConfigInfo->RefFileBeforeWriteScript();
	CCmdEnv cmdenv;
	if ( rScr.empty() ) return true;

	// 環境変数を設定
	cmdenv.AddEnvironment( "TAEDIT_OLD_FILE_NAME", theDocument.GetFileName().c_str() );
	cmdenv.AddEnvironment( "TAEDIT_NEW_FILE_NAME", NewFileName.c_str() );

	// コマンドを実行
	int r = cmdenv.Run( rScr.c_str() );

	// 負の値が返ってきた場合は、エラーとする。
	if ( r < 0 ){
		ProcErrorMsg( pConfigInfo->RefRunScriptErrnoMsg( errno ) );
		return true;	// とりあえず続行するものとする
	}

	// スクリプトの実行結果が正の場合は書き込みをキャンセルする
	if ( r >= 1 ) {
		if ( pConfigInfo->GetShowCancelSaveMsg() )
			ProcErrorMsg( pConfigInfo->RefRunScriptCancelSaveMsg() );
		return false;
	}
	return true;
}

// ファイルが出力されたときのコマンドを実行
bool CTaEditShell::RunFileWriteScript( const string& OldFileName ) const
{
	const string &rScr = pConfigInfo->RefFileWriteScript();
	CCmdEnv cmdenv;
	if ( rScr.empty() ) return true;

	// 環境変数を設定
	cmdenv.AddEnvironment( "TAEDIT_OLD_FILE_NAME", OldFileName.c_str() );
	cmdenv.AddEnvironment( "TAEDIT_NEW_FILE_NAME", theDocument.GetFileName().c_str() );

	// コマンドを実行
	int r = cmdenv.Run( rScr.c_str() );

	// 負の値が返ってきた場合は、エラーとする。
	if ( r >= 0 ) return true;
	ProcErrorMsg( pConfigInfo->RefRunScriptErrnoMsg( errno ) );
	return false;
}


////////////////////////////////////////////////////////////////////////////
// その他

// ドキュメントオブジェクトの参照
CTaEditDoc *CTaEditShell::GetDocument()
{
	return &theDocument;
}

// 編集オブジェクトを取得
VClsPtr< CTextEdit > CTaEditShell::GetTextEditor()
{
	return m_Draw->GetTextEditor();
}

// コマンド行オプションオブジェクトの参照
const CCmdOption& CTaEditShell::GetCmdOption() const
{
	return m_CmdOption;
}

// ウインドウのタイトルを設定
void CTaEditShell::SetWindowTitle( const string &Title ) const
{
	Arg al[3];
	int ac = 0;
	string w;

	w = pConfigInfo->RefAppTitle();
	w += " : ";
	w += Title;
	if ( theDocument.GetIsModify() ) {
		w += " : ";
		w += pConfigInfo->RefModifiedSignStr();
	}
	XtSetArg(al[ac], XmNtitle, w.c_str() ); ac++;
	XtSetArg(al[ac], XmNiconName, Title.c_str() ); ac++;
	XtSetValues( m_TaEditShell, al, ac );
}

// ファイルのパス名からファイル名のみを抽出
string CTaEditShell::GetFileNameFromFullPathName( const string& FullPathName ) const
{
	if ( FullPathName.empty() ) return "";

	// 実はFullPathNameは必ずしもフルパスとは限らない
	if ( FullPathName[0] != '/' ) return FullPathName;

	int idx = FullPathName.rfind( "/" );	// テキストの末尾から区切り記号を検索
	if ( idx < 0 || idx - 1 >= FullPathName.length() )
		return "";	// 見つからなかった

	return FullPathName.substr( idx + 1 );
}

// タイマイベントのエントリ用関数
void CTaEditShell::OnTimer( XtPointer client_data, XtIntervalId *timer )
{
	reinterpret_cast< CTaEditShell* >( client_data )->OnTimer();
}

// タイマイベント
void CTaEditShell::OnTimer()
{
	XtAppContext appContext = XtWidgetToApplicationContext( m_TaEditShell );

	// ドローウィジットに、タイマイベントを伝える。
	m_Draw->OnTimer();

	// 次のタイマを設定する。
	CursorTimerID = XtAppAddTimeOut( appContext, 500, CTaEditShell::OnTimer, this );
}

// 設定情報オブジェクトの参照
VClsPtr< CConfigInfo > CTaEditShell::GetConfigInfo()
{
	return pConfigInfo;
}

// コピー・切り取りメニューの有効・無効を設定する
void CTaEditShell::SetEnableCopyPasteMenu( bool flg ) const
{
	XtSetSensitive( m_menuEditCut, flg ? True : False );
	XtSetSensitive( m_menuEditCopy, flg ? True : False );
}

// Undoメニューの有効・無効を設定する
void CTaEditShell::SetEnableUndoMenu( bool flg ) const
{
	XtSetSensitive( m_menuEditUndo, flg ? True : False );
}

// Redoメニューの有効・無効を設定する
void CTaEditShell::SetEnableRedoMenu( bool flg ) const
{
	XtSetSensitive( m_menuEditRedo, flg ? True : False );
}

// コピー・切り取りメニューの有効・無効を取得する
bool CTaEditShell::GetEnableCopyPasteMenu() const
{
	return XtIsSensitive( m_menuEditCut ) && XtIsSensitive( m_menuEditCopy );
}

// Undoメニューの有効・無効を取得する
bool CTaEditShell::GetEnableUndoMenu() const
{
	return XtIsSensitive( m_menuEditUndo );
}

// Redoメニューの有効・無効を取得する
bool CTaEditShell::GetEnableRedoMenu() const
{
	return XtIsSensitive( m_menuEditRedo );
}

// 必要に応じてエラーメッセージを表示する
bool CTaEditShell::ProcErrorMsg( CErrorBool r ) const
{
	if ( r ) return true;	// メッセージを表示する必要がない
	ShowErrorMsgBox( r );	// メッセージを表示する
	return false;
}

// 言語別情報オブジェクトを取得
const NLangExt::CLangConfig* CTaEditShell::GetLangConfig() const
{
	return pLangConfig;
}

// プラグイン管理オブジェクトを参照
CPlugin& CTaEditShell::RefPluginMgr()
{
	return m_Plugin;
}

// 新しいウインドウを開く
bool CTaEditShell::OpenFileInNewWindow( const char *pfile, int Line )
{
	CProcStart procStart;
	string ArgFileName;
	string ArgLine;
	char buf[15];

	if ( pConstruction ) {
		// コンストラクション・モードの場合は、主筆の起動をサーバに依頼する
		bool ComplateFlg = false;
		CErrorBool r = pConstruction->OpenFileWithNewWnd( pfile, Line, &ComplateFlg );
		return ProcErrorMsg( r );
	}

	ArgFileName = "/file:";
	ArgFileName += pfile;
	snprintf( buf, 15, "%d", Line );
	ArgLine = "/line:";
	ArgLine += buf;
	ArgLine = " /standalone:";

	procStart.SpecifyCommand( m_CmdOption.GetArg0().c_str() );
	procStart.AddArg( ArgFileName.c_str() );
	procStart.AddArg( ArgLine.c_str() );

	// 新しいプロセスを起動
	if ( procStart.Start() < 0 ) {
		ShowErrorMsgBox( pConfigInfo->RefFailToGetPID() );
		return false;
	}
	return true;
}

// 自動保存用のタイマのエントリ
void CTaEditShell::OnAutoSaveTimer( XtPointer client_data, XtIntervalId *timer )
{
	reinterpret_cast< CTaEditShell* >( client_data )->OnAutoSaveTimer();
}

// 自動保存用のタイマイベント
void CTaEditShell::OnAutoSaveTimer()
{
	const string fname = theDocument.GetFileName();
	enumAUTOSAVE_NEWFILE asnw = pConfigInfo->GetAutoSaveNewFileMethod();

	// ドキュメントが更新されていなければ、保存処理は行わない
	if ( !theDocument.GetIsModify() ) goto EXIT_LB;

	// ファイル名なく、ファイル名がないときにはなにもしない設定になっていた場合は、
	// 処理を行わない
	if ( fname.empty() && asnw == ASNW_NOTHING ) goto EXIT_LB;

	// シェルが無効になっていた場合（メッセージボックスが表示されている等）で
	// かつ、ファイル名がない場合は、処理しない
	if ( !XtIsSensitive( m_TaEditShell ) && fname.empty() ) goto EXIT_LB;

	// 保存処理を行う
	SaveFileProcedure();

EXIT_LB:

	// 次のタイマを設定する
	XtAppAddTimeOut( XtWidgetToApplicationContext( m_TaEditShell ),
		pConfigInfo->GetAutoSaveInterval() * 1000, CTaEditShell::OnAutoSaveTimer, this );
}

// カーソル用タイマを遅延させる
void CTaEditShell::DelayCursorTimer()
{
	XtAppContext appContext = XtWidgetToApplicationContext( m_TaEditShell );
	// カーソル用タイマをいったん破棄して、再度登録し直す
	XtRemoveTimeOut( CursorTimerID );
	CursorTimerID = XtAppAddTimeOut( appContext, 500, CTaEditShell::OnTimer, this );
}

// タイトルを設定し直す
void CTaEditShell::ResetTitle() const
{
	// ドキュメントオブジェクトから、ファイル名を取得して、それをタイトルに設定する
	// ただし、ファイル名がない場合には、新規ファイルであることを示す文字列を
	// ファイル名の代わりに表示する
	if ( theDocument.GetFileName() != "" )
		SetWindowTitle( GetFileNameFromFullPathName( theDocument.GetFileName() ) );
	else
		SetWindowTitle( pConfigInfo->RefNewFileWndTitleStr().c_str() );
}

// プロセスを終了させる
void CTaEditShell::ExitProcess( int r )
{
	// サーバに、プロセスが終了することを通知する
	if ( pConstruction ) {

		CErrorBool sr = pConstruction->OnExit();
		if ( !sr ) ProcErrorMsg( sr );

		// コンストラクション・オブジェクトを破棄する
		delete pConstruction;
		pConstruction = NULL;
	}

	// ビューに終了を通知する
	m_Draw->OnExit();

	if ( pLangConfig )
		delete pLangConfig;
	pLangConfig = NULL;
	pConfigInfo = NULL;

	exit( r );
}

// 指定した行番号へ移動
void CTaEditShell::MoveTo( int Line )
{
	m_Draw->GetTextEditor()->OnMoveto( Line );
}

// コンストラクション・モードか否か
bool CTaEditShell::IsConstructionMode() const
{
	return pConstruction != NULL;
}

// スタンドアロン・モードにする
CErrorBool CTaEditShell::SetStandaloneMode()
{
	CErrorBool r;

	if ( !pConstruction ) return true;

	r = pConstruction->NoticeUnJoin();

	delete pConstruction;
	pConstruction = NULL;

	SetCSModeMenu();
	return r;
}

// コンストラクション・モードにする
CErrorBool CTaEditShell::SetConstructionMode()
{
	CErrorBool r;

	if ( pConstruction ) return true;

	pConstruction = new CConsruction();
	if ( !pConstruction ) {
		r = pConfigInfo->RefOutOfMemoryErrorMsg();
		goto ERR_EXIT;
	}

	if ( !pConstruction->Initialize() ) {
		// 初期化に失敗した
		r = pConfigInfo->RefFailedToInitConstructionModeMsg();
		goto ERR_EXIT;
	}

	r = pConstruction->NoticeJoin( theDocument.GetFileName() );
	if ( !r ) goto ERR_EXIT;
	SetCSModeMenu();
	return true;

ERR_EXIT:
	delete pConstruction;
	pConstruction = NULL;
	SetCSModeMenu();
	return r;
}

// コンストラクション／スタンドアロンモードのメニューを設定する
void CTaEditShell::SetCSModeMenu() const
{
	int ac = 0;
	Arg al[2];
	XtCallbackList cbList;

	// 一旦、コールバックを無効化する
	ac = 0;
	XtSetArg( al[ac], XmCValueChangedCallback, &cbList ); ac++;
	XtGetValues( m_menuCSModeStandalone, al, ac );
	ac = 0;
	XtSetArg( al[ac], XmCValueChangedCallback, NULL ); ac++;
	XtSetValues( m_menuCSModeStandalone, al, ac );

	// ラジオボタンを設定する
	ac = 0;
	XtSetArg( al[ac], XmNset, False ); ac++;
	if ( pConstruction )
		XtSetValues( m_menuCSModeStandalone, al, ac );
	else
		XtSetValues( m_menuCSModeConstruction, al, ac );

	ac = 0;
	XtSetArg( al[ac], XmNset, True ); ac++;
	if ( pConstruction )
		XtSetValues( m_menuCSModeConstruction, al, ac );
	else
		XtSetValues( m_menuCSModeStandalone, al, ac );

	// コールバックを元に戻す
	ac = 0;
	XtSetArg( al[ac], XmCValueChangedCallback, cbList ); ac++;
	XtSetValues( m_menuCSModeStandalone, al, ac );
}


