/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 1, or (at your option)
** any later version.

** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.

** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
 * Author : Alexandre Parenteau <aubonbeurre@hotmail.com> --- February 1998
 */

/*
 * CommitDlg.cpp : the cvs commit dialog
 */

#include "stdafx.h"

#ifdef WIN32
#	include "wincvs.h"
#	include <process.h>
#else /* !WIN32 */
#	include <ctype.h>
#endif /* !WIN32 */

#if qUnix
#	include "UCvsDialogs.h"
#endif

#ifdef qMacCvsPP
#	include <UModalDialogs.h>
#	include <LMultiPanelView.h>
#	include <LPopupGroupBox.h>
#	include <LCheckBox.h>
#	include <LTextEditView.h>
#	include "LPopupFiller.h"

#	include "MacCvsApp.h"
#endif /* qMacCvsPP */

#include "CommitDlg.h"
#include "CvsPrefs.h"
#include "getline.h"
#include "TextBinary.h"
#include "MultiString.h"
#include "CvsCommands.h"

static CMString gCommitLogs(10, "P_CommitLogs");

void combozify(CStr & str)
{
	// extract the first xxx words
	const char *tmp = str;
	CStr result;
	int numWords = 0;
#	define HOWMUCH_WORDS 5
	while(*tmp != '\0' && numWords < HOWMUCH_WORDS)
	{
		while(*tmp != '\0' && isspace(*tmp))
			tmp++;

		while(*tmp != '\0' && !isspace(*tmp))
			result << *tmp ++;

		if(*tmp != '\0')
			result << ' ';

		numWords++;
	}

	if(*tmp != '\0')
	{
		result << "...";
	}
	str = result;
}

#ifdef WIN32
#	include "GetPrefs.h"
#	ifdef _DEBUG
#		define new DEBUG_NEW
#		undef THIS_FILE
		static char THIS_FILE[] = __FILE__;
#	endif

IMPLEMENT_DYNCREATE(CCommit_MAIN, CPropertyPage)

CCommit_MAIN::CCommit_MAIN() : CPropertyPage(CCommit_MAIN::IDD)
{
}

CCommit_MAIN::CCommit_MAIN(const char *logmsg, const char *pathTmpl, MultiFiles *mf) :
	CPropertyPage(CCommit_MAIN::IDD)
{
	//{{AFX_DATA_INIT(CCommit_MAIN)
	m_logmsg = logmsg;
	m_norecurs = FALSE;
	m_wordwrap = FALSE;
	//}}AFX_DATA_INIT
	m_tmplPath = pathTmpl;
	if(!m_tmplPath.empty())
	{
		if(!m_tmplPath.endsWith(kPathDelimiter))
			m_tmplPath << kPathDelimiter;
		m_tmplPath << "CVS";
		m_tmplPath << kPathDelimiter;
		m_tmplPath << "Template";
	}
	m_pmfarg = mf;

	m_bSwitchingWrap = FALSE;
	m_wordwrap = gCvsPrefs.WordWrapLogMsg();
}

CCommit_MAIN::~CCommit_MAIN()
{
}

void CCommit_MAIN::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CCommit_MAIN)
	DDX_Control(pDX, IDC_FILETODIFF, m_fileToDiffCombo);
	DDX_Control(pDX, IDC_WORDWRAP, m_wordwrapctrl);
	DDX_Control(pDX, IDC_LOGMSG_WRAP, m_logmsgctrlwrap);
	DDX_Control(pDX, IDC_LOGMSG, m_logmsgctrl);
	DDX_Control(pDX, IDC_COMBO, m_combodef);
	DDX_Check(pDX, IDC_NORECURS, m_norecurs);
	DDX_Check(pDX, IDC_WORDWRAP, m_wordwrap);
	//}}AFX_DATA_MAP

	//JK - this DDX call is outside the main section to allow class wizard parse properly
	if( !pDX->m_bSaveAndValidate )
	{
		DDX_Text(pDX, IDC_LOGMSG_WRAP, m_logmsg);
		DDX_Text(pDX, IDC_LOGMSG, m_logmsg);
	}
	else
	{
		DDX_Text(pDX, m_wordwrapctrl.GetCheck() ? IDC_LOGMSG_WRAP : IDC_LOGMSG, m_logmsg);
	}

	if(!pDX->m_bSaveAndValidate)
	{
		m_combodef.ResetContent();
		m_combodef.AddString("Insert CVS/Template");
		const NAMESPACE(std) vector<CStr> & list = gCommitLogs.GetList();
		NAMESPACE(std) vector<CStr>::const_iterator i;
		for(i = list.begin(); i != list.end(); ++i)
		{
			CStr str = *i;
			combozify(str);
			m_combodef.AddString(str);
		}
	}
	else
	{
		if(!m_logmsg.IsEmpty())
		{
			gCommitLogs.Insert(m_logmsg);
		}
	}
}

