/*
** 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> --- March 1998
 */

/*
 * UpdateDlg.cpp : the cvs update dialog
 */

#include "stdafx.h"

#ifdef WIN32
#	include "wincvs.h"
#	include "OptionalPropertySheet.h"
#endif /* WIN32 */

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

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

#	include "MacCvsConstant.h"
# include "UCommandDialogs.h"
#endif /* qMacCvsPP */

#include "UpdateDlg.h"
#include "CvsPrefs.h"
#include "MultiFiles.h"
#include "ItemListDlg.h"

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

char *sDefTagNames[] = 
{
	"1.1",
	"1.6.2.4",
	"HEAD",
	"branch-release-1-0",
	0L
};

char *sDefDateNames[] = 
{
	"1998-3",
	"1998-3-24",
	"1998-3-24 20:55",
	"24 Mar",
	"24 Mar 1998",
	"<=1998-3-24",
	0L
};

char *sDefRevDateNames[] = 
{
	"1.1",
	"1.6.2.4",
	"HEAD",
	"branch-release-1-0",
	"1998-3",
	"1998-3-24",
	"1998-3-24 20:55",
	"24 Mar",
	"24 Mar 1998",
	"<=1998-3-24",
	0L
};

CMString gRevNames(10, "P_TagNames", sDefTagNames);
CMString gDateNames(10, "P_DateNames", sDefDateNames);
CMString gDateOrRevNames(20, "P_RebDateNames", sDefRevDateNames);

#ifdef WIN32
#include "GetPrefs.h"

IMPLEMENT_DYNAMIC(CUpdateMain, CPropertyPage)

CUpdateMain::CUpdateMain() : CPropertyPage(CUpdateMain::IDD)
{
	//{{AFX_DATA_INIT(CUpdateMain)
	m_delsticky = FALSE;
	m_norecurs = FALSE;
	m_stdout = FALSE;
	m_createmissdir = FALSE;
	m_getcleancopy = FALSE;
	//}}AFX_DATA_INIT
}

CUpdateMain::~CUpdateMain()
{
}

void CUpdateMain::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CUpdateMain)
	DDX_Check(pDX, IDC_DELSTICKY, m_delsticky);
	DDX_Check(pDX, IDC_NORECURS, m_norecurs);
	DDX_Check(pDX, IDC_STDOUT, m_stdout);
	DDX_Check(pDX, IDC_CREATEMISSDIR, m_createmissdir);
	DDX_Check(pDX, IDC_CLEANCOPY, m_getcleancopy);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CUpdateMain, CPropertyPage)
	//{{AFX_MSG_MAP(CUpdateMain)
		// NOTE: the ClassWizard will add message map macros here
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

IMPLEMENT_DYNAMIC(CUpdateSticky, CPropertyPage)

CUpdateSticky::CUpdateSticky(const MultiFiles* mf, 
							 const char* rev, const char* date, const char* keyword) 
							 : m_mf(mf), CPropertyPage(CUpdateSticky::IDD)
{
	//{{AFX_DATA_INIT(CUpdateSticky)
	m_date = date;
	m_rev = rev;
	m_hasdate = FALSE;
	m_hasrev = FALSE;
	m_match = FALSE;
	m_keyword = keyword;
	//}}AFX_DATA_INIT

	m_revCombo.SetItems(&gRevNames);
	m_dateCombo.SetItems(&gDateNames);
}

CUpdateSticky::~CUpdateSticky()
{
}

void CUpdateSticky::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CUpdateSticky)
	DDX_Control(pDX, IDC_KEYWORDSUBSTITUTION, m_keywordCombo);
	DDX_Control(pDX, IDC_KEYWORDDESC, m_keywordDescStatic);
	DDX_Control(pDX, IDC_COMBODATE, m_dateCombo);
	DDX_Control(pDX, IDC_COMBOREV, m_revCombo);
	DDX_CBString(pDX, IDC_COMBODATE, m_date);
	DDX_CBString(pDX, IDC_COMBOREV, m_rev);
	DDX_Check(pDX, IDC_DATE, m_hasdate);
	DDX_Check(pDX, IDC_REV, m_hasrev);
	DDX_Check(pDX, IDC_MATCH, m_match);
	DDX_CBString(pDX, IDC_KEYWORDSUBSTITUTION, m_keyword);
	//}}AFX_DATA_MAP

	if( m_hasrev )
	{
		DDV_MinChars(pDX, m_rev, 1);
	}
	
	if( m_hasdate )
	{
		DDV_MinChars(pDX, m_date, 1);
	}
	
	if( !pDX->m_bSaveAndValidate )
	{
		OnDate();
		OnRev();
	}

	DDX_ComboMString(pDX, IDC_COMBOREV, m_revCombo);
	DDX_ComboMString(pDX, IDC_COMBODATE, m_dateCombo);
}

