Click here to Skip to main content
15,892,059 members
Articles / Desktop Programming / WTL

A fast and lightweight cell control

Rate me:
Please Sign up or sign in to vote.
4.42/5 (31 votes)
11 Mar 2008CPOL1 min read 91K   4.5K   81  
A fast and lightweight cell control for displaying tabular data. The cell is a custom control derived from ATL::CWindow.
// MyCell - version 1.1
// Written by Yanxueming <yanxm2003@hotmail.com>
// Copyright (C) 2006-2007
// All rights reserved.
//
// The code and information is provided "as-is" without
// warranty of any kind, either expressed or implied.
//Yanxm 2007��12��6�� 11:16:58
#include "stdafx.h"
#include "../include/XmlMyCell.h"
namespace mycell{
	//BOOL ReadIntFromAttribute(MSXML2::IXMLDOMElement* pE,BSTR bstrAttrName,int& val)
	//{
	//	CComVariant v;
	//	pE->getAttribute(bstrAttrName,&v);
	//	if(VT_BSTR==v.vt && SUCCEEDED(v.ChangeType(VT_I4))){
	//		val=v.lVal;
	//		return TRUE;
	//	}
	//	return FALSE;
	//}
	void XmlMyCell::StyleE2BorderStyle(MSXML2::IXMLDOMElement* pE,Border& bdr)
	{
		CComVariant v;
		pE->getAttribute(L"LineStyle",&v);
		if(VT_BSTR==v.vt){
			const EXlLineStyle ls=EXlLineStyleFromString(v.bstrVal);
			bdr.put_LineStyle(ls);
		}
		v.Clear();
		pE->getAttribute(L"Weight",&v);
		if(VT_BSTR==v.vt && SUCCEEDED(v.ChangeType(VT_I1))){
			bdr.put_Weight(v.bVal);
		}
	}
	void XmlMyCell::StyleE2StyleDesc(MSXML2::IXMLDOMNode* pStyleN,StyleDesc& sd)
	{
		{//Alignment
			CComPtr<MSXML2::IXMLDOMNode> pN;
			pStyleN->selectSingleNode(L"Alignment",&pN);
			CComQIPtr<MSXML2::IXMLDOMElement> pE=pN;
			if(pE){
				CComVariant v;
				pE->getAttribute(L"Horizontal",&v);
				if(v.vt==VT_BSTR){
					sd.Align_SetHorizontal(EXlHAlignFromStr(v.bstrVal));
				}
				v.Clear();
				pE->getAttribute(L"Vertical",&v);
				if(v.vt==VT_BSTR){
					sd.Align_SetVertical(EXlVAlignFromStr(v.bstrVal));
				}
				v.Clear();
				pE->getAttribute(L"WrapText",&v);
				if(v.vt==VT_BSTR){
					sd.Align_SetWrapText(CComBSTR(v.bstrVal)==L"0"?FALSE:TRUE);
				}
			}
		}
		{//Font
			CComPtr<MSXML2::IXMLDOMNode> pN;
			pStyleN->selectSingleNode(L"Font",&pN);
			CComQIPtr<MSXML2::IXMLDOMElement> pE=pN;
			if(pE){
				LOGFONT& lf=sd.Font_GetLogFont();
				CComVariant v;
				pE->getAttribute(L"FontName",&v);
				if(v.vt==VT_BSTR){
					lstrcpy(lf.lfFaceName,(LPCTSTR)CString(v.bstrVal));
				}
				v.Clear();
				pE->getAttribute(L"CharSet",&v);
				if(v.vt==VT_BSTR && SUCCEEDED(v.ChangeType(VT_UI1))){
					lf.lfCharSet=v.bVal;
				}
				pE->getAttribute(L"Size",&v);
				if(v.vt==VT_BSTR && SUCCEEDED(v.ChangeType(VT_I4))){
					lf.lfHeight=v.lVal;
				}
				pE->getAttribute(L"Bold",&v);
				if(v.vt==VT_BSTR && SUCCEEDED(v.ChangeType(VT_I4))){
					sd.Font_SetBold(v.lVal);
				}

				pE->getAttribute(L"StrikeThrough",&v);
				if(v.vt==VT_BSTR && SUCCEEDED(v.ChangeType(VT_I1))){
					lf.lfStrikeOut=v.bVal;
				}
				pE->getAttribute(L"Italic",&v);
				if(v.vt==VT_BSTR && SUCCEEDED(v.ChangeType(VT_I1))){
					lf.lfItalic=v.bVal;
				}
			}
		}
		{//Borders
			CComPtr<MSXML2::IXMLDOMNodeList> pNL;
			pStyleN->selectNodes(L"Borders/Border",&pNL);
			pNL->reset();
			CComPtr<MSXML2::IXMLDOMNode> pN;
			Borders* pbdrs=sd.GetBorders();
			for(pNL->nextNode(&pN);pN;pN.Release(),pNL->nextNode(&pN)){
				CComQIPtr<MSXML2::IXMLDOMElement> pE=pN;
				if(pE){
					CComVariant vp;
					pE->getAttribute(L"Position",&vp);
					if(VT_BSTR==vp.vt){
						const CComBSTR bstrPos(vp.bstrVal);
						if(bstrPos==L"Left")
							StyleE2BorderStyle(pE,pbdrs->left);
						if(bstrPos==L"Top")
							StyleE2BorderStyle(pE,pbdrs->top);
						if(bstrPos==L"Right")
							StyleE2BorderStyle(pE,pbdrs->right);
						if(bstrPos==L"Bottom")
							StyleE2BorderStyle(pE,pbdrs->bottom);
					}
				}
			}
		}
	}
	HRESULT XmlMyCell::LoadStyles(Worksheet* pGrid,RowHeader& rh,ColHeader& ch,map<StyleID_t,StyleDesc>& mapStyle,MSXML2::IXMLDOMElement* pStylesE)
	{
		HRESULT hr=S_OK;
		StyleDesc defStyle=pGrid->Style_GetTableStyle();
		CComPtr<MSXML2::IXMLDOMNode> pN;
		pStylesE->get_firstChild(&pN);
		//pStylesE->selectSingleNode(L"Style[ID=\"Default\"]",&pN);
		if(pN){
			StyleE2StyleDesc(pN,defStyle);
			pGrid->Style_SetTableStyle(defStyle);
		}
		CComPtr<MSXML2::IXMLDOMNodeList> pNL;
		pStylesE->selectNodes(L"Style",&pNL);
		//CComPtr<MSXML2::IXMLDOMNode> pN;
		pN.Release();
		pNL->reset();
		for(pNL->nextNode(&pN);pN;pN.Release(),pNL->nextNode(&pN)){
			CComQIPtr<MSXML2::IXMLDOMElement> pE=pN;
			if(!pE)
				continue;
			CComVariant v;
			pE->getAttribute(L"ID",&v);
			StyleID_t nStyleID=0;
			if(VT_BSTR==v.vt){
				CString str(v.bstrVal);
				if(str==_T("Default") || str.GetLength()<2)
					continue;
				str=str.Right(str.GetLength()-1);
				CComVariant vid(str);
				if(SUCCEEDED(vid.ChangeType(VT_I2))){
					nStyleID=vid.iVal;
				}else continue;
			}else
				continue;
			StyleDesc style=defStyle;
			StyleE2StyleDesc(pN,style);
			mapStyle[nStyleID]=style;
			//const StyleID_t nNewStyleID=pGrid->add_style(style);
			//mapO2N[nStyleID]=nNewStyleID;
		}
		return hr;
	}
	HRESULT XmlMyCell::LoadColumns(Worksheet* pGrid,RowHeader& rh,ColHeader& ch,const map<StyleID_t,StyleDesc>& mapStyle,MSXML2::IXMLDOMElement* pColumnsE)
	{
		HRESULT hr=S_OK;
		CComPtr<MSXML2::IXMLDOMNodeList> pNL;
		pColumnsE->get_childNodes(&pNL);
		int nPreCol=-1;
		pNL->reset();
		CComPtr<MSXML2::IXMLDOMNode> pN;
		for(pNL->nextNode(&pN);pN;pN.Release(),pNL->nextNode(&pN)){
			CComQIPtr<MSXML2::IXMLDOMElement> pE=pN;
			if(!pE)
				continue;
			int col=-1;
			CComVariant v;
			pE->getAttribute(L"idx",&v);
			if(VT_BSTR==v.vt){
				v.ChangeType(VT_I4);
				col=v.lVal;
				nPreCol=col;
			}else{
				col=++nPreCol;
			}
			v.Clear();
			pE->getAttribute(L"l",&v);
			if(VT_BSTR==v.vt){
				ch.put_ColLabel(col,(LPCTSTR)CString(v.bstrVal));
			}

			v.Clear();
			pE->getAttribute(L"wi",&v);
			if(VT_BSTR==v.vt && SUCCEEDED(v.ChangeType(VT_R8))){
				const int wi=this->X_Point2Pixel(v.dblVal);
				pGrid->put_ColWidth(col,wi,FALSE,FALSE);
			}
		}
		return hr;
	}
	HRESULT LoadCells(Worksheet* pGrid,RowHeader& rh,ColHeader& ch,int row,const map<StyleID_t,StyleDesc>& mapStyle,MSXML2::IXMLDOMElement* pRowE)
	{
		HRESULT hr=S_OK;
		CComPtr<MSXML2::IXMLDOMNodeList> pNL;
		pRowE->get_childNodes(&pNL);
		int nPreCol=-1;
		pNL->reset();
		CComPtr<MSXML2::IXMLDOMNode> pN;
		for(pNL->nextNode(&pN);pN;pN.Release(),pNL->nextNode(&pN)){
			CComQIPtr<MSXML2::IXMLDOMElement> pE=pN;
			if(!pE)
				continue;
			CComVariant v;
			int col=-1,nMergeAcross=0,nMergeDown=0;
			pE->getAttribute(L"ma",&v);
			if(VT_BSTR==v.vt && SUCCEEDED(v.ChangeType(VT_I4))){
				nMergeAcross=v.lVal;
			}
			v.Clear();
			pE->getAttribute(L"md",&v);
			if(VT_BSTR==v.vt && SUCCEEDED(v.ChangeType(VT_I4))){
				nMergeDown=v.lVal;
			}

			v.Clear();
			pE->getAttribute(L"idx",&v);
			if(VT_BSTR==v.vt){
				v.ChangeType(VT_I4);
				col=v.lVal;
				//nPreCol=col;
			}else{
				//col=nMergeAcross?nPreCol+nMergeAcross:nPreCol+1;
				col=nPreCol+1;
			}
			nPreCol=col+nMergeAcross;

			v.Clear();
			pE->getAttribute(L"t",&v);
			if(VT_BSTR==v.vt){
				pGrid->SetCellText(row,col,(LPCTSTR)CString(v.bstrVal),FALSE);
			}

			const StyleDesc* pStyle=NULL;
			v.Clear();
			pE->getAttribute(L"sid",&v);
			if(VT_BSTR==v.vt){
				CString str(v.bstrVal);
				if(str.GetLength()>1){
					str=str.Right(str.GetLength()-1);
					v=str;
					if(SUCCEEDED(v.ChangeType(VT_I2))){
						const StyleID_t nStyleID=v.iVal;
						map<StyleID_t,StyleDesc>::const_iterator it=mapStyle.find(nStyleID);
						if(it!=mapStyle.end()){
							pStyle=&it->second;
							pGrid->Style_SetCellStyle(CellID(row,col),it->second);
						}
					}
				}
			}

			if(nMergeAcross || nMergeDown){
				const int maxr=row+nMergeDown;
				const int maxc=col+nMergeAcross;
				pGrid->MergeCells(row,col,maxr,maxc);
				if(pStyle){
					for(int r=row;r<=maxr;++r){
						for(int c=col;c<=maxc;++c)
							if(r!=row && c!=c)
								pGrid->Style_SetCellStyle(CellID(r,c),*pStyle);
					}
				}
			}

		}
		return hr;
	}