void CCommit_MAIN::OnSelchangeCombo() 
{
	int sel = m_combodef.GetCurSel();
	if(sel == CB_ERR)
		return;

	CEdit* pEdit = m_wordwrapctrl.GetCheck() ? &m_logmsgctrlwrap : &m_logmsgctrl;

	pEdit->SetSel(0, -1);
	if(sel == 0)
	{
		bool gotIt = false;
		FILE *output;

		if(!m_tmplPath.empty() && (output = fopen(m_tmplPath, "r")) != 0L)
		{
			char *line = 0L;
			size_t line_chars_allocated = 0;
			int line_length;
			while ((line_length = getline (&line, &line_chars_allocated, output)) > 0)
			{
				//correct the new line characters for edit box and insert the line
				CString strLine(line);
				strLine.Replace( "\n", "\r\n" );
				pEdit->ReplaceSel(strLine);
			}

			gotIt = true;
			if (line_length < 0 && !feof (output))
				gotIt = false;

			if(line != 0L)
				free (line);

			fclose(output);
		}
		if(!gotIt)
			pEdit->ReplaceSel("*found no CVS/Template file*");
	}
	else
	{
		const NAMESPACE(std) vector<CStr> & list = gCommitLogs.GetList();
		pEdit->ReplaceSel(list[sel - 1]);
	}
}

BEGIN_MESSAGE_MAP(CCommit_MAIN, CPropertyPage)
	//{{AFX_MSG_MAP(CCommit_MAIN)
	ON_CBN_SELCHANGE(IDC_COMBO, OnSelchangeCombo)
	ON_BN_CLICKED(IDC_LAUNCHEDITOR, OnLauncheditor)
	ON_WM_ERASEBKGND()
	ON_BN_CLICKED(IDC_WORDWRAP, OnWordwrap)
	ON_BN_CLICKED(IDC_DIFF, OnDiff)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL CCommit_MAIN::PreTranslateMessage(MSG* pMsg) 
{
	// TODO: Add your specialized code here and/or call the base class
	if( pMsg->message >= WM_KEYFIRST ||
		pMsg->message <= WM_KEYLAST ||
		pMsg->message == WM_COPY || pMsg->message == WM_CUT || pMsg->message == WM_PASTE )
	{
		UpdateInfo();
	}
	
	return CPropertyPage::PreTranslateMessage(pMsg);
}

void CCommit_MAIN::UpdateInfo()
{
	CEdit* pEdit = m_wordwrapctrl.GetCheck() ? &m_logmsgctrlwrap : &m_logmsgctrl;
	
	CString strOldInfo;
	CString strInfo;
	int nLineNumber = pEdit->LineFromChar();
	int nLineLenght = pEdit->LineLength( pEdit->LineIndex() );
	
	strInfo.Format( "Line %d (%d chars)", nLineNumber + 1, nLineLenght );
	
	GetDlgItemText( IDC_EDIT_POSITION, strOldInfo );
	if( strOldInfo != strInfo )
	{
		SetDlgItemText( IDC_EDIT_POSITION, strInfo );
	}
}

