/*
** 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> --- December 1997
 *
 * Sep. 21, 00 - added option to compile this file without 'explore' view,
 *               define NOEXPLOREVIEW 
 */

// MainFrm.cpp : implementation of the CMainFrame class
//

#include "stdafx.h"
#include <afxmt.h>
//#include <../src/afximpl.h>
#include "wincvs.h"

#include "MainFrm.h"
#include "WinCvsBrowser.h"
#include "BrowseFileView.h"
#include "WincvsView.h"
#include "Persistent.h"
#include "AppConsole.h"
#include "Splash.h"
#include "BrowserBar.h"
#include "ExploreBar.h"
#include "CvsPrefs.h"
#include "AppGlue.h"

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

static bool IsAppEnabled()
{
	CWincvsApp* app = (CWincvsApp *)AfxGetApp();
	return !app->gCvsRunning && !gCvsPrefs.empty();
}

class CWinPlacement : public CPersistent
{
public:
	WINDOWPLACEMENT placement;
	bool hasOne;

	CWinPlacement(const char *uniqueName) : CPersistent(uniqueName, kNoClass)
	{
		hasOne = false;
	}
	virtual ~CWinPlacement()
	{
	}

	virtual unsigned int SizeOf(void) const
	{
		return hasOne ? sizeof(WINDOWPLACEMENT) : 0;
	}
	
	virtual const void *GetData(void) const
	{
		return hasOne ? &placement : 0L;
	}
	
	virtual void SetData(const void *ptr, unsigned int size)
	{
		if(size == sizeof(WINDOWPLACEMENT))
		{
			memcpy(&placement, ptr, sizeof(WINDOWPLACEMENT));
			hasOne = true;
		}
	}

	CWinPlacement & operator=(const WINDOWPLACEMENT & newplace)
	{
		TouchTimeStamp();
		memcpy(&placement, &newplace, sizeof(WINDOWPLACEMENT));
		hasOne = true;
		return *this;
	}
};

static CWinPlacement gMainPlacement("P_MainPlacement");

/////////////////////////////////////////////////////////////////////////////
// CMainFrame