BEGIN_MESSAGE_MAP(CUpdateSticky, CPropertyPage)
	//{{AFX_MSG_MAP(CUpdateSticky)
	ON_BN_CLICKED(IDC_DATE, OnDate)
	ON_BN_CLICKED(IDC_REV, OnRev)
	ON_BN_CLICKED(IDC_BROWSE_TAG, OnBrowseTag)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/// OnInitDialog virtual override, initialize the controls
BOOL CUpdateSticky::OnInitDialog() 
{
	CPropertyPage::OnInitDialog();
	
	// Extra initialization
	m_keywordCombo.SetDescriptionWnd(m_keywordDescStatic.m_hWnd);
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CUpdateSticky::OnDate() 
{
	CButton* but = (CButton *)GetDlgItem(IDC_DATE);
	CWnd* wnd = GetDlgItem(IDC_COMBODATE);
	wnd->EnableWindow(but->GetCheck() == 1);
}

void CUpdateSticky::OnRev() 
{
	CButton* but = (CButton*)GetDlgItem(IDC_REV);
	
	CWnd* wnd = GetDlgItem(IDC_COMBOREV);
	if( wnd )
	{
		wnd->EnableWindow(but->GetCheck());
	}
	
	wnd = GetDlgItem(IDC_BROWSE_TAG);
	if( wnd )
	{
		wnd->EnableWindow(but->GetCheck());
	}
}

void CUpdateSticky::OnBrowseTag() 
{
	CStr tagName;
	if( CompatGetTagListItem(m_mf, tagName) )
	{
		m_rev = (const char*)tagName;
		m_revCombo.SetWindowText(m_rev);
	}
}

IMPLEMENT_DYNAMIC(CUpdateMerge, CPropertyPage)

CUpdateMerge::CUpdateMerge(const MultiFiles* mf,
						   bool isCheckout, 
						   const char* rev1, const char* rev2, const char* date1, const char* date2) 
						   : m_mf(mf), CPropertyPage(CUpdateMerge::IDD)
{
	//{{AFX_DATA_INIT(CUpdateMerge)
	m_rev1 = rev1;
	m_rev2 = rev2;
	m_merge = 0;
	m_hasDate1 = FALSE;
	m_hasDate2 = FALSE;
	m_date1 = _T("");
	m_date2 = _T("");
	//}}AFX_DATA_INIT

	m_isCheckout = isCheckout;

	m_rev1Combo.SetItems(m_isCheckout ? &gReleasesNames : &gRevNames);
	m_rev2Combo.SetItems(m_isCheckout ? &gReleasesNames : &gRevNames);
	m_date1Combo.SetItems(&gDateNames);
	m_date2Combo.SetItems(&gDateNames);
}

CUpdateMerge::~CUpdateMerge()
{
}

void CUpdateMerge::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CUpdateMerge)
	DDX_Control(pDX, IDC_COMBODATE2, m_date2Combo);
	DDX_Control(pDX, IDC_COMBODATE1, m_date1Combo);
	DDX_Control(pDX, IDC_COMBOREV2, m_rev2Combo);
	DDX_Control(pDX, IDC_COMBOREV, m_rev1Combo);
	DDX_CBString(pDX, IDC_COMBOREV, m_rev1);
	DDX_CBString(pDX, IDC_COMBOREV2, m_rev2);
	DDX_Radio(pDX, IDC_MERGE, m_merge);
	DDX_Check(pDX, IDC_CHECKDATE1, m_hasDate1);
	DDX_Check(pDX, IDC_CHECKDATE2, m_hasDate2);
	DDX_CBString(pDX, IDC_COMBODATE1, m_date1);
	DDX_CBString(pDX, IDC_COMBODATE2, m_date2);
	//}}AFX_DATA_MAP

	if( m_merge == 1 || m_merge == 2 )
	{
		DDV_MinChars(pDX, m_rev1, 1);
		if( m_hasDate1 )
		{
			DDV_MinChars(pDX, m_date1, 1);
		}
	}
	
	if( m_merge == 2 )
	{
		DDV_MinChars(pDX, m_rev2, 1);
		if( m_hasDate2 )
		{
			DDV_MinChars(pDX, m_date2, 1);
		}
	}
	
	if( !pDX->m_bSaveAndValidate )
	{
		OnMerge();
	}

	DDX_ComboMString(pDX, IDC_COMBOREV, m_rev1Combo);
	DDX_ComboMString(pDX, IDC_COMBOREV2, m_rev2Combo);
	DDX_ComboMString(pDX, IDC_COMBODATE1, m_date1Combo);
	DDX_ComboMString(pDX, IDC_COMBODATE2, m_date2Combo);
}