	HRESULT XmlMyCell::LoadRows(Worksheet* pGrid,RowHeader& rh,ColHeader& ch,const map<StyleID_t,StyleDesc>& mapStyle,MSXML2::IXMLDOMElement* pRowsE)
	{
		HRESULT hr=S_OK;
		CComPtr<MSXML2::IXMLDOMNodeList> pNL;
		pRowsE->get_childNodes(&pNL);
		int nPreRow=-1;
		pNL->reset();
		CComPtr<MSXML2::IXMLDOMNode> pN;
		for(pNL->nextNode(&pN);pN;pN.Release(),pNL->nextNode(&pN)){
			CComQIPtr<MSXML2::IXMLDOMElement> pE=pN;
			if(!pE)
				continue;
			int row=-1;
			CComVariant v;
			pE->getAttribute(L"idx",&v);
			if(VT_BSTR==v.vt){
				v.ChangeType(VT_I4);
				row=v.lVal;
				nPreRow=row;
			}else{
				row=++nPreRow;
			}
			v.Clear();
			pE->getAttribute(L"hi",&v);
			if(VT_BSTR==v.vt && SUCCEEDED(v.ChangeType(VT_R8))){
				const int hi=this->Y_Point2Pixel(v.dblVal);
				pGrid->put_RowHeight(row,hi,FALSE,FALSE);
			}

			LoadCells(pGrid,rh,ch,row,mapStyle,pE);
		}
		return hr;
	}
	HRESULT XmlMyCell::load(Worksheet* pGrid,LPCTSTR lpszFile)
	{
		HRESULT hr=S_OK;
		CComPtr<MSXML2::IXMLDOMDocument>	   pXmlDoc;
		if FAILED(hr=pXmlDoc.CoCreateInstance(MSXML2::CLSID_DOMDocument))
			return hr;
		const CComVariant bstrXml(lpszFile);
		VARIANT_BOOL bSucc;
		if(FAILED(hr=pXmlDoc->load(bstrXml,&bSucc)))
			return hr;

		if(!bSucc){
			if FAILED(hr=pXmlDoc->loadXML(CComBSTR(lpszFile),&bSucc))
				return hr;
		}
		if(!bSucc){
			return AtlReportError(CLSID_NULL,L"�����ļ�ʧ�ܣ�",GUID_NULL,E_FAIL);
		}
		RowHeader& rh=pGrid->get_RowHeader();
		ColHeader& ch=pGrid->get_ColHeader();

		pGrid->clear();
		//pGrid->ClearStyles();
		//pGrid->put_rows(1);
		//pGrid->put_cols(1);
		map<StyleID_t,StyleDesc> mapStyle;

		{//load GridProperties properties
			CComPtr<MSXML2::IXMLDOMNode> pN;
			pXmlDoc->selectSingleNode(L"mycell/GridProperties",&pN);
			CComQIPtr<MSXML2::IXMLDOMElement> pE=pN;
			if(pE){
				int rows=0,cols=0;//,nDefaultColumnWidth=0,nDefaultRowHeight=0;
				if(ReadIntFromAttribute(pE,L"Rows",rows)){
					pGrid->put_rows(rows);
				}else
					return hr;
				if(ReadIntFromAttribute(pE,L"Cols",cols)){
					pGrid->put_cols(cols);
				}else
					return hr;
				double dx;
				if(ReadDoubleFromAttribute(pE,L"DefaultColumnWidth",dx)){
					const int nDefaultColumnWidth=X_Point2Pixel(dx);
					ch.put_DefColWidth(nDefaultColumnWidth);
				}
				if(ReadDoubleFromAttribute(pE,L"DefaultRowHeight",dx)){
					const int nDefaultRowHeight=this->Y_Point2Pixel(dx);
					rh.put_DefRowHeight(nDefaultRowHeight);
				}
			}else
				return hr;
		}
		{//load styles properties
			CComPtr<MSXML2::IXMLDOMNode> pN;
			pXmlDoc->selectSingleNode(L"mycell/Styles",&pN);
			CComQIPtr<MSXML2::IXMLDOMElement> pE=pN;
			if(pE){
				hr=LoadStyles(pGrid,rh,ch,mapStyle,pE);
			}
		}
		{//load columns properties
			CComPtr<MSXML2::IXMLDOMNode> pN;
			pXmlDoc->selectSingleNode(L"mycell/Columns",&pN);
			CComQIPtr<MSXML2::IXMLDOMElement> pE=pN;
			if(pE){
				hr=LoadColumns(pGrid,rh,ch,mapStyle,pE);
			}
		}
		{//load Rows properties
			CComPtr<MSXML2::IXMLDOMNode> pN;
			pXmlDoc->selectSingleNode(L"mycell/Rows",&pN);
			CComQIPtr<MSXML2::IXMLDOMElement> pE=pN;
			if(pE){
				hr=LoadRows(pGrid,rh,ch,mapStyle,pE);
			}
		}
		pGrid->put_TopVisScrollRow(0);
		pGrid->put_LeftVisScrollCol(0);
		pGrid->Scroll_ResetHScrollBar();//TRUE,TRUE);
		pGrid->Scroll_ResetVScrollBar();
		//pGrid->Scroll_ResetScrollBars(TRUE,TRUE);
		return hr;
	}
	CComPtr<MSXML2::IXMLDOMElement> XmlMyCell::CreateStyleNode(MSXML2::IXMLDOMDocument* pXmlDoc,BSTR bstrStyleNodeName,MSXML2::IXMLDOMElement* pStylesE/*,CComPtr<MSXML2::IXMLDOMElement>& pStyleE*/)
	{
			CComPtr<MSXML2::IXMLDOMNode> _pN;
			pStylesE->selectSingleNode(bstrStyleNodeName,&_pN);
			CComQIPtr<MSXML2::IXMLDOMElement> pStyleE=_pN;
			if(!pStyleE){
				//AppendTextNode(pXmlDoc,pStylesE,L"\r\n\t\t");
				pXmlDoc->createElement(bstrStyleNodeName,&pStyleE);	
				pStylesE->appendChild(pStyleE,NULL);
			}
			return pStyleE;
	}	
	void XmlMyCell::CreateBorderNode(MSXML2::IXMLDOMDocument* pXmlDoc,MSXML2::IXMLDOMElement* pBordersE,const Border* bdr,BSTR bstrPos)
	{
		const EXlLineStyle ls=bdr->get_LineStyle();
		const CComBSTR bstrLineStyle(EXlLineStyleToString(ls));
		if(bstrLineStyle.Length()>0){
			CComPtr<MSXML2::IXMLDOMNode> pN;
			CComBSTR sql(L"Border[@Position=\"");sql.Append(bstrPos);sql.Append(L"\"]");
			pBordersE->selectSingleNode(sql,&pN);
			CComQIPtr<MSXML2::IXMLDOMElement> pBorderE=pN;
			if(!pBorderE){
				pXmlDoc->createElement(L"Border",&pBorderE);
				pBordersE->appendChild(pBorderE,NULL);
			}
			pBorderE->setAttribute(L"Position",CComVariant(bstrPos));
			pBorderE->setAttribute(L"LineStyle",CComVariant(bstrLineStyle));
			pBorderE->setAttribute(L"Weight",CComVariant(bdr->get_Weight()));
			RemoveEmptyAttributeNode(pBordersE,pBorderE);
		}
	}
	HRESULT XmlMyCell::_SaveStyles(const StyleDesc& sd,MSXML2::IXMLDOMDocument* pXmlDoc,MSXML2::IXMLDOMElement* pE,const StyleDesc* pDefStyle)
	{
		const EXlVAlign va=sd.Align_GetVertical();
		const EXlHAlign ha=sd.Align_GetHorizontal();
		const BOOL bWrapText=sd.Align_IsWrapText()?1:0;
		const CComBSTR bstrVAlignment(EXlVAlignToStr(va));
		const CComBSTR bstrHAlignment(EXlHAlignToStr(ha));
		{//Alignment properties
			CComPtr<MSXML2::IXMLDOMElement> _pE=CreateStyleNode(pXmlDoc,L"Alignment",pE);
			{
				if(!pDefStyle || pDefStyle->Align_GetHorizontal()!=ha)
					_pE->setAttribute(L"Horizontal",CComVariant(bstrHAlignment));
				if(!pDefStyle || pDefStyle->Align_GetVertical()!=va)
					_pE->setAttribute(L"Vertical",CComVariant(bstrVAlignment));
				if(!pDefStyle || pDefStyle->Align_IsWrapText()!=bWrapText)
					_pE->setAttribute(L"WrapText",CComVariant(bWrapText));
			}
			RemoveEmptyAttributeNode(pE,_pE);
		}

		{//Font properties
			CComPtr<MSXML2::IXMLDOMElement> _pE=CreateStyleNode(pXmlDoc,L"Font",pE);
			const LOGFONT& lf=sd.Font_GetLogFont();
			const LOGFONT* lfDef=pDefStyle?&pDefStyle->Font_GetLogFont():NULL;
			if(!lfDef || lstrcmp(lfDef->lfFaceName,lf.lfFaceName))
				_pE->setAttribute(L"FontName",CComVariant(lf.lfFaceName));
			if(!lfDef || lfDef->lfCharSet!=lf.lfCharSet)
				_pE->setAttribute(L"CharSet",CComVariant(lf.lfCharSet));
			if(!lfDef || lfDef->lfHeight!=lf.lfHeight)
				_pE->setAttribute(L"Size",CComVariant(lf.lfHeight));
			if(!lfDef || pDefStyle->Font_IsBold()!=sd.Font_IsBold())
				_pE->setAttribute(L"Bold",CComVariant(sd.Font_IsBold()));
			if(!lfDef || lfDef->lfStrikeOut!=lf.lfStrikeOut)
				_pE->setAttribute(L"StrikeThrough",CComVariant(lf.lfStrikeOut));
			if(!lfDef || lfDef->lfItalic!=lf.lfItalic)
				_pE->setAttribute(L"Italic",CComVariant(lf.lfItalic?L"1":L"0"));
			RemoveEmptyAttributeNode(pE,_pE);
		}
		{//Borders properties
			CComPtr<MSXML2::IXMLDOMElement> _pE=CreateStyleNode(pXmlDoc,L"Borders",pE);
			const Borders* pBdrs=sd.GetBorders();
			if(pBdrs){
				/*
				const EXlLineStyle ls=pBdrs->bottom.get_LineStyle();
				CComBSTR bstrLineStyle(EXlLineStyleToString(ls));
				if(bstrLineStyle.Length()>0){
					CComPtr<MSXML2::IXMLDOMElement> pBorderE;
					pXmlDoc->createElement(L"Border",&pBorderE);
					_pE->appendChild(pBorderE,NULL);
					pBorderE->setAttribute(L"Position",CComVariant(L"Bottom"));
					pBorderE->setAttribute(L"LineStyle",CComVariant(bstrLineStyle));
					pBorderE->setAttribute(L"Weight",CComVariant(pBdrs->bottom.get_Weight()));
					RemoveEmptyAttributeNode(_pE,pBorderE);
				}
				*/
				CreateBorderNode(pXmlDoc,_pE,&pBdrs->bottom,L"Bottom");
				CreateBorderNode(pXmlDoc,_pE,&pBdrs->left,L"Left");
				CreateBorderNode(pXmlDoc,_pE,&pBdrs->right,L"Right");
				CreateBorderNode(pXmlDoc,_pE,&pBdrs->top,L"Top");
			}
			RemoveEmptyChildNode(pE,_pE);
		}
		return S_OK;
	}
	HRESULT XmlMyCell::SaveStyles(Worksheet const* pGrid,map<StyleID_t,size_t>& mapStyleID,const RowHeader& rh,const ColHeader& ch,MSXML2::IXMLDOMDocument* pXmlDoc,MSXML2::IXMLDOMNode* pNode)
	{
		HRESULT hr=S_OK;
		CComQIPtr<MSXML2::IXMLDOMElement> pE=pNode;
		const StyleDesc& sd=pGrid->Style_GetTableStyle();
		{
			CComPtr<MSXML2::IXMLDOMNode> pN;
			pE->selectSingleNode(L"Style[@ID=\"Default\"]",&pN);
			CComQIPtr<MSXML2::IXMLDOMElement> _pE=pN;
			if(_pE)
				hr=_SaveStyles(sd,pXmlDoc,_pE);
		}
		vector<pair<StyleID_t,const StyleDesc*> > vec;
		pGrid->Style_EnumStyles(vec);
		//for(vector<pair<StyleID_t,StyleDesc> >::const_iterator it=vec.begin();it!=vec.end();++it){
		for(size_t i=0;i<vec.size();++i){
			const size_t nID=i+1;
//#pragma warning(disable:4267)
			mapStyleID[vec[i].first]=nID;
//#pragma warning(default:4267)
			AppendTextNode(pXmlDoc,pE,L"\r\n\t\t");
			CComPtr<MSXML2::IXMLDOMElement> _pE;
			pXmlDoc->createElement(L"Style",&_pE);
			CString sid;sid.Format(_T("s%d"),nID);
			_pE->setAttribute(L"ID",CComVariant(sid));
			hr=_SaveStyles(vec[i].second,pXmlDoc,_pE,&sd);
			pE->appendChild(_pE,NULL);
		}
		if(!vec.empty())
			AppendTextNode(pXmlDoc,pE,L"\r\n\t");
		return hr;
	}
	void XmlMyCell::CreateColumnNode(MSXML2::IXMLDOMDocument* pXmlDoc,bool& bCreated,int col,int nPreCol,MSXML2::IXMLDOMNode* pColumns,MSXML2::IXMLDOMElement** ppColE)
	{
		_ASSERT(NULL==*ppColE);
		AppendTextNode(pXmlDoc,pColumns,L"\r\n\t\t");
		//CComPtr<MSXML2::IXMLDOMElement> _pE;
		pXmlDoc->createElement(L"c",ppColE);
		bCreated=true;
		pColumns->appendChild(*ppColE,NULL);
		if(col && (-1==nPreCol  || col-nPreCol>1)){
			(*ppColE)->setAttribute(L"idx",CComVariant(col));
		}
	}
	HRESULT XmlMyCell::SaveColumns(Worksheet const* pGrid,const RowHeader& rh,const ColHeader& ch,MSXML2::IXMLDOMDocument* pXmlDoc,MSXML2::IXMLDOMNode* pNode)
	{
		HRESULT hr=S_OK;
		CComQIPtr<MSXML2::IXMLDOMElement> pE=pNode;
		const int cols=ch.get_cols();
		const int nDefWidth=ch.get_DefColWidth();
		int nPreCol=-1;
		TCHAR buf[MAX_CELLTEXT];
		for(int col=0;col<cols;++col){
			bool bCreated=false;
			const int wi=ch.get_ColWidth(col);
			CComPtr<MSXML2::IXMLDOMElement> _pE;
			if(nDefWidth!=wi){
				CreateColumnNode(pXmlDoc,bCreated,col,nPreCol,pE,&_pE);
				_pE->setAttribute(L"wi",CComVariant(this->X_Pixel2Point(wi)));
			}
			const StyleID_t styleid=ch.Style_GetColStyleID(col);
			if(styleid){
				if(!_pE){
					CreateColumnNode(pXmlDoc,bCreated,col,nPreCol,pE,&_pE);
				}
				CString sid;sid.Format(_T("s%d"),styleid);
				_pE->setAttribute(L"sid",CComVariant(sid));
			}
			if(0){//����label
				const int len=ch.get_text(col,buf);
				if(len>0){
					if(!_pE){
						CreateColumnNode(pXmlDoc,bCreated,col,nPreCol,pE,&_pE);
					}
					_pE->setAttribute(L"l",CComVariant(buf));
				}
			}
			if(bCreated){
				nPreCol=col;
			}
		}
		AppendTextNode(pXmlDoc,pE,L"\r\n\t");
		return hr;
	}
	//struct xml_row_item
	//{
	//	row_t row;
	//	short nRowHeight;
	//	vector<col_t> cells;
	//};
	void XmlMyCell::CreateRowNode(MSXML2::IXMLDOMDocument* pXmlDoc,int row,int nPreRow,bool& bRowCreated,MSXML2::IXMLDOMElement* pE,MSXML2::IXMLDOMElement** ppRowE)
	{
		AppendTextNode(pXmlDoc,pE,L"\r\n\t\t");
		pXmlDoc->createElement(L"r",ppRowE);
		pE->appendChild(*ppRowE,NULL);
		bRowCreated=true;
		if(row && (-1==nPreRow || row-nPreRow>1)){
			(*ppRowE)->setAttribute(L"idx",CComVariant(row));
		}
	}
	void XmlMyCell::CreateCellNode(MSXML2::IXMLDOMDocument* pXmlDoc,int row,int col,int nPreRow,int nPreCol,bool& bRowCreated,bool& bCellCreated,MSXML2::IXMLDOMElement* pE,CComPtr<MSXML2::IXMLDOMElement>& pRowE,CComPtr<MSXML2::IXMLDOMElement>& pCellE)
	{
		if(!pRowE){
			CreateRowNode(pXmlDoc,row,nPreRow,bRowCreated,pE,&pRowE);
		}
		if(!pCellE){
			AppendTextNode(pXmlDoc,pRowE,L"\r\n\t\t\t");
			pXmlDoc->createElement(L"c",&pCellE);
			pRowE->appendChild(pCellE,NULL);
			bCellCreated=true;
			if(nPreCol+1!=col){
				pCellE->setAttribute(L"idx",CComVariant(col));
			}
		}
	}
	HRESULT XmlMyCell::SaveRows(Worksheet const* pGrid,const map<StyleID_t,size_t>& mapStyleID,const RowHeader& rh,const ColHeader& ch,MSXML2::IXMLDOMDocument* pXmlDoc,MSXML2::IXMLDOMNode* pNode)
	{
		HRESULT hr=S_OK;
		CComQIPtr<MSXML2::IXMLDOMElement> pE=pNode;
		const int nDefRowHeight=rh.get_DefRowHeight();
		const int rows=rh.get_rows();
		const int cols=ch.get_cols();
		TCHAR buf[MAX_CELLTEXT];
		int nPreRow=-1;
		for(int row=0;row<rows;++row){
			bool bRowCreated=false;
			CComPtr<MSXML2::IXMLDOMElement> pRowE;
			const int nRowHeight=rh.get_RowHeight(row);
			if(nRowHeight!=nDefRowHeight){
				CreateRowNode(pXmlDoc,row,nPreRow,bRowCreated,pE,&pRowE);
				pRowE->setAttribute(L"hi",CComVariant(this->Y_Pixel2Point(nRowHeight)));
			}
			int nPreCol=-1;
			for(int col=0;col<cols;++col){
				const CellRange* pMerge=pGrid->GetMergeCells(row,col);
				if(pMerge && !(pMerge->TopRow()==row && pMerge->LeftCol()==col))
					continue;

				bool bCellCreated=false;
				CComPtr<MSXML2::IXMLDOMElement> pCellE;

				//�������
				//const StyleID_t nStyleID
				const pair<StyleID_t,EStyleStorePosition> pr=pGrid->Style_GetCellStyleID(CellID(row,col));
				
				if(ESP_STYLE_CELL_OWN==pr.second){
					map<StyleID_t,size_t>::const_iterator it=mapStyleID.find(pr.first);
					if(it!=mapStyleID.end()){
						CreateCellNode(pXmlDoc,row,col,nPreRow,nPreCol,bRowCreated,bCellCreated,pE,pRowE,pCellE);
						CString sid;sid.Format(_T("s%d"),it->second);
						pCellE->setAttribute(L"sid",CComVariant(sid));
					}
				}

				int nMergeAcross=0;
				//��Ԫ��ϲ�����
				if(pMerge && pMerge->TopRow()==row && pMerge->LeftCol()==col){
					nMergeAcross=pMerge->RightCol()-col;
					const int nMergeDown=pMerge->BottomRow()-row;
					if(nMergeAcross||nMergeDown){
						CreateCellNode(pXmlDoc,row,col,nPreRow,nPreCol,bRowCreated,bCellCreated,pE,pRowE,pCellE);
						if(nMergeAcross)
							pCellE->setAttribute(L"ma",CComVariant(nMergeAcross));
						if(nMergeDown)
							pCellE->setAttribute(L"md",CComVariant(nMergeDown));
					}
				}

				//�ı�����
				const int iTextLen= pGrid->GetCellText(row,col,buf);
				if(iTextLen>0){
					CreateCellNode(pXmlDoc,row,col,nPreRow,nPreCol,bRowCreated,bCellCreated,pE,pRowE,pCellE);
					pCellE->setAttribute(L"t",CComVariant(buf));
				}
				//:~�ı�����

				if(bCellCreated){
					if(!nMergeAcross)
						nPreCol=col;
					else{
						nPreCol=col+nMergeAcross;
					}
				}
			}
			if(bRowCreated)
				nPreRow=row;
		}
		return hr;
	}
	//HRESULT SaveMergeCells(Worksheet const* pGrid,const RowHeader& rh,const ColHeader& ch,MSXML2::IXMLDOMNode* pNode)
	//{
	//	HRESULT hr=S_OK;
	//	CComQIPtr<MSXML2::IXMLDOMElement> pE=pNode;
	//	return hr;
	//}
	HRESULT XmlMyCell::save(Worksheet const* pGrid,LPCTSTR lpszFile)
	{
		HRESULT hr=S_OK;
		CComPtr<MSXML2::IXMLDOMDocument>	   pXmlDoc;
		if FAILED(hr=pXmlDoc.CoCreateInstance(MSXML2::CLSID_DOMDocument))
			return hr;
		if FAILED(hr=init(pXmlDoc))
			return hr;
		const RowHeader& rh=pGrid->get_RowHeader();
		const ColHeader& ch=pGrid->get_ColHeader();
		CComPtr<MSXML2::IXMLDOMNode> pN;
		{
			//rh.get_FreezeBottomRow
			pXmlDoc->selectSingleNode(L"/mycell/GridProperties",&pN);
			CComQIPtr<MSXML2::IXMLDOMElement> pE=pN;
			pE->setAttribute(L"Rows",CComVariant(rh.get_rows()));
			pE->setAttribute(L"Cols",CComVariant(ch.get_cols()));
			pE->setAttribute(L"DefaultColumnWidth",CComVariant(X_Pixel2Point(ch.get_DefColWidth())));
			pE->setAttribute(L"DefaultRowHeight",CComVariant(this->Y_Pixel2Point(rh.get_DefRowHeight())));
		}

		for(int i=0;i<1;++i){
			pN.Release();
			hr=pXmlDoc->selectSingleNode(L"/mycell/Styles",&pN);
			if(!pN)
				break;

			map<StyleID_t,size_t> mapStyleID;
			SaveStyles(pGrid,mapStyleID,rh,ch,pXmlDoc,pN);

			pN.Release();
			pXmlDoc->selectSingleNode(L"/mycell/Columns",&pN);
			SaveColumns(pGrid,rh,ch,pXmlDoc,pN);

			pN.Release();
			pXmlDoc->selectSingleNode(L"/mycell/Rows",&pN);
			SaveRows(pGrid,mapStyleID,rh,ch,pXmlDoc,pN);

			//pN.Release();
			//pXmlDoc->selectSingleNode(L"/mycell/MergeCells",&pN);
			//SaveMergeCells(pGrid,rh,ch,pN);
		}
		//pXmlDoc->save(CComVariant(lpszFile));
		if FAILED(hr=pXmlDoc->save(CComVariant(lpszFile)))
			return hr;
		return hr;
	}
	HRESULT XmlMyCell::init(MSXML2::IXMLDOMDocument* pXmlDoc)
	{
		CComBSTR xml(L"<?xml version=\"1.0\"?>");
		xml.Append(L"<mycell>\r\n");
		xml.Append(L"<!--ӳ���ϵ(sid->StyleID),(idx->Index),(r->row),(c->column),(hi->Height),(wi->Width),(t->text),(ma->MergeAcross),(md->MergeDown),(l->Label)-->\r\n");
		xml.Append(L"<DocumentProperties><Author>yanxm</Author><Version>1.0</Version></DocumentProperties>\r\n");
		xml.Append(L"<GridProperties/>\r\n");
		xml.Append(L"<Styles>\r\n\t<Style ID=\"Default\" Name=\"Normal\"/>\r\n</Styles>\r\n");
		xml.Append(L"<Columns/>\r\n");
		xml.Append(L"<Rows/>\r\n");
		xml.Append(L"</mycell>");
		VARIANT_BOOL bOk;
		HRESULT hr=pXmlDoc->loadXML(xml,&bOk);
		return hr;
	}
}//namespace mycell

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
China China
My name is Yanxueming,i live in Chengdu China.Graduated from UESTC in 1999.

Comments and Discussions