// XTPReportView.cpp : implementation of the CXTPReportView class.
//
// This file is a part of the XTREME REPORTCONTROL MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"


#include "Common/XTPDrawHelpers.h"
#include "Common/XTPImageManager.h"
#include "Common/XTPCustomHeap.h"
#include "Common/XTPSystemHelpers.h"
#include "Common/XTPSmartPtrInternalT.h"
#include "Common/XTPColorManager.h"

#include "Resource.h"


#include "XTPReportDefines.h"
#include "XTPReportControl.h"
#include "XTPReportView.h"
#include "XTPReportColumn.h"
#include "XTPReportColumns.h"
#include "XTPReportRows.h"
#include "XTPReportSection.h"
#include "XTPReportSelectedRows.h"
#include "XTPReportPaintManager.h"
#include "XTPReportPageSetupDialog.h"


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


/////////////////////////////////////////////////////////////////////////////
// CXTPReportView

IMPLEMENT_DYNCREATE(CXTPReportView, CView)

CXTPReportView::CXTPReportView()
	: m_nColumnStart(0)
	, m_nColumnEnd  (0)

	, m_pScrollBarVer(NULL)
	, m_pScrollBarHor(NULL)
	, m_pSlider      (NULL)
{
	m_pReport = NULL;
	m_pPrintOptions = new CXTPReportViewPrintOptions();

	m_bPrintSelection = FALSE;
	m_bPaginated = FALSE;

	m_bPrintDirect = FALSE;
	m_bResizeControlWithView = TRUE;

	m_bAllowCut = TRUE;
	m_bAllowPaste = TRUE;


	m_nStartIndex = 0;
	m_bSwitchMode = FALSE;
}

CXTPReportView::~CXTPReportView()
{
	CMDTARGET_RELEASE(m_pPrintOptions);
	SAFE_DELETE(m_pReport);
}


CXTPReportControl& CXTPReportView::GetReportCtrl() const
{
	return m_pReport == NULL ? (CXTPReportControl&)m_wndReport : *m_pReport;
}

void CXTPReportView::SetReportCtrl(CXTPReportControl* pReport)
{
	if (::IsWindow(m_wndReport.GetSafeHwnd()))
		m_wndReport.DestroyWindow();

	m_pReport = pReport;
}

void CXTPReportView::SetScrollBarCtrl(CScrollBar* pScrollBar, BOOL bHor)
{
	if (bHor)
	{
		m_pScrollBarHor = pScrollBar;
	}
	else
	{
		m_pScrollBarVer = pScrollBar;
	}
}

void CXTPReportView::SetSliderCtrl(CSliderCtrl* pSlider)
{
	m_pSlider = pSlider;
}

BEGIN_MESSAGE_MAP(CXTPReportView, CView)
	//{{AFX_MSG_MAP(CXTPReportView)
	ON_WM_ERASEBKGND()
	ON_WM_SIZE()
	ON_WM_CREATE()
	ON_WM_SETFOCUS()
	ON_WM_PAINT()
	ON_WM_VSCROLL()
	ON_WM_HSCROLL()
	ON_COMMAND(ID_FILE_PRINT, OnFilePrint)
	ON_COMMAND(ID_EDIT_CUT, OnEditCut)
	ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
	ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
	ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
	ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
	ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCut)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CXTPReportView drawing

void CXTPReportView::OnDraw(CDC* pDC)
{
	UNREFERENCED_PARAMETER(pDC);
}

void CXTPReportView::OnPaint()
{
	Default();
}

BOOL CXTPReportView::OnEraseBkgnd(CDC* pDC)
{
	UNREFERENCED_PARAMETER(pDC);
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CXTPReportView diagnostics

#ifdef _DEBUG
void CXTPReportView::AssertValid() const
{
	CView::AssertValid();
}

void CXTPReportView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CXTPReportView message handlers

CScrollBar* CXTPReportView::GetScrollBarCtrl(int nBar) const
{
	if (nBar == SB_VERT && m_pScrollBarVer)
		return m_pScrollBarVer;

	if (nBar == SB_HORZ && m_pScrollBarHor)
		return m_pScrollBarHor;

	return CView::GetScrollBarCtrl(nBar);
}

void CXTPReportView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	if (m_pScrollBarVer && pScrollBar == m_pScrollBarVer)
	{
		GetReportCtrl().OnVScroll(nSBCode, nPos, 0);
	}

	CView::OnVScroll(nSBCode, nPos, pScrollBar);
}