void CCommit_MAIN::OnLauncheditor() 
{
	// TODO: Add your control notification handler code here
	if(gCvsPrefs.Viewer() == 0L)
	{
		AfxMessageBox("You need to define a default viewer in the preferences", MB_OK | MB_ICONSTOP);
		return;
	}
	
	const char * argv[2] = { 0L, 0L };
	CStr program;
	if(strchr(gCvsPrefs.Viewer(), ' ') != 0L)
	{
		program << '\"';
		program << gCvsPrefs.Viewer();
		program << '\"';
	}
	else
		program = gCvsPrefs.Viewer();

	argv[0] = program;
	int process = _spawnvp(_P_NOWAIT, gCvsPrefs.Viewer(), argv);
}

//switch the edit boxes
void CCommit_MAIN::SwitchWrapEdit(BOOL bWordWrap)
{
	CString strMessage;

	if( bWordWrap )
	{
		m_logmsgctrl.GetWindowText( strMessage );
		m_logmsgctrlwrap.SetWindowText( strMessage );

		m_bSwitchingWrap = TRUE;
		m_logmsgctrl.ShowWindow( SW_HIDE );
		m_logmsgctrlwrap.ShowWindow( SW_SHOW );
		m_bSwitchingWrap = FALSE;
	}
	else
	{
		m_logmsgctrlwrap.GetWindowText( strMessage );
		m_logmsgctrl.SetWindowText( strMessage );

		m_bSwitchingWrap = TRUE;
		m_logmsgctrlwrap.ShowWindow( SW_HIDE );
		m_logmsgctrl.ShowWindow( SW_SHOW );
		m_bSwitchingWrap = FALSE;
	}
}

BOOL CCommit_MAIN::OnEraseBkgnd(CDC* pDC) 
{
	// TODO: Add your message handler code here and/or call default
	if( m_bSwitchingWrap )
	{
		return TRUE;
	}
	
	return CPropertyPage::OnEraseBkgnd(pDC);
}

void CCommit_MAIN::OnWordwrap() 
{
	// TODO: Add your control notification handler code here
	gCvsPrefs.SetWordWrapLogMsg( m_wordwrapctrl.GetCheck() );
	
	SwitchWrapEdit( gCvsPrefs.WordWrapLogMsg() );
}

void CCommit_MAIN::OnDiff() 
{
	const int nComboIndex = m_fileToDiffCombo.GetCurSel();
	if( nComboIndex > CB_ERR )
	{
		int nIndex = (int)m_fileToDiffCombo.GetItemData(nComboIndex);
		CStr path;
		CStr fileName;
		if( m_pmfarg->get(nIndex, path, fileName) )
		{
			MultiFiles mf;
			mf.newdir(path);
			mf.newfile(fileName);
			
			CvsCmdDiffFiles(&mf);
		}
	}
}

BOOL CCommit_MAIN::OnInitDialog() 
{
	CPropertyPage::OnInitDialog();
	
	// Extra initialization here
	SwitchWrapEdit( gCvsPrefs.WordWrapLogMsg() );
	if( m_pmfarg )
	{
		for( int nIndex = 0; nIndex < m_pmfarg->NumFiles(); nIndex++ )
		{
			CStr path;
			CStr fileName;
			m_pmfarg->get(nIndex, path, fileName);
			int nComboIndex = m_fileToDiffCombo.AddString(CString(path) + CString(fileName));
			m_fileToDiffCombo.SetItemData(nComboIndex, (DWORD)nIndex);
		}
	}

	if( m_fileToDiffCombo.GetCount() ) 
	{
		//set the combo box to read-only
		CEdit* pEdit = (CEdit*)m_fileToDiffCombo.GetDlgItem(1001);
		if( pEdit && IsWindow(pEdit->m_hWnd) )
		{
			pEdit->SetReadOnly();
		}

		m_fileToDiffCombo.SetCurSel(0);
	}
	else
	{
		m_fileToDiffCombo.EnableWindow(FALSE);
		CWnd* pButton = GetDlgItem(IDC_DIFF);
		if( pButton )
		{
			pButton->EnableWindow(FALSE);
		}
	}
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}


/////////////////////////////////////////////////////////////////////////////
// CCommit_OPTIONS property page