IMPLEMENT_DYNAMIC(CMainFrame, CCJMDIFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CCJMDIFrameWnd)
	ON_WM_INITMENU()
	//{{AFX_MSG_MAP(CMainFrame)
	ON_WM_CREATE()
	ON_WM_CLOSE()
	ON_WM_DROPFILES()
	ON_CBN_SELCHANGE(ID_HISTORYBROWSE, OnHistorySelect)
	ON_WM_ACTIVATE()
	ON_WM_SYSCOMMAND()
	ON_COMMAND(ID_VIEW_RECURSIVE, OnViewRecursive)
	ON_COMMAND(ID_VIEW_MODIFIED, OnViewModified)
	ON_UPDATE_COMMAND_UI(ID_VIEW_MODIFIED, OnUpdateViewModified)
	ON_UPDATE_COMMAND_UI(ID_VIEW_RECURSIVE, OnUpdateViewRecursive)
	ON_COMMAND(ID_VIEW_CONFLICT, OnViewConflict)
	ON_UPDATE_COMMAND_UI(ID_VIEW_CONFLICT, OnUpdateViewConflict)
	ON_COMMAND(ID_VIEW_UNKNOWN, OnViewUnknown)
	ON_UPDATE_COMMAND_UI(ID_VIEW_UNKNOWN, OnUpdateViewUnknown)
	ON_COMMAND(ID_VIEW_MISSING, OnViewMissing)
	ON_UPDATE_COMMAND_UI(ID_VIEW_MISSING, OnUpdateViewMissing)
	ON_COMMAND(ID_VIEW_IGNORE, OnViewIgnore)
	ON_UPDATE_COMMAND_UI(ID_VIEW_IGNORE, OnUpdateViewIgnore)
	ON_UPDATE_COMMAND_UI(ID_FILTERMASK, OnUpdateFilterMask)
	ON_UPDATE_COMMAND_UI(ID_HISTORYBROWSE, OnUpdateHistory)
	ON_COMMAND(ID_VIEW_ADDED, OnViewAdded)
	ON_UPDATE_COMMAND_UI(ID_VIEW_ADDED, OnUpdateViewAdded)
	ON_UPDATE_COMMAND_UI(ID_VIEW_REMOVED, OnUpdateViewRemoved)
	ON_COMMAND(ID_VIEW_REMOVED, OnViewRemoved)
	ON_COMMAND(ID_VIEW_CHANGED, OnViewChanged)
	ON_UPDATE_COMMAND_UI(ID_VIEW_CHANGED, OnUpdateViewChanged)
	ON_COMMAND(ID_VIEW_HIDEUNKNOWN, OnViewHideunknown)
	ON_UPDATE_COMMAND_UI(ID_VIEW_HIDEUNKNOWN, OnUpdateViewHideunknown)
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
	ON_COMMAND_EX(ID_VIEW_BROWSER_BAR, CCJMDIFrameWnd::OnBarCheck)
	ON_COMMAND_EX(ID_VIEW_FILES_BAR, CCJMDIFrameWnd::OnBarCheck)
	ON_COMMAND_EX(ID_VIEW_FILTER_BAR, CCJMDIFrameWnd::OnBarCheck)
	ON_COMMAND_EX(ID_VIEW_MULTI_BAR, CCJMDIFrameWnd::OnBarCheck)
	ON_COMMAND_EX(ID_VIEW_TAGS_BAR, CCJMDIFrameWnd::OnBarCheck)
	ON_COMMAND_EX(ID_VIEW_CONSOLE_BAR, CCJMDIFrameWnd::OnBarCheck)
	ON_COMMAND_EX(ID_VIEW_WORKSPACE, CCJMDIFrameWnd::OnBarCheck)
	ON_UPDATE_COMMAND_UI(ID_VIEW_BROWSER_BAR, CCJMDIFrameWnd::OnUpdateControlBarMenu)
	ON_UPDATE_COMMAND_UI(ID_VIEW_FILES_BAR, CCJMDIFrameWnd::OnUpdateControlBarMenu)
	ON_UPDATE_COMMAND_UI(ID_VIEW_FILTER_BAR, CCJMDIFrameWnd::OnUpdateControlBarMenu)
	ON_UPDATE_COMMAND_UI(ID_VIEW_MULTI_BAR, CCJMDIFrameWnd::OnUpdateControlBarMenu)
	ON_UPDATE_COMMAND_UI(ID_VIEW_TAGS_BAR, CCJMDIFrameWnd::OnUpdateControlBarMenu)
	ON_UPDATE_COMMAND_UI(ID_VIEW_CONSOLE_BAR, CCJMDIFrameWnd::OnUpdateControlBarMenu)
	ON_UPDATE_COMMAND_UI(ID_VIEW_WORKSPACE, CCJMDIFrameWnd::OnUpdateControlBarMenu)
	// Global help commands
	ON_COMMAND(ID_HELP_FINDER, CCJMDIFrameWnd::OnHelpFinder)
	ON_COMMAND(ID_HELP, CCJMDIFrameWnd::OnHelp)
	ON_COMMAND(ID_CONTEXT_HELP, CCJMDIFrameWnd::OnContextHelp)
	ON_COMMAND(ID_DEFAULT_HELP, CCJMDIFrameWnd::OnHelpFinder)
END_MESSAGE_MAP()

static UINT indicators[] =
{
	ID_SEPARATOR,           // status line indicator
	ID_SEPARATOR,           // rotating icon
	ID_INDICATOR_CAPS,
	ID_INDICATOR_NUM,
	ID_INDICATOR_SCRL,
};

/////////////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction

CMainFrame::CMainFrame()
{	
	m_bRestoreFocus = FALSE;
}

CMainFrame::~CMainFrame()
{
}

