Type xlsxComment = Class
	///缺省构造函数
	Function Create(sheet,excel); overload;
	Begin
		authors_ := array();
		excel_ := excel;
		sheetName_ := sheet;
		[rid, commentFileName_, sheetFileName_, relsfile] := excel_.WorkBook().GetRelationshipRid(sheet, '../comments');
		if commentFileName_ = '' then Begin
			rid++;
			rId_ := 'rId' + inttostr(rid);
			commentId_ := excel_.WorkBook().GetFilesCount('xl/comments') + 1;
			commentFileName_ := '../comments' + inttostr(commentId_) + '.xml';
			xlCommentFileName := 'xl/comments' + inttostr(commentId_) + '.xml';
			excel_.Zip().Add(xlCommentFileName, class(TSXml).XmlHeader() + '<comments xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"></comments>');
			excel_.WorkBook().AddRelationshipRid(relsfile, commentFileName_, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments', rId_);
			rid ++;
			drawingVML_ := '../drawings/vmlDrawing' + inttostr(commentId_) + '.vml';
			drawingVMLFile := 'xl/drawings/vmlDrawing' + inttostr(commentId_) + '.vml';
			excel_.Zip().Remove(drawingVMLFile);
			excel_.Zip().Add(drawingVMLFile, '<xml
xmlns:oa="urn:schemas-microsoft-com:office:activation"
xmlns:p="urn:schemas-microsoft-com:office:powerpoint"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:v="urn:schemas-microsoft-com:vml">
<o:shapelayout v:ext="edit">
	<o:idmap v:ext="edit" data="' + inttostr(commentId_) + '"/>
</o:shapelayout>
<v:shapetype id="_x0000_t202" coordsize="21600,21600" o:spt="202" path="m0,0l0,21600,21600,21600,21600,0xe">
	<v:stroke joinstyle="miter"/>
	<v:path gradientshapeok="t" o:connecttype="rect"/>
</v:shapetype>
 </xml>');
			excel_.WorkBook().AddRelationshipRid(relsfile, drawingVML_, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing', 'rId' + inttostr(rid));
			content_xml := excel_.WorkBook().GetXmlFileObj(class(TSXml).GetFileName('Content_Types'));
			class(TSXml).AddOverrideContentType(content_xml, '/' + xlCommentFileName, 'application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml');
			class(TSXml).AddDefaultContentType(content_xml, 'vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing');

			sheetXml := excel_.WorkBook().GetSheetXmlfile(sheetName_).FirstChildElement('worksheet');
			legacy := sheetXml.FirstChildElement('legacyDrawing');
			if not ifObj(legacy) then legacy := sheetXml.InsertEndChild('element', 'legacyDrawing');
			legacy.SetAttribute('r:id', 'rId' + inttostr(rid));
		End
		else Begin
			rId_ := 'rId' + inttostr(rid);
			xlCommentFileName := 'xl/' + ExtractFileName(commentFileName_);
			s := RightStr(xlCommentFileName, length(xlCommentFileName) - 11);
			commentId_ := strtoint(leftstr(s, length(s) - 4));
			drawingVML_ := './drawings/vmlDrawing' + inttostr(commentId_) + '.vml';
		End;
		commentXmlFile_ := excel_.WorkBook().GetXmlFileObj(xlCommentFileName);
		authors := commentXmlFile_.FirstChildElement('comments').FirstChildElement('authors');
		if not ifObj(authors) then 
			authors := commentXmlFile_.FirstChildElement('comments').InsertEndChild('element', 'authors');
		node := authors.FirstChildElement();
		i := 0;
		while ifObj(node) do Begin
			author := node.GetText();
			authors_[ author ] := i ++;
			node := node.NextElement();
		End;
		initCommentObjs();
		//println('sheet={},commentfile={},vmlfile={}',sheet, commentXmlFile_, drawingVML_);
	End;
	
	class Function NewObject(sheet, excel);
	Begin
		excel_ := excel;
		o := excel_.WorkBook().GetSheetObj(sheet);//sheet存在
		if not ifObj(o) then return 0;
		return new xlsxComment(sheet, excel);
	End;
	
	Function AddComment(cell, author, comment);
	Begin
		authorId := authors_[author];
		if not ifint(authorId) then Begin
			authorId := length(authors_);
			commentXmlFile_.FirstChildElement('comments').FirstChildElement('authors').InsertEndChild('element', 'author', author);//添加作者
			authors_[author] := authorId;
		End;
		if not ifstring(comment) then return 'comment is not a string';
		comments := TOfficeObj('TComments');
		comments.Ref := cell;
		comments.AuthorId := authorId;
		authorObj := comments.AddComment(author + ':');
		arr := str2array(comment, '\n');
		colCount := length(author)+1;
		for i:=0 to length(arr)-1 do Begin
			line := TrimRight(arr[i]);
			if length(line) > colCount then colCount := length(line);
		End;
		lineCount := length(arr);
		commentObj := comments.AddComment('\n' + comment);
		commentObj.Font.Bold := nil;
		commentObj.Space := 'preserve';
		domData := comments.Marshal();
		node := commentObjs_[cell];
		if ifObj(node) then
			node.DeleteChildren();
		else
			node := commentXmlFile_.FirstChildElement('comments').FirstChildElement('commentList').InsertEndChild('element', 'comment');
		node.UnMarshal(domData);
		commentObjs_[cell] := node;
		//commentXmlFile_.print;
		innerxml := '<v:shape id="_x0000_s1025" o:spt="202" type="#_x0000_t202" style="position:absolute;left:0pt;top:0pt;margin-left:59.85pt;margin-top:1.5pt;height:60pt;width:97.5pt;visibility:hidden;" fillcolor="#FFFFE1" filled="t" stroked="t" o:insetmode="auto" coordsize="21600,21600">
		<v:path/>
		<v:fill on="t" color2="#FFFFFF" focussize="0,0"/>
		<v:stroke color="#000000"/>
		<v:imagedata o:title=""/>
		<o:lock v:ext="edit" aspectratio="f"/>
		<v:textbox style="direction:context;layout-flow:horizontal;mso-rotate:0;">
			<div style="text-align:left"/>
		</v:textbox>
	<x:ClientData />
</v:shape>';
		drawingVMLFile := 'xl/drawings/vmlDrawing' + inttostr(commentId_) + '.vml';
		xmlObj := excel_.WorkBook().GetXmlFileObj(drawingVMLFile);
		if ifObj(xmlObj) then Begin
			node := xmlObj.LastChildElement('xml').InsertEndChild('element','v:shape');
			node.UnMarshal(innerxml);
			node := node.FirstChildElement('x:ClientData');
			if ifObj(node) then Begin
				[err, col, row] := excel_.CellNameToCoordinates(cell);
				clientData := TOfficeObj('TClientData');
				clientData.Anchor := format('%d,23,%d,0,%d,%d,%d,5',col, row, 1+col+lineCount, colCount+col-1, 1+row+lineCount);
				clientData.Row := row - 1;
				ClientData.Column := col - 1;
				node.UnMarshal(clientData.Marshal());
				//xmlObj.Print;
			End;
		End;
		return 'ok';
	End;
	
	Function GetComment(cell);
	Begin
		o := commentObjs_[cell];
		if not ifObj(o) then return array(nil, nil);
		r_node := o.FirstChildElement('text').FirstChildElement('r');
		author := r_node.FirstChildElement('t').GetText();	
		if length(author) > 1 then author := author[:length(author)-1];
		r_node := r_node.NextElement();
		comment := '';
		while ifObj(r_node) do
		begin
			comment += r_node.FirstChildElement('t').GetText();
			r_node := r_node.NextElement();
		end
		if length(comment) > 1 then comment := comment[2:];
		return array(author, comment);
	End;
	
	Function RemoveComment(cell);
	Begin
		node := commentObjs_[cell];
		if ifObj(node) then 
		begin
			commentXmlFile_.FirstChildElement('comments').FirstChildElement('commentList').DeleteChild(node);
			commentObjs_[cell] := nil;
		end
	End;

private

	Function initCommentObjs();
	Begin
		if not ifarray(commentObjs_) then Begin
			commentObjs_ := array();
			node := commentXmlFile_.FirstChildElement('comments').FirstChildElement('commentList');
			if not ifObj(node) then 
				node := commentXmlFile_.FirstChildElement('comments').InsertEndChild('element','commentList');
			node := node.FirstChildElement('comment');
			while ifObj(node) do Begin
				ref := node.GetAttribute('ref');
				commentObjs_[ref] := node;
				node := node.NextElement();
			End;
		End;
	End;

	authors_;
	commentId_;
	commentFileName_:string;//'../comments/comment1.xml'
	drawingVML_:string;//'../drawings/vmlDrawing1.xml'
	rId_:string;
	sheetName_:string;//sheet名称
	sheetFileName_;//xl/worksheets/sheetN.xml
	excel_;//TSExcelFile对象
	commentXmlFile_;//XmlFile对象
	commentObjs_;
End;