IMPLEMENT_DYNCREATE(CCommit_OPTIONS, CPropertyPage)

CCommit_OPTIONS::CCommit_OPTIONS() : CPropertyPage(CCommit_OPTIONS::IDD)
{
	//{{AFX_DATA_INIT(CCommit_OPTIONS)
	m_forceCommit = FALSE;
	m_rev = _T("");
	m_forceRecurse = FALSE;
	m_forceRevision = FALSE;
	m_noModuleProgram = FALSE;
	//}}AFX_DATA_INIT
}

CCommit_OPTIONS::~CCommit_OPTIONS()
{
}

void CCommit_OPTIONS::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CCommit_OPTIONS)
	DDX_Control(pDX, IDC_COMBOREV, m_refDef);
	DDX_Check(pDX, IDC_FORCECOMMIT, m_forceCommit);
	DDX_CBString(pDX, IDC_COMBOREV, m_rev);
	DDX_Check(pDX, IDC_FORCERECURSE, m_forceRecurse);
	DDX_Check(pDX, IDC_FORCEREVISION, m_forceRevision);
	DDX_Check(pDX, IDC_NOMODULEPROGRAM, m_noModuleProgram);
	//}}AFX_DATA_MAP

	if(m_forceRevision)
		DDV_MinChars(pDX, m_rev, 1);
	if(!pDX->m_bSaveAndValidate)
	{
		OnForcerevision();
	}
	DDX_ComboMString(pDX, IDC_COMBOREV, gRevNames, m_refDef);
}


BEGIN_MESSAGE_MAP(CCommit_OPTIONS, CPropertyPage)
//{{AFX_MSG_MAP(CCommit_OPTIONS)
	ON_BN_CLICKED(IDC_FORCEREVISION, OnForcerevision)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCommit_OPTIONS message handlers

void CCommit_OPTIONS::OnForcerevision() 
{
	CButton* but = (CButton *)GetDlgItem(IDC_FORCEREVISION);
	CWnd* wnd = GetDlgItem(IDC_COMBOREV);
	wnd->EnableWindow(but->GetCheck() == 1);
}


#endif /* WIN32 */

#ifdef qMacCvsPP
class LLogFillerWrapper : public LFillerWrapper
{
public:
	LLogFillerWrapper(LMenuController *menu, CMString & mstr, const char *pathTmpl) :
		LFillerWrapper(menu), fMStr(mstr), fFirstTime(true)
	{
		fTmplPath = pathTmpl;
		if(!fTmplPath.empty())
		{
			if(!fTmplPath.endsWith(kPathDelimiter))
				fTmplPath << kPathDelimiter;
			fTmplPath << "CVS";
			fTmplPath << kPathDelimiter;
			fTmplPath << "Template";
		}

	}
	
	virtual void OnAddingItem(CStr & str)
	{
		if(fFirstTime)
		{
			fMenu->InsertMenuItem("\pInsert CVS/Template", max_Int16);
			fMenu->InsertMenuItem("\p(-", max_Int16, false);
			fFirstTime = false;
		}
		
		combozify(str);
		CPStr pstr(str);
		fMenu->InsertMenuItem(pstr, max_Int16);
	}
	
	virtual bool OnSelectingItem(SInt32 inItem, CStr & str)
	{
		str = "";
		if(inItem == 2)
		{
			bool gotIt = false;
			FILE *output;
			if(!fTmplPath.empty() && (output = fopen(fTmplPath, "r")) != 0L)
			{
				char *line = 0L;
				size_t line_chars_allocated = 0;
				int line_length;
				while ((line_length = getline (&line, &line_chars_allocated, output)) > 0)
				{
					char *tmp = line;
					while((tmp = strchr(tmp, '\n')) != 0L)
					{
						*tmp++ = '\r';
					}
					str << line;
				}

				gotIt = true;
				if (line_length < 0 && !feof (output))
					gotIt = false;

				if(line != 0L)
					free (line);

				fclose(output);
			}
			if(!gotIt)
				str << "*found no CVS/Template file*";
			return true;
		}
		else if(inItem >= 4)
		{
			str = fMStr.GetList()[inItem - 4];
			return true;
		}
		
		return false;
	}
protected:
	CMString & fMStr;
	CStr fTmplPath;
	bool fFirstTime;
};