void CUpdateMerge::OnMerge() 
{
	CButton* chkMerge1 = (CButton*)GetDlgItem(IDC_MERGE1);
	CButton* chkMerge2 = (CButton*)GetDlgItem(IDC_MERGE2);
	CWnd* wndRev1 = GetDlgItem(IDC_COMBOREV);
	CWnd* wndRev2 = GetDlgItem(IDC_COMBOREV2);
	CWnd* wndBrowseTag1 = GetDlgItem(IDC_BROWSE_TAG1);
	CWnd* wndBrowseTag2 = GetDlgItem(IDC_BROWSE_TAG2);
	
	CButton* chkDate1 = (CButton*)GetDlgItem(IDC_CHECKDATE1);
	CButton* chkDate2 = (CButton*)GetDlgItem(IDC_CHECKDATE2);
	CWnd* wndDate1 = GetDlgItem(IDC_COMBODATE1);
	CWnd* wndDate2 = GetDlgItem(IDC_COMBODATE2);

	if( chkMerge1->GetCheck() == 1 )
	{
		wndRev1->EnableWindow(TRUE);
		wndRev2->EnableWindow(FALSE);
		wndBrowseTag1->EnableWindow(TRUE);
		wndBrowseTag2->EnableWindow(FALSE);
	}
	else if( chkMerge2->GetCheck() == 1 )
	{
		wndRev1->EnableWindow(TRUE);
		wndRev2->EnableWindow(TRUE);
		wndBrowseTag1->EnableWindow(TRUE);
		wndBrowseTag2->EnableWindow(TRUE);
	}
	else
	{
		wndRev1->EnableWindow(FALSE);
		wndRev2->EnableWindow(FALSE);
		wndBrowseTag1->EnableWindow(FALSE);
		wndBrowseTag2->EnableWindow(FALSE);
	}

	chkDate1->EnableWindow(wndRev1->IsWindowEnabled());
	chkDate2->EnableWindow(wndRev2->IsWindowEnabled());
	wndDate1->EnableWindow(wndRev1->IsWindowEnabled() && chkDate1->GetCheck());
	wndDate2->EnableWindow(wndRev2->IsWindowEnabled() && chkDate2->GetCheck());
}

void CUpdateMerge::OnMerge1() 
{
	OnMerge();
}

void CUpdateMerge::OnMerge2() 
{
	OnMerge();
}

void CUpdateMerge::OnCheckdate1() 
{
	OnMerge();
}

void CUpdateMerge::OnCheckdate2() 
{
	OnMerge();
}

void CUpdateMerge::OnBrowseTag1() 
{
	CStr tagName;
	if( CompatGetTagListItem(m_mf, tagName) )
	{
		m_rev1 = (const char*)tagName;
		m_rev1Combo.SetWindowText(m_rev1);
	}
}

void CUpdateMerge::OnBrowseTag2() 
{	
	CStr tagName;
	if( CompatGetTagListItem(m_mf, tagName) )
	{
		m_rev2 = (const char*)tagName;
		m_rev2Combo.SetWindowText(m_rev2);
	}
}