BOOL CMainFrame::InitializeDockingWindows()
{
	// Initial size when docked: top, bottom, left, right.
	// ??? SetInitialSize(125,225,225,225);
	
	if (!m_wndWorkspace.Create(this, ID_VIEW_WORKSPACE,
		_T("Workspace"), CSize(200,100), CBRS_LEFT))
	{
		TRACE0("Failed to create dialog bar (Workspace)\n");
		return -1;		// fail to create
	}

	m_wndWorkspace.AddView(_T("Modules"), RUNTIME_CLASS(CBrowserBar));
#ifndef NOEXPLOREVIEW 
	m_wndWorkspace.AddView(_T("Explore"), RUNTIME_CLASS(CExploreBar));
#endif
	m_wndWorkspace.SetActiveView(0);
	// Define the image list to use with the tab control
	m_TabImages.Create (IDR_WORKSPACE, 16, 1, RGB(255,255,255));
	m_wndWorkspace.SetTabImageList(&m_TabImages);
	//m_wndWorkspace.SetMenuID(IDR_POPUP);
	m_wndWorkspace.EnableDockingOnSizeBar(CBRS_ALIGN_ANY);

	if (!m_consolebar.Create(this, ID_VIEW_CONSOLE_BAR,
		_T("Output"), CSize(300,100), CBRS_BOTTOM))
	{
		TRACE0("Failed to create dialog bar (Output)\n");
		return FALSE;		// fail to create
	}
	
	//m_consolebar.SetMenuID(IDR_POPUP);
	m_consolebar.EnableDockingOnSizeBar(CBRS_ALIGN_ANY);

	EnableDockingSizeBar(CBRS_ALIGN_ANY);
	DockSizeBar(&m_wndWorkspace);
	DockSizeBar(&m_consolebar);

	return TRUE;
}