void CXTPReportView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	if (m_pScrollBarHor && pScrollBar == m_pScrollBarHor)
	{
		GetReportCtrl().OnHScroll(nSBCode, nPos, 0);
	}

	CView::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CXTPReportView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);

	int nScroll = GetSystemMetrics(SM_CXVSCROLL);
	//SM_CXVSCROLL SM_CYHSCROLL SM_CXBORDER SM_CYBORDER
	int dx = 0;
	if (GetPaintManager()->m_bMoveScrollbarOnFixedColumnsIndent)
		dx = GetPaintManager()->m_nFixedColumnsIndent;

	BOOL bV = (m_pScrollBarVer != NULL) && (m_pScrollBarVer->GetSafeHwnd() != NULL);
	BOOL bH = (m_pScrollBarHor != NULL) && (m_pScrollBarHor->GetSafeHwnd() != NULL);

	CRect rc; GetClientRect(&rc);
	cx = rc.Width();
	cy = rc.Height();

	int CX = cx;
	int CY = cy;

	if (bV || bH)
	{
		if (bV && bH)
		{
			cx -= nScroll;
			cy -= nScroll;
		}
		else if (bV)
		{
			cx -= nScroll;
		}
		else if (bH)
		{
			cy -= nScroll;
		}

		// Right-to-left
		if (GetReportCtrl().IsLayoutRTL())
		{
			if (bV)
			{
				m_pScrollBarVer->MoveWindow(0, 0, nScroll, cy);
			}
			if (bH)
			{
				m_pScrollBarHor->MoveWindow(0, cy, CX - dx, nScroll);

				if (WS_EX_LAYOUTRTL != (m_pScrollBarHor->GetExStyle() & WS_EX_LAYOUTRTL))
				{
					// Turn RTL on
					m_pScrollBarHor->ModifyStyleEx(0, WS_EX_LAYOUTRTL);
				}
			}

			if (m_pSlider)
			{
				if (dx)
				{
					m_pSlider->MoveWindow(CX - dx, cy, dx, nScroll);
					m_pSlider->ShowWindow(SW_SHOW);
				}
				else
				{
					m_pSlider->MoveWindow(CX - dx, cy, dx, nScroll);
					m_pSlider->ShowWindow(SW_HIDE);
				}
			}
		}
		// Left-to-right
		else
		{
			if (bV)
			{
				m_pScrollBarVer->MoveWindow(cx, 0, nScroll, cy);
			}
			if (bH)
			{
				m_pScrollBarHor->MoveWindow(dx, cy, CX - dx, nScroll);

				if (WS_EX_LAYOUTRTL == (m_pScrollBarHor->GetExStyle() & WS_EX_LAYOUTRTL))
				{
					// Turn RTL off
					m_pScrollBarHor->ModifyStyleEx(WS_EX_LAYOUTRTL, 0);
				}
			}

			if (m_pSlider)
			{
				if (dx)
				{
					m_pSlider->MoveWindow(0, cy, dx, nScroll);
					m_pSlider->ShowWindow(SW_SHOW);
				}
				else
				{
					m_pSlider->MoveWindow(0, cy, dx, nScroll);
					m_pSlider->ShowWindow(SW_HIDE);
				}
			}
		}
	}
	else
		nScroll = 0;

	if (m_bResizeControlWithView && GetReportCtrl().GetSafeHwnd())
	{
		if (nScroll > 0)
		{
			if (GetReportCtrl().IsLayoutRTL())
			{
				if (bV)
					GetReportCtrl().MoveWindow(nScroll, 0, cx, cy);
				else
					GetReportCtrl().MoveWindow(0, 0, cx, cy);
			}
			else
			{
				if (bV)
					GetReportCtrl().MoveWindow(0, 0, cx, cy);
				else
					GetReportCtrl().MoveWindow(0, 0, cx, cy);
			}
		}
		else
		{
			GetReportCtrl().MoveWindow(0, 0, CX, CY);
		}
	}
}

BOOL CXTPReportView::PreCreateWindow(CREATESTRUCT &cs)
{
	cs.style |= WS_CLIPCHILDREN|WS_CLIPSIBLINGS;

	return CView::PreCreateWindow(cs);
}

int CXTPReportView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	if (!GetReportCtrl().Create(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE,
		CRect(0, 0, 0, 0), this, XTP_ID_REPORT_CONTROL))
	{
		TRACE(_T("Failed to create report control window\n"));
		return -1;
	}

	return 0;
}

void CXTPReportView::OnSetFocus(CWnd* pOldWnd)
{
	CView::OnSetFocus(pOldWnd);

	if (IsWindow(GetReportCtrl().GetSafeHwnd()))
		GetReportCtrl().SetFocus();
}


/////////////////////////////////////////////////////////////////////////////

BOOL CXTPReportView::OnPreparePrinting(CPrintInfo* pInfo)
{
	if (GetReportCtrl().IsIconView())
	{
		GetReportCtrl().SetIconView(FALSE);
		m_bSwitchMode = TRUE;
	}

	m_bShowRowNumber = GetReportCtrl().IsShowRowNumber();
	GetReportCtrl().ShowRowNumber(FALSE);

	if (GetReportCtrl().GetSelectedRows()->GetCount() > 0)
		pInfo->m_pPD->m_pd.Flags &= ~PD_NOSELECTION;

	pInfo->m_bDirect = m_bPrintDirect;

	// default preparation
	if (!DoPreparePrinting(pInfo))
		return FALSE;

	m_bPrintSelection = pInfo->m_pPD->PrintSelection();

	return TRUE;
}