BEGIN_MESSAGE_MAP(CUpdateMerge, CPropertyPage)
	//{{AFX_MSG_MAP(CUpdateMerge)
	ON_BN_CLICKED(IDC_MERGE, OnMerge)
	ON_BN_CLICKED(IDC_MERGE1, OnMerge1)
	ON_BN_CLICKED(IDC_MERGE2, OnMerge2)
	ON_BN_CLICKED(IDC_CHECKDATE1, OnCheckdate1)
	ON_BN_CLICKED(IDC_CHECKDATE2, OnCheckdate2)
	ON_BN_CLICKED(IDC_BROWSE_TAG1, OnBrowseTag1)
	ON_BN_CLICKED(IDC_BROWSE_TAG2, OnBrowseTag2)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

#endif /* WIN32 */

#ifdef qMacCvsPP
static void DoDataExchange_UpdateMerge(LWindow *theDialog, const MultiFiles* mf,
	bool & merge1, bool & merge2,
	CPStr & sLastRev1, CPStr & sLastRev2, bool putValue)
{
	LRadioButton *chkHasRev = dynamic_cast<LRadioButton*>
		(theDialog->FindPaneByID(item_CheckRevTag1));
	LEditText *editRev = dynamic_cast<LEditText*>
		(theDialog->FindPaneByID(item_EditRevTag1));
	LRadioButton *chkHasRev2 = dynamic_cast<LRadioButton*>
		(theDialog->FindPaneByID(item_CheckRevTag2));
	LEditText *editRev2 = dynamic_cast<LEditText*>
		(theDialog->FindPaneByID(item_EditRevTag2));
	LPopupFiller *fill1 = dynamic_cast<LPopupFiller*>
		(theDialog->FindPaneByID(item_FillerRev1));
	LPopupFiller *fill2 = dynamic_cast<LPopupFiller*>
		(theDialog->FindPaneByID(item_FillerRev2));
	
	LTagWrapper *wrapper1 = putValue ? NEW LTagWrapper(fill1, mf) : 0L;
	fill1->DoDataExchange(gRevNames, putValue, wrapper1);
	LTagWrapper *wrapper2 = putValue ? NEW LTagWrapper(fill2, mf) : 0L;
	fill2->DoDataExchange(gRevNames, putValue, wrapper2);
		
	if(putValue)
	{
		if(merge1 && merge2)
			theDialog->SetValueForPaneID (item_CheckRevTag2, Button_On);
		else if(merge1)
			theDialog->SetValueForPaneID (item_CheckRevTag1, Button_On);
		else
			theDialog->SetValueForPaneID (item_MergeNone, Button_On);

		editRev->SetText((Ptr)(const char *)sLastRev1, sLastRev1.length());
		editRev2->SetText((Ptr)(const char *)sLastRev2, sLastRev2.length());
	}
	else
	{
		if(theDialog->GetValueForPaneID(item_CheckRevTag2) == Button_On)
		{
			merge1 = merge2 = true;
		}
		else if (theDialog->GetValueForPaneID(item_CheckRevTag1) == Button_On)
		{
			merge1 = true;
			merge2 = false;
		}
		else
		{
			merge1 = merge2 = false;
		}

		char str[255];
		Size len;
		
		editRev->GetText(str, 254, &len);
		sLastRev1.set(str, len);
		editRev2->GetText(str, 254, &len);
		sLastRev2.set(str, len);
	}
}