static void onFilterMaskEntered(CObject *obj)
{
	((CMainFrame *)obj)->OnFilterMaskEntered();
}

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CCJMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
		| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
		!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
	{
		TRACE0("Failed to create toolbar (Standard)\n");
		return -1;      // fail to create
	}

	if (!m_wndBrowser.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
		| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC, CRect(0, 0, 0, 0), ID_VIEW_BROWSER_BAR) ||
		!m_wndBrowser.LoadToolBar(IDR_BROWSER))
	{
		TRACE0("Failed to create toolbar (Browse)\n");
		return -1;      // fail to create
	}

	m_wndBrowser.SetButtonInfo(3, ID_SEPARATOR, TBBS_SEPARATOR, 200);
	CRect rect;
	m_wndBrowser.GetItemRect(3, &rect);
	rect.bottom += 140;

	if (!m_browseHist.Create(CBS_DROPDOWNLIST|WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL|WS_HSCROLL,
			rect, &m_wndBrowser, ID_HISTORYBROWSE))
	{
		TRACE0("Failed to create combobox (Browse History)\n");
		return -1;			// fail to create
	}
	m_browseHist.SetDroppedWidth(500);

	// Older versions of Windows* (NT 3.51 for instance) fail with DEFAULT_GUI_FONT
	if (!m_fontNormal.CreateStockObject(DEFAULT_GUI_FONT))
	{
		if (!m_fontNormal.CreatePointFont(80, "MS Sans Serif"))
		{
			TRACE0("Failed to create default GUI font\n");
			return -1;
		}
	}

	// Make browse history use default GUI font
	m_browseHist.SetFont(&m_fontNormal);

	if (!m_wndList.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
		| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC, CRect(0, 0, 0, 0), ID_VIEW_FILES_BAR) ||
		!m_wndList.LoadToolBar(IDR_FILELIST))
	{
		TRACE0("Failed to create toolbar (Files)\n");
		return -1;      // fail to create
	}

	if (!m_wndFilter.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
		| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC, CRect(0, 0, 0, 0), ID_VIEW_FILTER_BAR) ||
		!m_wndFilter.LoadToolBar(IDR_FILTER))
	{
		TRACE0("Failed to create toolbar (Filter)\n");
		return -1;      // fail to create
	}

	if (!m_wndMultiUser.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
		| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC, CRect(0, 0, 0, 0), ID_VIEW_MULTI_BAR) ||
		!m_wndMultiUser.LoadToolBar(IDR_MULTIUSER))
	{
		TRACE0("Failed to create toolbar (Multi-User)\n");
		return -1;      // fail to create
	}

	if (!m_wndTags.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
		| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC, CRect(0, 0, 0, 0), ID_VIEW_TAGS_BAR) ||
		!m_wndTags.LoadToolBar(IDR_TAGS))
	{
		TRACE0("Failed to create toolbar (Tags)\n");
		return -1;      // fail to create
	}

	if (!m_wndStatusBar.Create(this) ||
		!m_wndStatusBar.SetIndicators(indicators,
		  sizeof(indicators)/sizeof(UINT)))
	{
		TRACE0("Failed to create status bar\n");
		return -1;      // fail to create
	}

	// rotating icon
	UINT nID, nStyle;
	int cxWidth;
	m_wndStatusBar.GetPaneInfo( 1, nID, nStyle, cxWidth);
	m_wndStatusBar.SetPaneInfo( 1, nID, nStyle|SBPS_OWNERDRAW, 100);

	EnableDocking(CBRS_ALIGN_ANY);

	// Set toolbar title (visible when toolbar is floating)
	// Adjust toolbar height (default of 26 pixels is a little bit too small)
	// Enable docking
	m_wndToolBar.SetWindowText("Standard");
	m_wndToolBar.SetHeight(28);
	m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
		CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
	m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
	DockControlBar(&m_wndToolBar,AFX_IDW_DOCKBAR_TOP);

	m_wndBrowser.SetWindowText("Browse");
	m_wndBrowser.SetHeight(28);
	m_wndBrowser.SetBarStyle(m_wndBrowser.GetBarStyle() |
		CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
	m_wndBrowser.EnableDocking(CBRS_ALIGN_ANY);
	DockControlBarLeftOf(&m_wndBrowser,&m_wndToolBar);

	m_wndList.SetWindowText("Files");
	m_wndList.SetHeight(28);
	m_wndList.SetBarStyle(m_wndList.GetBarStyle() |
		CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
	m_wndList.EnableDocking(CBRS_ALIGN_ANY);
	DockControlBarLeftOf(&m_wndList,&m_wndBrowser);

	m_wndMultiUser.SetWindowText("Multi-Users");
	m_wndMultiUser.SetHeight(28);
	m_wndMultiUser.SetBarStyle(m_wndMultiUser.GetBarStyle() |
		CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
	m_wndMultiUser.EnableDocking(CBRS_ALIGN_ANY);
	DockControlBarLeftOf(&m_wndMultiUser,&m_wndList);

	m_wndTags.SetWindowText("Tags");
	m_wndTags.SetHeight(28);
	m_wndTags.SetBarStyle(m_wndTags.GetBarStyle() |
		CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
	m_wndTags.EnableDocking(CBRS_ALIGN_ANY);
	DockControlBarLeftOf(&m_wndTags,&m_wndMultiUser);

	m_wndFilter.SetWindowText("Filter");
	m_wndFilter.SetHeight(28);
	m_wndFilter.SetBarStyle(m_wndFilter.GetBarStyle() | 
		CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
	m_wndFilter.EnableDocking(CBRS_ALIGN_ANY);
	DockControlBarLeftOf(&m_wndFilter,&m_wndTags);

	m_wndFilter.SetButtonInfo(2, ID_SEPARATOR, TBBS_SEPARATOR, 200);
	m_wndFilter.GetItemRect(2, &rect);
	rect.bottom += 80;

	if (!m_comboFilterMask.Create(CBS_DROPDOWN|WS_CHILD|WS_VISIBLE|WS_TABSTOP,
			rect, &m_wndFilter, ID_FILTERMASK))
	{
		TRACE0("Failed to create combobox (filter mask)\n");
		return -1;			// fail to create
	}

	// Make browse history use default GUI font
	m_comboFilterMask.SetFont(&m_fontNormal);
	m_comboFilterMask.GetManager()->CheckIn(this, onFilterMaskEntered);

	
	if(!InitializeDockingWindows())
	{
		TRACE0("Failed to initialize docking windows\n");
		return -1;      // fail to create
	}

#if 1
	// load the dock state, but check the toolbar exists (MFC bug)
	CDockState state;
	state.LoadState(_T("Bar State"));
	for (int i = 0; i < state.m_arrBarInfo.GetSize(); i++)
	{
		CControlBarInfo* pInfo = (CControlBarInfo*)state.m_arrBarInfo[i];
		ASSERT(pInfo != NULL);
		if (!pInfo->m_bFloating)
		{
			pInfo->m_pBar = GetControlBar(pInfo->m_nBarID);
			if(pInfo->m_pBar == NULL)
			{
				delete (CControlBarInfo*)state.m_arrBarInfo[i];
				state.m_arrBarInfo.RemoveAt(i);
				i--;
			}
		}
	}
	SetDockState(state);
#else
	LoadBarState(_T("Bar State"));
#endif
	m_state.LoadWindowPos(this);

	// CG: The following line was added by the Splash Screen component.
	CSplashWnd::ShowSplashScreen(this);

	SetTimer(99, 200, 0L);

	return 0;
}

void CMainFrame::DockControlBarLeftOf(CToolBar* Bar,CToolBar* LeftOf)
{
	CRect rect;
	DWORD dw;
	UINT n;

	// get MFC to adjust the dimensions of all docked ToolBars
	// so that GetWindowRect will be accurate
	RecalcLayout();
	LeftOf->GetWindowRect(&rect);
	rect.OffsetRect(1,0);
	dw=LeftOf->GetBarStyle();
	n = 0;
	n = (dw&CBRS_ALIGN_TOP) ? AFX_IDW_DOCKBAR_TOP : n;
	n = (dw&CBRS_ALIGN_BOTTOM && n==0) ? AFX_IDW_DOCKBAR_BOTTOM : n;
	n = (dw&CBRS_ALIGN_LEFT && n==0) ? AFX_IDW_DOCKBAR_LEFT : n;
	n = (dw&CBRS_ALIGN_RIGHT && n==0) ? AFX_IDW_DOCKBAR_RIGHT : n;

	// When we take the default parameters on rect, DockControlBar will dock
	// each Toolbar on a seperate line.  By calculating a rectangle, we in effect
	// are simulating a Toolbar being dragged to that location and docked.
	DockControlBar(Bar,n,&rect);
}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CCJMDIFrameWnd::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics

#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
	CCJMDIFrameWnd::AssertValid();
}

void CMainFrame::Dump(CDumpContext& dc) const
{
	CCJMDIFrameWnd::Dump(dc);
}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers

void CMainFrame::OnClose() 
{
	CWincvsApp* app = (CWincvsApp *)AfxGetApp();
	if(app->gCvsRunning)
	{
		AfxMessageBox("Cvs is currently running : stop cvs first before quitting", MB_OK | MB_ICONSTOP);
		return;
	}

	// only way I found to notify the browser
	// and to prevent the memory leak support.
	app->GetBrowserView()->ResetBrowser(0L);	

	// Charybids Ltd's suggested fix:
	// Saving the window positions whilst iconic trashes the registry.
	if (!IsIconic())
	{
		m_state.SaveWindowPos(this);
		SaveBarState(_T("Bar State"));

		WINDOWPLACEMENT wp;
		wp.length = sizeof wp;
		if (GetWindowPlacement(&wp)) {
			wp.flags &= WPF_RESTORETOMAXIMIZED;
			gMainPlacement = wp;
		}
	}

	// write all the persistents to the .INI file
	gCvsPrefs.save();

	CCJMDIFrameWnd::OnClose();
}

void CMainFrame::OnDropFiles(HDROP hDropInfo) 
{
	SetActiveWindow();	// activate us first !
	UINT nFiles = ::DragQueryFile(hDropInfo, (UINT)-1, NULL, 0);

	CWinApp* pApp = AfxGetApp();
	for (UINT iFile = 0; iFile < nFiles; iFile++)
	{
		TCHAR szFileName[_MAX_PATH];
		::DragQueryFile(hDropInfo, iFile, szFileName, _MAX_PATH);

		if( iFile == 0 )
		{
			CColorConsole out;
			out << kBold << "Locating: " << kNormal << kUnderline << szFileName << kNormal <<  kNormal << kNL;

			CWincvsApp* pApp = (CWincvsApp *)AfxGetApp();
			if( pApp )
			{
				const TCHAR *p1, *p2 = szFileName;
				
				while( p2 )
				{
					p1 = ++p2;
					p2 = strchr(p2, _T('\\'));
				}			

				CWinCvsBrowser* pBrowser = pApp->GetBrowserView();
				if( pBrowser )
				{
					if( pBrowser->StepToLocation(szFileName, true) )
					{
						pApp->GetFileView()->ResetView(false, p1);
					}
				}
			}
		}

		// replace \ by /
		TCHAR *tmp = szFileName;
		while( (tmp = strchr(tmp, '\\')) != 0L )
		{
			*tmp++ = '/';
		}
		
		cvs_out("%s\n", szFileName);

		//pApp->OpenDocumentFile(szFileName);
	}//end for

	::DragFinish(hDropInfo);
}

void CMainFrame::OnInitMenu(CMenu* pMenu)
{
	CCJMDIFrameWnd::OnInitMenu(pMenu);

#if 0 // now it's in the resources
	// CG: This block added by 'Tip of the Day' component.
	{
		// TODO: This code adds the "Tip of the Day" menu item
		// on the fly.  It may be removed after adding the menu
		// item to all applicable menu items using the resource
		// editor.

		// Add Tip of the Day menu item on the fly!
		static CMenu* pSubMenu = NULL;

		CString strHelp; strHelp.LoadString(CG_IDS_TIPOFTHEDAYHELP);
		CString strMenu;
		int nMenuCount = pMenu->GetMenuItemCount();
		BOOL bFound = FALSE;
		for (int i=0; i < nMenuCount; i++) 
		{
			pMenu->GetMenuString(i, strMenu, MF_BYPOSITION);
			if (strMenu == strHelp)
			{ 
				pSubMenu = pMenu->GetSubMenu(i);
				bFound = TRUE;
				ASSERT(pSubMenu != NULL);
			}
		}

		CString strTipMenu;
		strTipMenu.LoadString(CG_IDS_TIPOFTHEDAYMENU);
		if (!bFound)
		{
			// Help menu is not available. Please add it!
			if (pSubMenu == NULL) 
			{
				// The same pop-up menu is shared between mainfrm and frame 
				// with the doc.
				static CMenu popUpMenu;
				pSubMenu = &popUpMenu;
				pSubMenu->CreatePopupMenu();
				pSubMenu->InsertMenu(0, MF_STRING|MF_BYPOSITION, 
					CG_IDS_TIPOFTHEDAY, strTipMenu);
			} 
			pMenu->AppendMenu(MF_STRING|MF_BYPOSITION|MF_ENABLED|MF_POPUP, 
				(UINT)pSubMenu->m_hMenu, strHelp);
			DrawMenuBar();
		} 
		else
		{      
			// Check to see if the Tip of the Day menu has already been added.
			pSubMenu->GetMenuString(0, strMenu, MF_BYPOSITION);

			if (strMenu != strTipMenu) 
			{
				// Tip of the Day submenu has not been added to the 
				// first position, so add it.
				pSubMenu->InsertMenu(0, MF_BYPOSITION);  // Separator
				pSubMenu->InsertMenu(0, MF_STRING|MF_BYPOSITION, 
					CG_IDS_TIPOFTHEDAY, strTipMenu);
			}
		}
	}
#endif
}

void CMainFrame::InitialShowWindow(int nCmdShow)
{
	if (gMainPlacement.hasOne) 
	{
		WINDOWPLACEMENT wp = gMainPlacement.placement;
		if (nCmdShow != SW_SHOWNORMAL)
			wp.showCmd = nCmdShow;
		else if (wp.showCmd & SW_SHOWMINIMIZED)
			wp.showCmd = (wp.flags & WPF_RESTORETOMAXIMIZED) ? SW_MAXIMIZE : SW_SHOWNORMAL;
		SetWindowPlacement(&wp);
	}
	else
	{
		ShowWindow(nCmdShow);
	}
}

void CMainFrame::OnHistorySelect()
{
	int nCurSel = m_browseHist.GetCurSel();
	CString s;
	m_browseHist.GetLBText(nCurSel, s);
	if(!s.IsEmpty())
	{
		CWincvsApp* app = (CWincvsApp *)AfxGetApp();
		app->GetBrowserView()->ResetBrowser(s, true);
		app->ActivateBrowserView();
	}
}

CWinCvsBrowser *CMainFrame::GetBrowserView()
{
	CBrowserBar *bar = (CBrowserBar *)m_wndWorkspace.GetView(0);
	return bar->GetBrowserView();
}

CCJShellTree *CMainFrame::GetExplorerView()
{
	CExploreBar *bar = (CExploreBar *)m_wndWorkspace.GetView(1);
	return &bar->m_TreeCtrl;
}

BOOL CMainFrame::OnBroadcastCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
	CPushRoutingFrame push(this);

	CWincvsApp* app = (CWincvsApp *)AfxGetApp();

	// pump through dock bars FIRST
	CWinCvsBrowser *bView = app->GetBrowserView();
	if (bView != NULL && bView == CWnd::GetFocus() && bView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
		return TRUE;
#ifndef NOEXPLOREVIEW
	// pump through dock bars FIRST
	CCJShellTree *eView = app->GetExplorerView();
	if (eView != NULL && eView == CWnd::GetFocus())
	{	
		if(eView->GetParent()->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
			return TRUE;
	}
#endif

	CWincvsView *cView = app->GetConsoleView();
	if (cView != NULL && cView == CWnd::GetFocus() && cView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
		return TRUE;

	return FALSE;
}

void CMainFrame::DropFiles(HDROP hDropInfo)
{
	OnDropFiles(hDropInfo);
}

void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
{
	CCJMDIFrameWnd::OnActivate(nState, pWndOther, bMinimized);
	
	// TODO: Add your message handler code here

	//JK - prevent the focus to be gone from FileView to the Workspace - for the Dialogs etc.
	CWincvsApp* pApp = (CWincvsApp*)AfxGetApp();
	ASSERT(pApp);

	if( WA_INACTIVE == nState && !m_bRestoreFocus )
	{
		m_bRestoreFocus = BOOL( GetFocus() == pApp->GetFileView() );
	}
	else
	{
		if( !bMinimized && m_bRestoreFocus )
		{
			m_bRestoreFocus = FALSE;
			CBrowseFileView* pBrowseFileView = pApp->GetFileView();
			if(pBrowseFileView)
			{
				pBrowseFileView->SetFocus();
			}
		}
	}
}

void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam) 
{
	// TODO: Add your message handler code here and/or call default

	//JK - prevent the focus to be gone from FileView to the Workspace - for the Minimize
	if( SC_MINIMIZE == nID )
	{
		CWincvsApp* pApp = (CWincvsApp*)AfxGetApp();
		ASSERT(pApp);
		
		m_bRestoreFocus = BOOL( GetFocus() == pApp->GetFileView() );
	}

	CCJMDIFrameWnd::OnSysCommand(nID, lParam);
}

void CMainFrame::OnViewRecursive() 
{
	m_recursion.ToggleRecursion();
	m_recursion.GetNotificationManager()->NotifyAll();
	OnFilterMaskEntered();	
}

void CMainFrame::OnUpdateViewRecursive(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(IsAppEnabled());
	pCmdUI->SetCheck(m_recursion.IsShowRecursive());
}

bool CMainFrame::FreshenFileMask() 
{
	CString strFileMask;
	m_comboFilterMask.GetWindowText(strFileMask);
	return m_filter.SetMask(strFileMask);
}

void CMainFrame::OnViewModified() 
{
	m_filter.ToggleModified();
	FreshenFileMask();
	m_filter.GetNotificationManager()->NotifyAll();
}

void CMainFrame::OnUpdateViewModified(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(IsAppEnabled());
	pCmdUI->SetCheck(m_filter.IsModified());
}

void CMainFrame::OnFilterMaskEntered()
{
	if (FreshenFileMask())
	{
		m_filter.GetNotificationManager()->NotifyAll();
	}
}

void CMainFrame::OnViewConflict() 
{
	m_filter.ToggleConflict();
	FreshenFileMask();
	m_filter.GetNotificationManager()->NotifyAll();
}

void CMainFrame::OnUpdateViewConflict(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(IsAppEnabled());
	pCmdUI->SetCheck(m_filter.IsConflict());
}

void CMainFrame::OnViewUnknown() 
{
	m_filter.ToggleUnknown();
	FreshenFileMask();
	m_filter.GetNotificationManager()->NotifyAll();
}

void CMainFrame::OnUpdateViewUnknown(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(IsAppEnabled());
	pCmdUI->SetCheck(m_filter.IsUnknown());
}

void CMainFrame::OnViewMissing() 
{
	m_filter.ToggleMissing();
	FreshenFileMask();
	m_filter.GetNotificationManager()->NotifyAll();
}

void CMainFrame::OnUpdateViewMissing(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(IsAppEnabled());
	pCmdUI->SetCheck(m_filter.IsMissing());	
}

void CMainFrame::OnViewIgnore() 
{
	m_ignore.ToggleIgnore();
	m_ignore.GetNotificationManager()->NotifyAll();
	OnFilterMaskEntered();
}

void CMainFrame::OnUpdateViewIgnore(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(IsAppEnabled());
	pCmdUI->SetCheck(m_ignore.IsShowIgnored());
}

void CMainFrame::OnUpdateFilterMask(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(IsAppEnabled());	
}

void CMainFrame::OnUpdateHistory(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(IsAppEnabled());		
}

void CMainFrame::OnViewAdded() 
{
	m_filter.ToggleAdded();
	FreshenFileMask();
	m_filter.GetNotificationManager()->NotifyAll();
}

void CMainFrame::OnUpdateViewAdded(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(IsAppEnabled());
	pCmdUI->SetCheck(m_filter.IsAdded());
}

void CMainFrame::OnUpdateViewRemoved(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(IsAppEnabled());
	pCmdUI->SetCheck(m_filter.IsRemoved());
}

void CMainFrame::OnViewRemoved() 
{
	m_filter.ToggleRemoved();
	FreshenFileMask();
	m_filter.GetNotificationManager()->NotifyAll();
}

void CMainFrame::OnViewChanged() 
{
	m_filter.ToggleChanged();
	FreshenFileMask();
	m_filter.GetNotificationManager()->NotifyAll();
}

void CMainFrame::OnUpdateViewChanged(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(IsAppEnabled());
	pCmdUI->SetCheck(m_filter.IsChanged());
}

void CMainFrame::OnViewHideunknown() 
{
	m_filter.ToggleHideUnknown();
	FreshenFileMask();
	m_filter.GetNotificationManager()->NotifyAll();
}

void CMainFrame::OnUpdateViewHideunknown(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(IsAppEnabled() && m_filter.IsDefaultMode());	
	pCmdUI->SetCheck(m_filter.IsHideUnknown());
}

static bool sAskingMainThread;
static UStr sGetEnvResult;

static CSemaphore sGetEnv(0);

char *CMainFrame::GetEnvMainThread(const char *name)
{
	ASSERT(::GetCurrentThreadId() != AfxGetApp()->m_nThreadID);

	sGetEnvResult = name;
	sAskingMainThread = true;

	sGetEnv.Lock();

	return sGetEnvResult;
}

void CMainFrame::OnTimer(UINT nIDEvent) 
{
	if(sAskingMainThread)
	{
		sAskingMainThread = false;

		sGetEnvResult = glue_getenv(sGetEnvResult);
		sGetEnv.Unlock();
	}
}