static void DoDataExchange_Commit(LWindow *theDialog, CStr & commit, bool & norecurs,
	const char *pathTmpl, bool putValue)
{
	LCheckBox *chkNoRecurs = dynamic_cast<LCheckBox*>
		(theDialog->FindPaneByID(item_NoRecurs));
	LTextEditView *editLog = dynamic_cast<LTextEditView*>
		(theDialog->FindPaneByID(item_LogMsg));
	LPopupFiller *fillLog = dynamic_cast<LPopupFiller*>
		(theDialog->FindPaneByID(item_FillerRev1));
	LLogFillerWrapper *wrapper = putValue ? NEW LLogFillerWrapper(fillLog, gCommitLogs, pathTmpl) : 0L;
	
	fillLog->DoDataExchange(gCommitLogs, putValue, wrapper);
	
	if(putValue)
	{
		chkNoRecurs->SetValue(norecurs ? Button_On : Button_Off);
		editLog->SetTextPtr((Ptr)(const char *)commit, commit.length());	
		theDialog->SetLatentSub(editLog);
	}
	else
	{
		norecurs = chkNoRecurs->GetValue() == Button_On;
		Handle hdl = editLog->GetTextHandle();
		Assert_(hdl != 0L);
		commit.set(*hdl, GetHandleSize(hdl));
		
	}
}

static void 
DoDataExchange_CommitOptions(

	LView *theDialog, 
	bool & forceCommit,
	bool & forceRecurse,
	bool & hasRev,
	CPStr & lastRev, 
	bool & noModuleProgram,
	bool putValue)
{
	LPopupFiller *fillTag = dynamic_cast<LPopupFiller*> (theDialog->FindPaneByID(item_FillerTag));
	fillTag->DoDataExchange(gRevNames, putValue);

	DoDataExchange (theDialog, item_ForceCommit, forceCommit, putValue);
	DoDataExchange (theDialog, item_ForceRecurse, forceRecurse, putValue);
	DoDataExchange (theDialog, item_NoModuleProgram, noModuleProgram, putValue);
	DoDataExchange (theDialog, item_CheckRevTag, hasRev, putValue);
	DoDataExchange (theDialog, item_EditRevTag, lastRev, putValue);
}
#endif /* qMacCvsPP */

#if qUnix
class UCvsCommit : public UWidget
{
	UDECLARE_DYNAMIC(UCvsCommit)
public:
	UCvsCommit() : UWidget(::UEventGetWidID()) {}
	virtual ~UCvsCommit() {}

	enum
	{
		kOK = EV_COMMAND_START,	// 0
		kCancel,				// 1
		kTabGeneral				// 2
	};

	virtual void DoDataExchange(bool fill);

protected:
	ev_msg int OnOK(void);
	ev_msg int OnCancel(void);

	UDECLARE_MESSAGE_MAP()
};

UIMPLEMENT_DYNAMIC(UCvsCommit, UWidget)

UBEGIN_MESSAGE_MAP(UCvsCommit, UWidget)
	ON_UCOMMAND(UCvsCommit::kOK, UCvsCommit::OnOK)
	ON_UCOMMAND(UCvsCommit::kCancel, UCvsCommit::OnCancel)
UEND_MESSAGE_MAP()

int UCvsCommit::OnOK(void)
{
	EndModal(true);
	return 0;
}

int UCvsCommit::OnCancel(void)
{
	EndModal(false);
	return 0;
}

void UCvsCommit::DoDataExchange(bool fill)
{
	if(fill)
	{
	}
	else
	{
	}
}

class UCvsCommit_MAIN : public UWidget
{
	UDECLARE_DYNAMIC(UCvsCommit_MAIN)
public:
	UCvsCommit_MAIN(const char *logmsg, const char *pathTmpl);
	virtual ~UCvsCommit_MAIN() {}