void CXTPReportView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	m_aPageStart.RemoveAll();

	if (m_pPrintOptions->m_bBlackWhitePrinting)
		m_bmpGrayDC.DeleteObject();

	if (m_bSwitchMode)
	{
		GetReportCtrl().SetIconView(TRUE);
		m_bSwitchMode = FALSE;
	}
	GetReportCtrl().ShowRowNumber(m_bShowRowNumber);
}

CXTPReportPaintManager* CXTPReportView::GetPaintManager() const
{
	return GetReportCtrl().GetPaintManager();
}

void CXTPReportView::PrintHeader(CDC *pDC, CRect rcHeader)
{
	CXTPReportColumns *pColumns = GetReportCtrl().GetColumns();

	GetPaintManager()->FillHeaderControl(pDC, rcHeader);

	int x = rcHeader.left;
	int nWidth;

	for (int nColumn=m_nColumnStart; nColumn<m_nColumnEnd; nColumn++)
	{
		CXTPReportColumn *pColumn = pColumns->GetAt(nColumn);
		if (pColumn->IsVisible())
		{
			if (GetPaintManager()->IsColumnWidthWYSIWYG())
			{
				nWidth = pColumn->GetWidth();
			}
			else
			{
				nWidth = pColumn->GetPrintWidth(rcHeader.Width());
			}
			CRect rcItem(x, rcHeader.top, x + nWidth, rcHeader.bottom);
			GetPaintManager()->DrawColumn(pDC, pColumn, GetReportCtrl().GetReportHeader(), rcItem);
			x += nWidth;
		}
	}
}

void CXTPReportView::PrintFooter(CDC* pDC, CRect rcFooter)
{
	CXTPReportColumns* pColumns = GetReportCtrl().GetColumns();

	GetPaintManager()->FillFooter(pDC, rcFooter);

	int x = rcFooter.left;
	int nWidth(0);
	for (int nColumn=m_nColumnStart; nColumn<m_nColumnEnd; nColumn++)
	{
		CXTPReportColumn* pColumn = pColumns->GetAt(nColumn);
		if (!pColumn->IsVisible())
			continue;

		if (GetPaintManager()->IsColumnWidthWYSIWYG())
			nWidth = pColumn->GetWidth();
		else
			nWidth = pColumn->GetPrintWidth(rcFooter.Width());
		CRect rcItem(x, rcFooter.top, x + nWidth, rcFooter.bottom);
		GetPaintManager()->DrawColumnFooter(pDC, pColumn, GetReportCtrl().GetReportHeader(), rcItem);
		x += nWidth;
	}
}