static void DoDataExchange_UpdateSticky(LWindow *theDialog, const MultiFiles* mf,
	bool & hasDate, bool & hasRev,
	CPStr & sLastDate, CPStr & sLastRev, bool & useMostRecent, bool putValue)
{
	LCheckBox *chkHasDate = dynamic_cast<LCheckBox*>
		(theDialog->FindPaneByID(item_CheckDate));
	LCheckBox *chkHasRev = dynamic_cast<LCheckBox*>
		(theDialog->FindPaneByID(item_CheckRevTag));
	LCheckBox *chkMostRecent = dynamic_cast<LCheckBox*>
		(theDialog->FindPaneByID(item_MostRecentRev));
	LEditText *editDate = dynamic_cast<LEditText*>
		(theDialog->FindPaneByID(item_EditDate));
	LEditText *editRev = dynamic_cast<LEditText*>
		(theDialog->FindPaneByID(item_EditRevTag));
	LPopupFiller *fillTag = dynamic_cast<LPopupFiller*>
		(theDialog->FindPaneByID(item_FillerTag));
	LPopupFiller *fillDate = dynamic_cast<LPopupFiller*>
		(theDialog->FindPaneByID(item_FillerDate));
	
	LTagWrapper *wrapper = putValue ? NEW LTagWrapper(fillTag, mf) : 0L;
	fillTag->DoDataExchange(gRevNames, putValue, wrapper);
	fillDate->DoDataExchange(gDateNames, putValue);

	if(putValue)
	{
		chkHasDate->SetValue(hasDate ? Button_On : Button_Off);
		chkHasRev->SetValue(hasRev ? Button_On : Button_Off);
		chkMostRecent->SetValue(useMostRecent ? Button_On : Button_Off);
		editDate->SetText((Ptr)(const char *)sLastDate, sLastDate.length());
		editRev->SetText((Ptr)(const char *)sLastRev, sLastRev.length());
	}
	else
	{
		hasDate = chkHasDate->GetValue() == Button_On;
		hasRev = chkHasRev->GetValue() == Button_On;
		useMostRecent = chkMostRecent->GetValue() == Button_On;

		char str[255];
		Size len;
		
		editDate->GetText(str, 254, &len);
		sLastDate.set(str, len);
		editRev->GetText(str, 254, &len);
		sLastRev.set(str, len);
	}
}

static void DoDataExchange_UpdateSettings(LWindow *theDialog, bool & toStdout, bool & noRecurs,
	bool & resetSticky, bool & createMissDir, bool & getCleanCopy, bool putValue)
{
	DoDataExchange (theDialog, item_NoRecurs, noRecurs, putValue);
	DoDataExchange (theDialog, item_ToStout, toStdout, putValue);
	DoDataExchange (theDialog, item_ResetSticky, resetSticky, putValue);
	DoDataExchange (theDialog, item_CreateMissDir, createMissDir, putValue);
	DoDataExchange (theDialog, item_GetCleanCopy, getCleanCopy, putValue);
	
}
#endif /* qMacCvsPP */

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

	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(UCvsUpdate, UWidget)

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

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

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

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

class UCvsUpdate_MAIN : public UWidget
{
	UDECLARE_DYNAMIC(UCvsUpdate_MAIN)
public:
	UCvsUpdate_MAIN() : UWidget(::UEventGetWidID()) {}
	virtual ~UCvsUpdate_MAIN() {}

	enum
	{
		kCheckStdout = EV_COMMAND_START,	// 0
		kCheckRecurse,			// 1
		kCheckReset,			// 2
		kCheckMissing,			// 3
		kGetCleanCopy			// 4
	};

	virtual void DoDataExchange(bool fill);

	bool m_toStdout;
	bool m_noRecurs;
	bool m_resetSticky;
	bool m_createMissDir;
	bool m_getCleanCopy;
protected:

	UDECLARE_MESSAGE_MAP()
};

UIMPLEMENT_DYNAMIC(UCvsUpdate_MAIN, UWidget)

UBEGIN_MESSAGE_MAP(UCvsUpdate_MAIN, UWidget)
UEND_MESSAGE_MAP()

void UCvsUpdate_MAIN::DoDataExchange(bool fill)
{
	if(fill)
	{
		m_toStdout = false;
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckStdout, m_toStdout), 0L);
		m_noRecurs = false;
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckRecurse, m_noRecurs), 0L);
		m_resetSticky = false;
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckReset, m_resetSticky), 0L);
		m_createMissDir = false;
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckMissing, m_createMissDir), 0L);
		m_getCleanCopy = false;
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kGetCleanCopy, m_getCleanCopy), 0L);
	}
	else
	{
		m_toStdout = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckStdout, 0L) != 0;
		m_noRecurs = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckRecurse, 0L) != 0;
		m_resetSticky = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckReset, 0L) != 0;
		m_createMissDir = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckMissing, 0L) != 0;
		m_getCleanCopy = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kGetCleanCopy, 0L) != 0;
	}
}