	enum
	{
		kEditLog = EV_COMMAND_START,	// 0
		kComboLog,				// 1
		kCheckRecurs			// 2
	};

	virtual void DoDataExchange(bool fill);

	UStr m_logmsg;
	bool m_norecurs;
	UStr m_tmplPath;
protected:

	ev_msg void OnComboSel(int pos, const char *txt);

	UDECLARE_MESSAGE_MAP()
};

UIMPLEMENT_DYNAMIC(UCvsCommit_MAIN, UWidget)

UBEGIN_MESSAGE_MAP(UCvsCommit_MAIN, UWidget)
	ON_COMBO_SEL(UCvsCommit_MAIN::kComboLog, UCvsCommit_MAIN::OnComboSel)
UEND_MESSAGE_MAP()

UCvsCommit_MAIN::UCvsCommit_MAIN(const char *logmsg, const char *pathTmpl) : UWidget(::UEventGetWidID())
{
	m_logmsg = logmsg;
	m_norecurs = false;
	m_tmplPath = pathTmpl;
	if(!m_tmplPath.empty())
	{
		if(!m_tmplPath.endsWith(kPathDelimiter))
			m_tmplPath << kPathDelimiter;
		m_tmplPath << "CVS";
		m_tmplPath << kPathDelimiter;
		m_tmplPath << "Template";
	}
}

void UCvsCommit_MAIN::OnComboSel(int pos, const char *txt)
{
	if(pos == 0)
	{
		bool gotIt = false;
		FILE *output;

		if(!m_tmplPath.empty() && (output = fopen(m_tmplPath, "r")) != 0L)
		{
			char *line = 0L;
			size_t line_chars_allocated = 0;
			int line_length;
			while ((line_length = getline (&line, &line_chars_allocated, output)) > 0)
			{
				UEventSendMessage(GetWidID(), EV_SETTEXT, kEditLog, line);
			}

			gotIt = true;
			if (line_length < 0 && !feof (output))
				gotIt = false;

			if(line != 0L)
				free (line);

			fclose(output);
		}
		if(!gotIt)
			UEventSendMessage(GetWidID(), EV_SETTEXT, kEditLog, (void *)"*found no CVS/Template file*");
	}
	else
	{
		const std::vector<CStr> & list = gCommitLogs.GetList();
		UEventSendMessage(GetWidID(), EV_SETTEXT, kEditLog, (void *)(const char *)list[pos - 1]);
	}
}

void UCvsCommit_MAIN::DoDataExchange(bool fill)
{
	if(fill)
	{
		UEventSendMessage(GetWidID(), EV_SETTEXT, kEditLog, (void *)(const char *)m_logmsg);

		UEventSendMessage(GetWidID(), EV_COMBO_RESETALL, kComboLog, 0L);
		UEventSendMessage(GetWidID(), EV_COMBO_APPEND, kComboLog,
						  (void *)"Insert CVS/Template");
		const std::vector<CStr> & list = gCommitLogs.GetList();
		std::vector<CStr>::const_iterator i;
		for(i = list.begin(); i != list.end(); ++i)
		{
			CStr str = *i;
			combozify(str);
			UEventSendMessage(GetWidID(), EV_COMBO_APPEND, kComboLog, (void *)(const char *)str);
		}
		
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckRecurs, m_norecurs), 0L);
	}
	else
	{
		UEventSendMessage(GetWidID(), EV_GETTEXT, kEditLog, &m_logmsg);
		if(!m_logmsg.empty())
			gCommitLogs.Insert(m_logmsg);

		m_norecurs = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckRecurs, 0L) != 0;
	}
}

#endif // qUnix