int CXTPReportView::PrintReport(CDC *pDC, CPrintInfo *pInfo, CRect rcPage,
	int nRowFrom, int nColumnFrom, int nColumnTo)
{
	CXTPReportControl &wndReport = GetReportCtrl();

	int nMaxPages = -1;
	if (pInfo->GetMaxPage() != 65535)
		nMaxPages = pInfo->GetMaxPage();

	if (GetPaintManager()->m_bPrintWatermark)
	{
		CRect rcWater(rcPage);
		CRect rcClient(0, 0, rcWater.Width(), rcWater.Height());

		wndReport.DrawWatermark(pDC, rcWater, rcClient);
	}

	int nHeaderHeight = PrintPageHeader(pDC, pInfo, rcPage, FALSE,
		pInfo->m_nCurPage, nMaxPages,
		m_nStartIndex, (int) GetPaintManager()->m_arStartCol.GetSize() - 1);

	int nFooterHeight = PrintPageFooter(pDC, pInfo, rcPage, FALSE,
		pInfo->m_nCurPage, nMaxPages,
		m_nStartIndex, (int) GetPaintManager()->m_arStartCol.GetSize() - 1);

	CRect rcRows(rcPage);

	if (GetPaintManager()->m_bPrintPageRectangle)
	{
		rcRows.DeflateRect(1,1);
	}

	rcRows.top += nHeaderHeight;
	rcRows.bottom -= nFooterHeight;
	int nFooterTop = rcRows.bottom;


	// print header rows (if exist and visible)
	if (wndReport.GetHeaderRows()->GetCount() > 0 && GetReportCtrl().IsHeaderRowsVisible())
	{
		// print on the first page, at least
		if (0 == nRowFrom || m_pPrintOptions->m_bRepeatHeaderRows)
		{
			int nHeight = 0;
			wndReport.DrawRows(pDC, rcRows, rcRows.top, wndReport.GetHeaderRows(), 0, nColumnFrom, nColumnTo, &nHeight);
			rcRows.top += nHeight;

			// print divider
			rcRows.top += PrintFixedRowsDivider(pDC, rcRows, TRUE);
		}
	}

	// calculate space for footer rows
	int nNeedForFooterRows = 0;

	if (wndReport.GetFooterRows()->GetCount() > 0 && GetReportCtrl().IsFooterRowsVisible())
	{
		nNeedForFooterRows = wndReport.GetRowsHeight(GetReportCtrl().GetFooterRows(), rcRows.Width());
		nNeedForFooterRows += GetPaintManager()->GetSectionDividerHeight(wndReport.m_pSectionFooter->GetDividerStyle());

		if (m_pPrintOptions->m_bRepeatFooterRows)
		{
			// decrease space for body rows, if footer rows to be repeated on every page.
			rcRows.bottom = nFooterTop - nNeedForFooterRows;
		}
	}

	// print body rows
	int nPrintedBodyRowsHeight = 0;
	nRowFrom = wndReport.DrawRows(pDC, rcRows, rcRows.top, wndReport.GetRows(), nRowFrom, nColumnFrom, nColumnTo, &nPrintedBodyRowsHeight);

	// print footer rows (if exist and visible)
	if (nNeedForFooterRows > 0)
	{
		CRect rcFooterRows(rcRows);

		if (wndReport.IsFooterRowsPinnedPrinted())
		{
			rcFooterRows.top    = rcRows.top + nPrintedBodyRowsHeight; //immediately after body rows
			rcFooterRows.bottom = nFooterTop;
		}
		else
		{
			rcFooterRows.top    = nFooterTop - nNeedForFooterRows;
			rcFooterRows.bottom = nFooterTop;
		}

		// one more check, if there is enough space for footer divider + footer rows
		if (rcFooterRows.Height() >= nNeedForFooterRows)
		{
			// print divider
			rcFooterRows.top += PrintFixedRowsDivider(pDC, rcFooterRows, FALSE);

			// print footer rows
			int nHeight = 0;
			wndReport.DrawRows(pDC, rcFooterRows, rcFooterRows.top, wndReport.GetFooterRows(), 0, nColumnFrom, nColumnTo, &nHeight);
		}
	}

	if (GetPaintManager()->m_bPrintPageRectangle)
	{
		pDC->Draw3dRect(rcPage, 0, 0);
	}

	return nRowFrom;
}

int CXTPReportView::PrintFixedRowsDivider(CDC* pDC, const CRect& rc, BOOL bHeaderRows)
{
	CRect rcDivider(rc);

	XTPReportSectionDividerPosition dividerPosition = bHeaderRows
		? GetReportCtrl().m_pSectionHeader->GetDividerPosition()
		: GetReportCtrl().m_pSectionFooter->GetDividerPosition();

	XTPReportFixedRowsDividerStyle dividerStyle = bHeaderRows
		? GetReportCtrl().m_pSectionHeader->GetDividerStyle()
		: GetReportCtrl().m_pSectionFooter->GetDividerStyle();

	CXTPPaintManagerColor dividerColor = bHeaderRows
		? GetReportCtrl().m_pSectionHeader->GetDividerColor()
		: GetReportCtrl().m_pSectionHeader->GetDividerColor();

	int nHeight = GetPaintManager()->GetSectionDividerHeight(dividerStyle);

	rcDivider.bottom = rcDivider.top + nHeight;

	GetPaintManager()->DrawSectionDivider(pDC, rcDivider, dividerPosition, dividerStyle, dividerColor);

	return nHeight;
}

int CXTPReportView::PrintPage(CDC *pDC, CPrintInfo *pInfo, CRect rcPage,
	int nRowFrom, int nColumnFrom, int nColumnTo)
{
	if (!m_pPrintOptions || !pDC || !pInfo)
	{
		ASSERT(FALSE);
		return INT_MAX;
	}

	CRect rcPageHeader = rcPage;
	CRect rcPageFooter = rcPage;

	CString strTitle = CXTPPrintPageHeaderFooter::GetParentFrameTitle(this);

	int N = (int) GetPaintManager()->m_arStartCol.GetSize() - 1;
	int nVirPage(0);
	if (N > 0)
		nVirPage = 1 + m_nStartIndex;

	if (GetPaintManager()->m_bPrintVirtualPageNumber)
	{
		m_pPrintOptions->GetPageHeader()->FormatTexts(pInfo, strTitle, nVirPage);
		m_pPrintOptions->GetPageFooter()->FormatTexts(pInfo, strTitle, nVirPage);
	}
	else
	{
		m_pPrintOptions->GetPageHeader()->FormatTexts(pInfo, strTitle);
		m_pPrintOptions->GetPageFooter()->FormatTexts(pInfo, strTitle);
	}

	m_pPrintOptions->GetPageHeader()->Draw(pDC, rcPageHeader);
	m_pPrintOptions->GetPageFooter()->Draw(pDC, rcPageFooter);

	CRect rcReport = rcPage;
	rcReport.top    += rcPageHeader.Height() + 2;
	rcReport.bottom -= rcPageFooter.Height() + 2;

	nRowFrom = PrintReport(pDC, pInfo, rcReport, nRowFrom, nColumnFrom, nColumnTo);

	return nRowFrom;
}