class UCvsUpdate_STICKY : public UWidget
{
	UDECLARE_DYNAMIC(UCvsUpdate_STICKY)
public:
	UCvsUpdate_STICKY(const char *rev, const char *date);
	virtual ~UCvsUpdate_STICKY() {}

	enum
	{
		kCheckDate = EV_COMMAND_START,	// 0
		kComboDate,			// 1
		kCheckRev,			// 2
		kComboRev,			// 3
		kCheckMatch			// 4
	};

	virtual void DoDataExchange(bool fill);

	UStr m_date;
	UStr m_rev;
	bool m_hasdate;
	bool m_hasrev;
	bool m_match;
protected:

	ev_msg int OnDate(void);
	ev_msg int OnRev(void);

	UDECLARE_MESSAGE_MAP()
};

UIMPLEMENT_DYNAMIC(UCvsUpdate_STICKY, UWidget)

UBEGIN_MESSAGE_MAP(UCvsUpdate_STICKY, UWidget)
	ON_UCOMMAND(UCvsUpdate_STICKY::kCheckDate, UCvsUpdate_STICKY::OnDate)
	ON_UCOMMAND(UCvsUpdate_STICKY::kCheckRev, UCvsUpdate_STICKY::OnRev)
UEND_MESSAGE_MAP()

UCvsUpdate_STICKY::UCvsUpdate_STICKY(const char *rev, const char *date) : UWidget(::UEventGetWidID())
{
	m_date = date;
	m_rev = rev;
	m_hasdate = false;
	m_hasrev = false;
	m_match = false;
}

int UCvsUpdate_STICKY::OnDate()
{
	int state = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckDate, 0L);
	UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kComboDate, state), 0L);
	return 0;
}

int UCvsUpdate_STICKY::OnRev()
{
	int state = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckRev, 0L);
	UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kComboRev, state), 0L);
	return 0;
}

void UCvsUpdate_STICKY::DoDataExchange(bool fill)
{
	::DoDataExchange(fill, GetWidID(), kComboRev, gRevNames);
	::DoDataExchange(fill, GetWidID(), kComboDate, gDateNames);

	if(fill)
	{
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckDate, m_hasdate), 0L);
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckRev, m_hasrev), 0L);
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckMatch, m_match), 0L);

		OnDate();
		OnRev();
	}
	else
	{
		m_hasdate = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckDate, 0L);
		m_hasrev = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckRev, 0L);
		m_match = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckMatch, 0L);

		UEventSendMessage(GetWidID(), EV_GETTEXT, kComboDate, &m_date);
		UEventSendMessage(GetWidID(), EV_GETTEXT, kComboRev, &m_rev);
	}
}

class UCvsUpdate_MERGE : public UWidget
{
	UDECLARE_DYNAMIC(UCvsUpdate_MERGE)
public:
	UCvsUpdate_MERGE(const char *rev1, const char *rev2);
	virtual ~UCvsUpdate_MERGE() {}

	enum
	{
		kRadioNone = EV_COMMAND_START,	// 0
		kRadioMerge1,		// 1
		kRadioMerge2,		// 2
		kComboRev1,			// 3
		kComboRev2			// 4
	};

	virtual void DoDataExchange(bool fill);

	UStr m_rev1;
	UStr m_rev2;
	int m_merge;
protected:

	ev_msg int OnMerge(int cmd);

	UDECLARE_MESSAGE_MAP()
};

UIMPLEMENT_DYNAMIC(UCvsUpdate_MERGE, UWidget)

UBEGIN_MESSAGE_MAP(UCvsUpdate_MERGE, UWidget)
	ON_UCOMMAND_RANGE(UCvsUpdate_MERGE::kRadioNone, UCvsUpdate_MERGE::kRadioMerge2, UCvsUpdate_MERGE::OnMerge)
UEND_MESSAGE_MAP()

UCvsUpdate_MERGE::UCvsUpdate_MERGE(const char *rev1, const char *rev2) : UWidget(::UEventGetWidID())
{
	m_rev1 = rev1;
	m_rev2 = rev2;
	m_merge = 0;
}