bool CompatGetCommit(CStr & commit, bool & norecurs, 
					 bool & forceCommit, bool & forceRecurse, CPStr & rev, bool & noModuleProgram,
					 const char *pathTmpl,
					 MultiFiles *mf)
{
	bool userHitOK = false;
	
	static CStr sLastMsg;
	static CPStr sLastRev;
	
	bool hasRev = false;
	
	norecurs = false;
	commit = "";
	forceCommit = false;
	forceRecurse = false;
	rev = "";
	noModuleProgram = false;
	

#ifdef WIN32
	CPropertySheet pages("Commit settings");
	pages.m_psh.dwFlags |= PSH_NOAPPLYNOW;
	CCommit_MAIN page1(sLastMsg, pathTmpl, mf);
	CCommit_OPTIONS page2;
	CGetPrefs_GLOBALS page3;
	pages.AddPage(&page1);
	pages.AddPage(&page2);
	pages.AddPage(&page3);
	if(pages.DoModal() == IDOK)
	{
		commit = (const char *)page1.m_logmsg;
		sLastMsg = (const char *)page1.m_logmsg;
		norecurs = page1.m_norecurs ? true : false;
		forceCommit = page2.m_forceCommit ? true : false;
		forceRecurse = page2.m_forceRecurse ? true : false;
		hasRev = page2.m_forceRevision ? true : false;
		sLastRev = page2.m_rev;
		noModuleProgram = page2.m_noModuleProgram ? true : false;
		page3.StoreValues();

		userHitOK = true;
	}
#endif /* WIN32 */
#ifdef qMacCvsPP
	StDialogHandler	theHandler(dlg_Commit, CMacCvsApp::app);
	LWindow *theDialog = theHandler.GetDialog();
	ThrowIfNil_(theDialog);
	static UInt16 sRuntimePanel = 1;
	
	LMultiPanelView *multiView = dynamic_cast<LMultiPanelView*>
		(theDialog->FindPaneByID(item_MultiViewPrefs));
	LPane *groupView = theDialog->FindPaneByID(item_GroupViewPrefs);
	
	multiView->SwitchToPanel(3);
	DoDataExchange_Globals(theDialog, true);
	multiView->SwitchToPanel(2);
	DoDataExchange_CommitOptions(theDialog, forceCommit, forceRecurse, hasRev, sLastRev, noModuleProgram, true);
	multiView->SwitchToPanel(1);
	DoDataExchange_Commit(theDialog, sLastMsg, norecurs, pathTmpl, true);
	
	groupView->SetValue(sRuntimePanel);
	theDialog->Show();
	MessageT hitMessage;
	while (true)
	{		// Let DialogHandler process events
		hitMessage = theHandler.DoDialog();
		
		if (hitMessage == msg_OK || hitMessage == msg_Cancel)
			break;
	}
	theDialog->Hide();
	sRuntimePanel = groupView->GetValue();
	
	if(hitMessage == msg_OK)
	{
		multiView->SwitchToPanel(1);
		DoDataExchange_Commit(theDialog, sLastMsg, norecurs, pathTmpl, false);
		multiView->SwitchToPanel(2);
		DoDataExchange_CommitOptions(theDialog, forceCommit, forceRecurse, hasRev, sLastRev, noModuleProgram, false);
		multiView->SwitchToPanel(3);
		DoDataExchange_Globals(theDialog, false);
		commit = sLastMsg;
		commit.replace('\015', '\012');
		userHitOK = true;
	}
#endif /* qMacCvsPP */
#if qUnix
	void *wid = UCreate_CommitDlg();

	UCvsCommit *dlg = new UCvsCommit();
	UCvsCommit_MAIN *tab1 = new UCvsCommit_MAIN(sLastMsg, pathTmpl);
	UEventSendMessage(dlg->GetWidID(), EV_INIT_WIDGET, kUMainWidget, wid);	
	dlg->AddPage(tab1, UCvsCommit::kTabGeneral, 0);

	if(dlg->DoModal())
	{
		commit = tab1->m_logmsg;
		sLastMsg = tab1->m_logmsg;
		norecurs = tab1->m_norecurs;

		userHitOK = true;
	}

	delete dlg;
#endif // qUnix

	if(userHitOK)
	{
		if(commit.length() == 0)
			commit = "no message";
		if(hasRev && !sLastRev.empty())
			rev = sLastRev;
		gCvsPrefs.save();
	}
	return userHitOK;
}