int CXTPReportView::PrintPageHeader(CDC* pDC, CPrintInfo* pInfo, CRect rcPage,
					BOOL bOnlyCalculate, int nPageNumber, int nNumberOfPages,
					int nHorizontalPageNumber, int nNumberOfHorizontalPages)
{
	UNREFERENCED_PARAMETER(pInfo);
	UNREFERENCED_PARAMETER(nPageNumber);
	UNREFERENCED_PARAMETER(nNumberOfPages);
	UNREFERENCED_PARAMETER(nHorizontalPageNumber);
	UNREFERENCED_PARAMETER(nNumberOfHorizontalPages);
	UNREFERENCED_PARAMETER(bOnlyCalculate);
	UNREFERENCED_PARAMETER(nPageNumber);
	UNREFERENCED_PARAMETER(nHorizontalPageNumber);
	UNREFERENCED_PARAMETER(nNumberOfHorizontalPages);

	int nHeaderHeight = 0;

	if (GetPaintManager()->m_bPrintPageRectangle)
		rcPage.DeflateRect(1,1);

	if (GetReportCtrl().IsHeaderVisible())
		nHeaderHeight = GetPaintManager()->GetHeaderHeight(&GetReportCtrl(), pDC, rcPage.Width());

	rcPage.bottom = rcPage.top + nHeaderHeight;

	if (nHeaderHeight)
		PrintHeader(pDC, rcPage);

	return nHeaderHeight;
}

int CXTPReportView::PrintPageFooter(CDC* pDC, CPrintInfo* pInfo, CRect rcPage,
					BOOL bOnlyCalculate, int nPageNumber, int nNumberOfPages,
					int nHorizontalPageNumber, int nNumberOfHorizontalPages)
{
	UNREFERENCED_PARAMETER(pInfo);
	UNREFERENCED_PARAMETER(nPageNumber);
	UNREFERENCED_PARAMETER(nNumberOfPages);
	UNREFERENCED_PARAMETER(nHorizontalPageNumber);
	UNREFERENCED_PARAMETER(nNumberOfHorizontalPages);
	UNREFERENCED_PARAMETER(bOnlyCalculate);
	UNREFERENCED_PARAMETER(nPageNumber);
	UNREFERENCED_PARAMETER(nHorizontalPageNumber);
	UNREFERENCED_PARAMETER(nNumberOfHorizontalPages);

	int nFooterHeight = 0;

	if (GetPaintManager()->m_bPrintPageRectangle)
		rcPage.DeflateRect(1,1);

	if (GetReportCtrl().IsFooterVisible())
		nFooterHeight = GetPaintManager()->GetFooterHeight(&GetReportCtrl(), pDC, rcPage.Width());

	rcPage.top = rcPage.bottom - nFooterHeight;

	if (nFooterHeight)
		PrintFooter(pDC, rcPage);

	return nFooterHeight;
}

int CXTPReportView::SetupStartCol(CDC* pDC, CPrintInfo* pInfo)
{
	pDC->SetMapMode(MM_ANISOTROPIC);
	pDC->SetViewportExt(pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY));
	pDC->SetWindowExt(96, 96);
	pDC->OffsetWindowOrg(0, 0);

	pInfo->m_rectDraw.SetRect(0, 0, pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
	pDC->DPtoLP(&pInfo->m_rectDraw);

	CRect rcMargins = m_pPrintOptions->GetMarginsLP(pDC);
	CRect rc = pInfo->m_rectDraw;
	rc.DeflateRect(rcMargins);
	GetPaintManager()->m_PrintPageWidth = rc.Width();
	GetPaintManager()->m_arStartCol.RemoveAll();
	GetPaintManager()->m_arStartCol.Add(0);
	CXTPReportColumns* pColumns = GetReportCtrl().GetColumns();
	int nColumnCount = pColumns->GetCount();

	if (GetPaintManager()->IsColumnWidthWYSIWYG())
	{
		int x = 0;
		for (int nColumn = 0; nColumn < nColumnCount; nColumn++)
		{
			CXTPReportColumn* pColumn = pColumns->GetAt(nColumn);
			if (pColumn && pColumn->IsVisible())
			{
				int nWidth = pColumn->GetWidth();

				if (x + nWidth <= GetPaintManager()->m_PrintPageWidth)
				{
					x += nWidth;
				}
				else
				{
					GetPaintManager()->m_arStartCol.Add(nColumn);
					x = nWidth;
				}
			}
		}
	}
	GetPaintManager()->m_arStartCol.Add(nColumnCount);

	return (int) GetPaintManager()->m_arStartCol.GetSize() - 1;
}