int UCvsUpdate_MERGE::OnMerge(int cmd)
{
	int state = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kRadioNone, 0L);
	if(state)
	{
		UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kComboRev1, 0), 0L);
		UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kComboRev2, 0), 0L);
	}
	else
	{
		UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kComboRev1, 1), 0L);
		state = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kRadioMerge1, 0L);
		UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kComboRev2, state == 0), 0L);
	}
	return 0;
}

void UCvsUpdate_MERGE::DoDataExchange(bool fill)
{
	::DoDataExchange(fill, GetWidID(), kComboRev1, gRevNames);
	::DoDataExchange(fill, GetWidID(), kComboRev2, gRevNames);

	if(fill)
	{
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kRadioNone + m_merge, 1), 0L);

		OnMerge(kRadioNone + m_merge);
	}
	else
	{
		if(UEventSendMessage(GetWidID(), EV_QUERYSTATE, kRadioNone, 0L))
			m_merge = 0;
		else if(UEventSendMessage(GetWidID(), EV_QUERYSTATE, kRadioMerge1, 0L))
			m_merge = 1;
		else
			m_merge = 2;

		UEventSendMessage(GetWidID(), EV_GETTEXT, kComboRev1, &m_rev1);
		UEventSendMessage(GetWidID(), EV_GETTEXT, kComboRev2, &m_rev2);
	}
}
#endif // qUnix

/// Get the update options
bool CompatGetUpdate(const MultiFiles* mf,
					 bool& toStdout, bool& noRecurs, bool& resetSticky,
					 CPStr& date, CPStr& rev,
					 bool& useMostRecent,
					 CPStr& rev1, CPStr& rev2,
					 bool& createMissDir,
					 bool& getCleanCopy,
					 CPStr& keyword)
{
	bool userHitOK = false;

	static CPStr sLastDate;
	static CPStr sLastRev;
	static CPStr sLastRev1;
	static CPStr sLastRev2;
	static CPStr sLastDate1;
	static CPStr sLastDate2;

	bool hasDate = false;
	bool hasRev = false;
	bool merge1 = false;
	bool merge2 = false;
	bool hasDate1 = false;
	bool hasDate2 = false;

	date = "";
	rev = "";
	rev1 = "";
	rev2 = "";
	toStdout = false;
	noRecurs = false;
	resetSticky = false;
	useMostRecent = false;
	createMissDir = false;
	getCleanCopy = false;
	keyword = "";

#ifdef WIN32
	COptionalPropertySheet pages(gCvsPrefs.HideCommandDlgUpdate(), _i18n("Update settings"));
	pages.m_psh.dwFlags |= PSH_NOAPPLYNOW;
	CUpdateMain page1;
	CUpdateSticky page2(mf, sLastRev, sLastDate, keyword);
	CUpdateMerge page3(mf, false, sLastRev1, sLastRev2, sLastDate1, sLastDate2);
	CGetPrefs_GLOBALS page4;
	pages.AddPage(&page1);
	pages.AddPage(&page2);
	pages.AddPage(&page3);
	pages.AddPage(&page4);
	if(pages.DoModal() == IDOK)
	{
		toStdout = page1.m_stdout == TRUE;
		noRecurs = page1.m_norecurs == TRUE;
		resetSticky = page1.m_delsticky == TRUE;
		createMissDir = page1.m_createmissdir == TRUE;
		getCleanCopy = page1.m_getcleancopy == TRUE;

		sLastDate = page2.m_date;
		sLastRev = page2.m_rev;
		hasDate = page2.m_hasdate == TRUE;
		hasRev = page2.m_hasrev == TRUE;
		useMostRecent = page2.m_match == TRUE;
		keyword = page2.m_keyword;

		merge1 = page3.m_merge >= 1;
		merge2 = page3.m_merge == 2;
		sLastRev1 = page3.m_rev1;
		sLastRev2 = page3.m_rev2;
		hasDate1 = page3.m_hasDate1 == TRUE;
		hasDate2 = page3.m_hasDate2 == TRUE;
		sLastDate1 = page3.m_date1;
		sLastDate2 = page3.m_date2;

		page4.StoreValues();
		gCvsPrefs.SetHideCommandDlgUpdate(pages.GetHideCommandDlg());
		userHitOK = true;
	}
#endif /* WIN32 */
#ifdef qMacCvsPP
	StOptionalDialogHandler	theHandler(dlg_Update, gCvsPrefs.HideCommandDlgUpdate(), LCommander::GetTopCommander());
	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(4);
	DoDataExchange_Globals(theDialog, true);
	multiView->SwitchToPanel(3);
	DoDataExchange_UpdateMerge(theDialog, mf, merge1, merge2, sLastRev1, sLastRev2, true);
	multiView->SwitchToPanel(2);
	DoDataExchange_UpdateSticky(theDialog, mf, hasDate, hasRev, sLastDate, sLastRev, useMostRecent, true);
	multiView->SwitchToPanel(1);
	DoDataExchange_UpdateSettings(theDialog, toStdout, noRecurs, resetSticky, createMissDir, getCleanCopy, true);
	
	groupView->SetValue(sRuntimePanel);
  
	theHandler.ShowDialog();
	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_UpdateSettings(theDialog, toStdout, noRecurs, resetSticky, createMissDir, getCleanCopy, false);
		multiView->SwitchToPanel(2);
		DoDataExchange_UpdateSticky(theDialog, mf, hasDate, hasRev, sLastDate, sLastRev, useMostRecent, false);
		multiView->SwitchToPanel(3);
		DoDataExchange_UpdateMerge(theDialog, mf, merge1, merge2, sLastRev1, sLastRev2, false);
		multiView->SwitchToPanel(4);
		DoDataExchange_Globals(theDialog, false);
		gCvsPrefs.SetHideCommandDlgUpdate(theHandler.GetHideCommandDlg());
		userHitOK = true;
	}
