/*=========================================================================== ==== ==== ==== ==== ============================================================================= ==== ==== ==== File : LCPrinter.cpp ==== ==== Project name : ==== ==== Project number : ==== ==== Creation date : 10/08/2000 ==== ==== ==== ==== ==== ============================================================================= ===========================================================================*/ //============================================================================ // Inclusions //============================================================================ #include "stdafx.h" #include "LCPrinter.h" //============================================================================ // Constants //============================================================================ const int LEFT_MARGIN = 4; const int RIGHT_MARGIN = 8; const int HEADER_HEIGHT = 2; const int FOOTER_HEIGHT = 2; //============================================================================ // Data types //============================================================================ //============================================================================ // Variables //============================================================================ //============================================================================ // Development tools //============================================================================ //============================================================================ // Templates and global functions //============================================================================ //============================================================================ //============================================================================ // class CLCPrinter //============================================================================ //============================================================================ /*============================================================================ Description: Constructor. ============================================================================*/ CLCPrinter::CLCPrinter() { m_nRowHeight = 0; m_nRowsPerPage = 0; m_nMaxRowCount = 0; m_ratiox = 0; m_ratioy = 0; m_hcItems = 0; m_pLC = NULL; m_pOldFont = NULL; m_page_rc.SetRect(0,0,0,0); } /*============================================================================ Description: Sets alls of the row and metric member variables Retour: - ============================================================================*/ void CLCPrinter::ComputeMetrics(CDC *pDC) { // This includes width for all columns CRect row_rc; m_pLC->GetItemRect(0, &row_rc, LVIR_BOUNDS); // Get the list control window DC CDC* pCtlDC = m_pLC->GetDC(); if (pCtlDC == NULL) { return; } // so we can get the avg character width TEXTMETRIC tm; pCtlDC->GetTextMetrics(&tm); // Lets get the ratios for scaling to printer DC // Fit all columns to 1 page, regardless of column number. m_ratiox = pDC->GetDeviceCaps(HORZRES)/(row_rc.Width() + (LEFT_MARGIN+RIGHT_MARGIN)*tm.tmAveCharWidth); // width of pDC/whats got to fit into it in lcDC units m_ratioy = pDC->GetDeviceCaps(LOGPIXELSY)/pCtlDC->GetDeviceCaps(LOGPIXELSY); m_pLC->ReleaseDC(pCtlDC); // Set up a page rc in list control units that accounts for left and right margins m_page_rc.SetRect(0, 0, pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES)); // Convert units to List Control m_page_rc.bottom = m_page_rc.bottom / m_ratioy; m_page_rc.right = m_page_rc.right / m_ratiox; // Adjust sides for magins m_page_rc.left = LEFT_MARGIN * tm.tmAveCharWidth; m_page_rc.right -= RIGHT_MARGIN * tm.tmAveCharWidth; // Get the height of a row. m_nRowHeight = row_rc.Height(); // Get RowHeight in printer units. int pRowHeight = (int)(m_nRowHeight * m_ratioy); // How many rows will fit on page? m_nRowsPerPage = pDC->GetDeviceCaps(VERTRES)/pRowHeight; // After header and footer rows m_nRowsPerPage -= (HEADER_HEIGHT*2+FOOTER_HEIGHT); //After header Control row m_nRowsPerPage -= 1; } /*============================================================================ Description: Draw a horizontal line at the specified position pDC: See MFC y: Y-Axis position at which the line is to be drawned Retour: - ============================================================================*/ void CLCPrinter::DrawLineAt(CDC *pDC, unsigned int y) { //Use the m_page_rc to figure out the width of the line pDC->MoveTo(0, y); pDC->LineTo(m_page_rc.right, y); } /*============================================================================ Description: Draw a row of the list control pDC: See MFC nItem: Index of the item to be printed Retour: - ============================================================================*/ void CLCPrinter::DrawRow(CDC *pDC, int nItem) { // If nothing to print, return if (m_hcItems < 1) { return; } // Shouln't have more than 30 columns int order_array[30]; m_pLC->GetColumnOrderArray(order_array, m_hcItems); CRect rc; CString temp_str; LV_COLUMN lvc; lvc.mask = LVCF_WIDTH; m_pLC->GetItemRect(nItem, rc, LVIR_LABEL); int offset = pDC->GetTextExtent(_T(" "), 1).cx; // This makes it so that label will be over a little bit rc.left += offset / 2; // Just keep this stuff it DOES look better. rc.right -= offset; for (int i = 0; i < m_hcItems; i++) { // Get in viewed order m_pLC->GetColumn(order_array[i], &lvc); temp_str = m_pLC->GetItemText(nItem, order_array[i]); rc.right += lvc.cx; pDC->DrawText(temp_str, -1, rc, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER|DT_LEFT); // Draw a line below each row DrawLineAt(pDC, rc.bottom); rc.left += lvc.cx; } } /*============================================================================ Description: See MFC Retour: - ============================================================================*/ void CLCPrinter::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo, const CString& titleStr, const CString& dateStr) { if (pDC == NULL || pInfo == NULL) { return; } m_titleStr = titleStr; m_dateStr = dateStr; // Create listcontrol font, and bold listcontrol font LOGFONT lf; CFont* pFont = m_pLC->GetFont(); pFont->GetLogFont(&lf); m_lcFont.CreateFontIndirect(&lf); lf.lfWidth = 0; lf.lfWeight = FW_BOLD; // Make it a little bigger lf.lfHeight+= 22; m_boldFont.CreateFontIndirect(&lf); // Compute this again in case user changed printer ComputeMetrics(pDC); int nMaxPage = m_nMaxRowCount/m_nRowsPerPage + 1; pInfo->SetMaxPage(nMaxPage); // Start printing at first page pInfo->m_nCurPage = 1; } /*============================================================================ Description: See MFC Retour: - ============================================================================*/ void CLCPrinter::OnEndPrinting(CDC* pDC, CPrintInfo* pInfo) { m_lcFont.DeleteObject(); m_boldFont.DeleteObject(); } /*============================================================================ Description: See MFC Retour: - ============================================================================*/ BOOL CLCPrinter::OnPreparePrinting(CPrintInfo* pInfo, CView* pView, CListCtrl* pLC) { if (pLC == NULL || pView == NULL || pInfo == NULL) { return FALSE; } // Set Pointer to list Control m_pLC = pLC; // Lets make a guess as to how many pages there are based on the default printer. CPrintDialog dlg(FALSE); if (!dlg.GetDefaults()) { //If no defaults then no printer!! return FALSE; } CDC dc; dc.Attach(dlg.GetPrinterDC()); ComputeMetrics(&dc); // Get the number of rows m_nMaxRowCount = m_pLC->GetItemCount(); if (!m_nMaxRowCount) { return FALSE; } int nMaxPage = m_nMaxRowCount/m_nRowsPerPage + 1; pInfo->SetMaxPage(nMaxPage); // Start printing at first page pInfo->m_nCurPage = 1; // If you want to be able to do this remove it. pInfo->m_pPD->m_pd.Flags |= PD_HIDEPRINTTOFILE; return pView->DoPreparePrinting(pInfo); } /*============================================================================ Description: See MFC Retour: - ============================================================================*/ void CLCPrinter::OnPrint(CDC* pDC, CPrintInfo* pInfo) { if (pDC == NULL || pInfo == NULL) { return; } // This has to be in OnPrint() or else PrintPreview goes screwy m_pOldFont = pDC->GetCurrentFont(); // Fit all columns to 1 page, regardless of column number. pDC->SetMapMode(MM_ANISOTROPIC); // For every 1 List Control pixel pDC->SetWindowExt(1, 1); // The printer has ratio more dots pDC->SetViewportExt(m_ratiox, m_ratioy); int nStartRow = (pInfo->m_nCurPage - 1) * m_nRowsPerPage; int nEndRow = nStartRow + m_nRowsPerPage; if (nEndRow > m_nMaxRowCount) { nEndRow = m_nMaxRowCount; } // Print the header pDC->SetWindowOrg(-1 * m_page_rc.left, 0); PrintHeader(pDC, pInfo); // Print the footer PrintFooter(pDC, pInfo); pDC->SetWindowOrg(-1 * m_page_rc.left, -1 * HEADER_HEIGHT * m_nRowHeight); // Print the header Control manually PrintHeaderControl(pDC, pInfo); // Use the LC normal font pDC->SelectObject(&m_lcFont); // Black text on white paper pDC->SetTextColor(RGB(0, 0, 0)); pDC->SetBkColor(RGB(255, 255, 255)); CRect rcBounds; m_pLC->GetItemRect(nStartRow, &rcBounds, LVIR_BOUNDS); // Offset top margin of rcBounds by ListControl header CRect rc; m_pLC->GetHeaderCtrl()->GetClientRect(&rc); rcBounds.OffsetRect(0, -1 * rc.Height()); pDC->OffsetWindowOrg(rcBounds.left, rcBounds.top); // Start printing rows for (int i = nStartRow; i < nEndRow; i++) { DrawRow(pDC, i); } // SetWindowOrg back for next page pDC->SetWindowOrg(0,0); // Put the old font back pDC->SelectObject(m_pOldFont); } /*============================================================================ Description: Print the page footer with a line and a date, and page number pDC: See MFC pInfo: See MFC Retour: - ============================================================================*/ void CLCPrinter::PrintFooter(CDC *pDC, CPrintInfo *pInfo) { CRect rc = m_page_rc; rc.top = rc.bottom - FOOTER_HEIGHT * m_nRowHeight; rc.bottom = rc.top + m_nRowHeight + FOOTER_HEIGHT; // Draw line DrawLineAt(pDC, rc.top); DrawLineAt(pDC, rc.top + 1); DrawLineAt(pDC, rc.top + 2); // Draw page number CString sTemp ; rc.OffsetRect(0, m_nRowHeight/2); sTemp.Format(_T("Page %d - %d"), pInfo->m_nCurPage, pInfo->GetMaxPage()); pDC->DrawText(sTemp, -1, rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER); // Now draw the date at bottom of page rc.left = 0; pDC->DrawText(m_dateStr, -1, rc, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER); } /*============================================================================ Description: Print the page header pDC: See MFC pInfo: See MFC Retour: - ============================================================================*/ void CLCPrinter::PrintHeader(CDC *pDC, CPrintInfo *pInfo) { pDC->SelectObject(&m_boldFont); //Black text on white paper pDC->SetTextColor(RGB(0, 0, 0)); pDC->SetBkColor(RGB(255, 255, 255)); CRect rc = m_page_rc; rc.bottom = rc.top + m_nRowHeight + HEADER_HEIGHT; //Use the m_page_rc to figure out the width of the line DrawLineAt(pDC, rc.bottom + 1); DrawLineAt(pDC, rc.bottom + 2); DrawLineAt(pDC, rc.bottom + 3); // Print App title on top left margin pDC->DrawText(m_titleStr, &rc, DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER | DT_LEFT | DT_NOCLIP); } /*============================================================================ Description: Print the list control header pDC: See MFC pInfo: See MFC Retour: - ============================================================================*/ void CLCPrinter::PrintHeaderControl(CDC *pDC, CPrintInfo *pInfo) { CHeaderCtrl* hc = m_pLC->GetHeaderCtrl(); // Drawing flags UINT dtFlags = DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER|DT_LEFT; m_hcItems = hc->GetItemCount(); // Remember that m_hcItems is also used to draw rows. if (m_hcItems < 1) { return; } // Shouln't have more than 30 columns int order_array[30]; hc->GetOrderArray(order_array, m_hcItems); TCHAR temp_str[1024]; HDITEM phi; phi.cchTextMax = 1024; phi.mask = HDI_TEXT | HDI_WIDTH; phi.pszText = temp_str; CRect rc(0, 0, 0, m_nRowHeight); for (int i = 0; i < m_hcItems; i++) { // Get in viewed order hc->GetItem(order_array[i], &phi); rc.right += phi.cxy; pDC->DrawText(temp_str, -1, rc, dtFlags); rc.left += phi.cxy; } // Now draw the line below header control DrawLineAt(pDC, rc.bottom); } //============================================================================ //============================================================================ // Test section //============================================================================ //============================================================================