//struct CPrintInfo // Printing information structure
//  CPrintDialog* m_pPD;     // pointer to print dialog
//  BOOL m_bPreview;         // TRUE if in preview mode
//  BOOL m_bDirect;          // TRUE if bypassing Print Dialog
//  BOOL m_bContinuePrinting;// set to FALSE to prematurely end printing
//  UINT m_nCurPage;         // Current page
//  UINT m_nNumPreviewPages; // Desired number of preview pages
//  CString m_strPageDesc;   // Format string for page number display
//  void SetMinPage(UINT nMinPage);
//  void SetMaxPage(UINT nMaxPage);
//  UINT GetMinPage() const;
//  UINT GetMaxPage() const;
//  UINT GetFromPage() const;
//  UINT GetToPage() const;
void CXTPReportView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
{
	m_aPageStart.RemoveAll();
	m_aPageStart.Add(0);

	int nVirtualPages = SetupStartCol(pDC, pInfo);
	if (pInfo->m_bPreview)
	{
		pInfo->m_nNumPreviewPages = 1;
		AfxGetApp()->m_nNumPreviewPages = pInfo->m_nNumPreviewPages;
	}

	CString str1, str2;
	if (m_pPrintOptions && m_pPrintOptions->GetPageHeader())
		str1 = m_pPrintOptions->GetPageHeader()->m_strFormatString;
	if (m_pPrintOptions && m_pPrintOptions->GetPageFooter())
		str2 = m_pPrintOptions->GetPageFooter()->m_strFormatString;

	if (nVirtualPages > 1 && m_pPrintOptions->GetPageHeader()->m_strFormatString.IsEmpty())
		m_pPrintOptions->GetPageHeader()->m_strFormatString = _T(" &p/&P ");

	UINT pFr = pInfo->GetFromPage();
	UINT pTo = pInfo->GetToPage();
	if (pFr > 0)
	{
		pInfo->SetMinPage(pFr);
		pInfo->m_nCurPage = pFr;
	}

	if (pTo < 65535)
	{
		pInfo->SetMaxPage(pTo);
	}

	if (GetReportCtrl().m_bForcePagination)
	{
		m_bPaginated = FALSE;
	}

	if ((!pInfo->m_bPreview || GetReportCtrl().m_bForcePagination)
		&& (str1.Find(_T("&P")) >= 0
		|| nVirtualPages > 1
		|| pFr > 1
		|| pTo < 65535
		|| str2.Find(_T("&P")) >= 0))
	{
		m_nStartIndex = 0;
		m_nColumnStart = GetPaintManager()->m_arStartCol.GetAt(0);
		m_nColumnEnd   = GetPaintManager()->m_arStartCol.GetAt(1);

		int nCurPage = pInfo->m_nCurPage;
		pInfo->m_nCurPage = 65535;

		if (PaginateTo(pDC, pInfo))
			pInfo->SetMaxPage((int) m_aPageStart.GetSize() - 1 - m_nStartIndex);

		pInfo->m_nCurPage = nCurPage;
		if (GetReportCtrl().m_bForcePagination)
		{
			m_bPaginated = TRUE;
		}
	}
	m_nStartIndex = 0;
	m_nColumnStart = GetPaintManager()->m_arStartCol.GetAt(0);
	m_nColumnEnd   = GetPaintManager()->m_arStartCol.GetAt(1);
}