#endif /* qMacCvsPP */
#if qUnix
	void *wid;
#	if qGTK
	wid = UCreate_UpdateDlg();
#	endif

	UCvsUpdate *dlg = new UCvsUpdate();
	UCvsUpdate_MAIN *tab1 = new UCvsUpdate_MAIN();
	UCvsUpdate_STICKY *tab2 = new UCvsUpdate_STICKY(sLastRev, sLastDate);
	UCvsUpdate_MERGE *tab3 = new UCvsUpdate_MERGE(sLastRev1, sLastRev2);
	UEventSendMessage(dlg->GetWidID(), EV_INIT_WIDGET, kUMainWidget, wid);	
	dlg->AddPage(tab1, UCvsUpdate::kTabGeneral, 0);
	dlg->AddPage(tab2, UCvsUpdate::kTabGeneral, 1);
	dlg->AddPage(tab3, UCvsUpdate::kTabGeneral, 2);

	if(dlg->DoModal())
	{
		toStdout = tab1->m_toStdout;
		noRecurs = tab1->m_noRecurs;
		resetSticky = tab1->m_resetSticky;
		createMissDir = tab1->m_createMissDir;
		getCleanCopy = tab1->m_getCleanCopy;

		sLastDate = tab2->m_date;
		sLastRev = tab2->m_rev;
		hasDate = tab2->m_hasdate;
		hasRev = tab2->m_hasrev;
		useMostRecent = tab2->m_match;

		merge1 = tab3->m_merge >= 1;
		merge2 = tab3->m_merge == 2;
		sLastRev1 = tab3->m_rev1;
		sLastRev2 = tab3->m_rev2;

		userHitOK = true;
	}

	delete dlg;
#endif // qUnix

	if( userHitOK )
	{
		if( hasDate && !sLastDate.empty() )
			date = sLastDate;

		if( hasRev && !sLastRev.empty() )
			rev = sLastRev;

		if( merge1 && merge2 && !sLastRev1.empty() && !sLastRev2.empty() )
		{
			rev1 = sLastRev1;
			rev2 = sLastRev2;
			
			if( hasDate1 )
				rev1 << ":" << sLastDate1;
			
			if( hasDate2 )
				rev2 << ":" << sLastDate2;
		}
		
		if( merge1 && !merge2 && !sLastRev1.empty() )
		{
			rev1 = sLastRev1;
			
			if( hasDate1 )
				rev1 << ":" << sLastDate1;
		}

		gCvsPrefs.save();
	}

	return userHitOK;
}