void CXTPReportView::OnPrint(CDC *pDC, CPrintInfo *pInfo)
{
	if (!m_pPrintOptions || !pDC || !pInfo)
	{
		ASSERT(FALSE);
		return;
	}
	CRect rcMargins = m_pPrintOptions->GetMarginsLP(pDC);
	CRect rc = pInfo->m_rectDraw;
	rc.DeflateRect(rcMargins);

	UINT nVirtualPages = (UINT) GetPaintManager()->m_arStartCol.GetSize() - 1;
	UINT nPage = pInfo->m_nCurPage;
	int nSize = (int) m_aPageStart.GetSize();

	ASSERT(nPage <= (UINT) nSize);

	UINT nIndex = m_aPageStart[nPage - 1];
	UINT mIndex(0);

	//if (m_bPaginated)
	{
		m_nStartIndex = (pInfo->m_nCurPage - 1) % nVirtualPages;
		m_nColumnStart = GetPaintManager()->m_arStartCol.GetAt(m_nStartIndex);
		m_nColumnEnd   = GetPaintManager()->m_arStartCol.GetAt(m_nStartIndex + 1);
	}

	//TRACE(_T("CXTPReportView::OnPrint %d %d %d %d %d\n"), pInfo->m_nCurPage, nVirtualPages, m_nStartIndex, m_nColumnStart, m_nColumnEnd);

	if (!m_pPrintOptions->m_bBlackWhitePrinting)
	{
		mIndex = PrintPage(pDC, pInfo, rc, nIndex, m_nColumnStart, m_nColumnEnd);
	}
	else
	{
		CRect rc00(0, 0, rc.Width(), rc.Height());

		CDC memDC;
		VERIFY(memDC.CreateCompatibleDC(pDC));
		memDC.m_bPrinting = TRUE;

		if (!m_bmpGrayDC.m_hObject
			|| m_bmpGrayDC.GetBitmapDimension() != rc00.Size())
		{
			m_bmpGrayDC.DeleteObject();
			m_bmpGrayDC.CreateCompatibleBitmap(pDC, rc00.Width(), rc00.Height());
		}

		CXTPBitmapDC autpBmp(&memDC, &m_bmpGrayDC);

		memDC.FillSolidRect(rc00, RGB(255, 255, 255));

		mIndex = PrintPage(&memDC, pInfo, rc00, nIndex, m_nColumnStart, m_nColumnEnd);

		int nCC = max(0, min(m_pPrintOptions->m_nBlackWhiteContrast, 255));
		XTPImageManager()->BlackWhiteBitmap(memDC, rc00, nCC);

		pDC->BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY);
	}

	if (!m_bPaginated)
	{
		m_nStartIndex++;
		if (m_nStartIndex >= nVirtualPages) //done with the page!
			m_nStartIndex = 0;

		m_nColumnStart = GetPaintManager()->m_arStartCol.GetAt(m_nStartIndex);
		m_nColumnEnd   = GetPaintManager()->m_arStartCol.GetAt(m_nStartIndex + 1);

		if (m_nStartIndex > 0)
		{
			if (nPage == (UINT) nSize)
				m_aPageStart.Add(nIndex);
			else if (nPage < (UINT) nSize)
				m_aPageStart[nPage] = nIndex;
		}
		else
		{
			if (nPage == (UINT) nSize)
				m_aPageStart.Add(mIndex);
			else if (nPage < (UINT) nSize)
				m_aPageStart[nPage] = mIndex;

			if ((int) mIndex == GetReportCtrl().GetRows()->GetCount())
				pInfo->SetMaxPage(pInfo->m_nCurPage);
		}
	}

	if (pInfo->m_bPreview)
	{
		pInfo->m_nCurPage++;
	}
}

extern BOOL CALLBACK _XTPAbortProc(HDC, int);

BOOL CXTPReportView::PaginateTo(CDC* pDC, CPrintInfo* pInfo)
{
	ASSERT_VALID(this);
	ASSERT_VALID(pDC);

	UINT nVirtualPages = (UINT) GetPaintManager()->m_arStartCol.GetSize() - 1;
	BOOL bAborted = FALSE;
	CXTPPrintingDialog PrintStatus(this);
	CString strTemp;
	if (GetParentFrame())
		GetParentFrame()->GetWindowText(strTemp);

	PrintStatus.SetWindowText(_T("Calculating pages..."));
	PrintStatus.SetDlgItemText(AFX_IDC_PRINT_DOCNAME, strTemp);
	PrintStatus.SetDlgItemText(AFX_IDC_PRINT_PRINTERNAME, pInfo->m_pPD->GetDeviceName());
	PrintStatus.SetDlgItemText(AFX_IDC_PRINT_PORTNAME, pInfo->m_pPD->GetPortName());
	PrintStatus.ShowWindow(SW_SHOW);
	PrintStatus.UpdateWindow();

	CRect rectSave = pInfo->m_rectDraw;
	UINT nPageSave = pInfo->m_nCurPage;
	BOOL bBlackWhiteSaved = m_pPrintOptions->m_bBlackWhitePrinting;
	m_pPrintOptions->m_bBlackWhitePrinting = FALSE;

	ASSERT(nPageSave > 1);
	ASSERT(nPageSave >= (UINT) m_aPageStart.GetSize());
	VERIFY(pDC->SaveDC() != 0);

	pDC->IntersectClipRect(0, 0, 0, 0);
	UINT nCurPage = (UINT) m_aPageStart.GetSize();
	pInfo->m_nCurPage = nCurPage;

	while (pInfo->m_nCurPage < nPageSave && pInfo->m_nCurPage <= pInfo->GetMaxPage())
	{
		if (pInfo->m_bPreview)
			ASSERT(pInfo->m_nCurPage == (UINT) m_aPageStart.GetSize());

		OnPrepareDC(pDC, pInfo);

		if (!pInfo->m_bContinuePrinting)
			break;
		if (nVirtualPages > 1)
			strTemp.Format(_T("%d [%d - %d]"),
				pInfo->m_nCurPage,
				1 + (pInfo->m_nCurPage / nVirtualPages),
				1 + (pInfo->m_nCurPage % nVirtualPages));
		else
			strTemp.Format(_T("%d"), pInfo->m_nCurPage);

		PrintStatus.SetDlgItemText(AFX_IDC_PRINT_PAGENUM, strTemp);

		pInfo->m_rectDraw.SetRect(0, 0, pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
		pDC->DPtoLP(&pInfo->m_rectDraw);

		OnPrint(pDC, pInfo);

		if (!pInfo->m_bPreview)
			pInfo->m_nCurPage++;

		if (pInfo->GetMaxPage() == 65535)
			pInfo->SetMaxPage(max(pInfo->GetMaxPage(), pInfo->m_nCurPage));

		if (!_XTPAbortProc(0, 0))
		{
			bAborted = TRUE;
			break;
		}
	}
	PrintStatus.DestroyWindow();

	BOOL bResult = !bAborted
		&& (pInfo->m_nCurPage == nPageSave || nPageSave == 65535);

	pInfo->m_bContinuePrinting = bResult;
	pDC->RestoreDC(-1);
	m_pPrintOptions->m_bBlackWhitePrinting = bBlackWhiteSaved;
	pInfo->m_nCurPage = nPageSave;

	pInfo->m_rectDraw = rectSave;
	ASSERT_VALID(this);

	return bResult;
}

void CXTPReportView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
	ASSERT_VALID(this);
	ASSERT_VALID(pDC);
	if (!pInfo)
		return;

	if (!m_bPaginated)
	{
		int nRowCount = GetReportCtrl().GetRows()->GetCount();
		int nSize = (int) m_aPageStart.GetSize();
		int nPage = pInfo->m_nCurPage;
		UINT nVirtualPages = (UINT) GetPaintManager()->m_arStartCol.GetSize() - 1;
		UINT nVirPage(0);
		if (nVirtualPages > 0)
			nVirPage = 1 + m_nStartIndex;

		if (nPage == 1 && nRowCount == 0)                       //First page?
			pInfo->m_bContinuePrinting = TRUE;
		else if (nVirPage > 0 && nVirPage < nVirtualPages)      //not finished page
			pInfo->m_bContinuePrinting = TRUE;
		else if (nPage == nSize && m_aPageStart[nPage - 1] >= (UINT) nRowCount
			&& m_nStartIndex >= nVirtualPages - 1)              //Last page?
			pInfo->m_bContinuePrinting = FALSE;                 // can't paginate to that page
		else if (nPage > nSize
			&& m_nStartIndex > nVirtualPages - 1
			&& !PaginateTo(pDC, pInfo))                         //Can be last page?
			pInfo->m_bContinuePrinting = FALSE;                 // can't paginate to that page

		if (pInfo->m_nCurPage > pInfo->GetMaxPage())
			pInfo->m_bContinuePrinting = FALSE;
//TRACE(_T("OnPrepareDC pInfo->m_nCurPage=%d\n"), pInfo->m_nCurPage);
	}
	pDC->SetMapMode(MM_ANISOTROPIC);
	pDC->SetViewportExt(pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY));
	pDC->SetWindowExt(96, 96);
	pDC->OffsetWindowOrg(0, 0);

	if (pInfo->m_bPreview) //PRINT MODE in RTL does not work!
	{
//------------------------------------------------------------
	if (GetReportCtrl().GetExStyle() & WS_EX_RTLREADING)
		pDC->SetTextAlign(TA_RTLREADING);

		if (GetReportCtrl().GetExStyle() & WS_EX_LAYOUTRTL)
		//if (GetReportCtrl().IsLayoutRTL())
		XTPDrawHelpers()->SetContextRTL(pDC, LAYOUT_RTL);
//------------------------------------------------------------
	}
}

//////////////////////////////////////////////////////////////////////////
// Clipboard operations

void CXTPReportView::OnUpdateEditCopy(CCmdUI* pCmdUI)
{
	pCmdUI->Enable(GetReportCtrl().CanCopy());
}

void CXTPReportView::OnUpdateEditCut(CCmdUI* pCmdUI)
{
	pCmdUI->Enable(m_bAllowCut && GetReportCtrl().CanCut());
}

void CXTPReportView::OnUpdateEditPaste(CCmdUI* pCmdUI)
{
	pCmdUI->Enable(m_bAllowPaste && GetReportCtrl().CanPaste());
}

void CXTPReportView::OnEditCut()
{
	if (m_bAllowCut) GetReportCtrl().Cut();
}

void CXTPReportView::OnEditCopy()
{
	GetReportCtrl().Copy();
}

void CXTPReportView::OnEditPaste()
{
	if (m_bAllowPaste) GetReportCtrl().Paste();
}

void CXTPReportView::OnFilePageSetup()
{
	DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE;
	CXTPReportPageSetupDialog dlgPageSetup(GetPrintOptions(), dwFlags, this);

	XTPGetPrinterDeviceDefaults(dlgPageSetup.m_psd.hDevMode, dlgPageSetup.m_psd.hDevNames);

	int nDlgRes = (int) dlgPageSetup.DoModal();

	if (nDlgRes == IDOK)
		AfxGetApp()->SelectPrinter(dlgPageSetup.m_psd.hDevNames, dlgPageSetup.m_psd.hDevMode, FALSE);
}