From 06ae369ff552dd426f3d8464f10847dc81261400 Mon Sep 17 00:00:00 2001 From: sekelsenmat Date: Tue, 25 May 2010 09:11:02 +0000 Subject: [PATCH] Improves FPSpreadsheet examples and improves the Grid component git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1229 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../examples/fpschart/fpschart.lpi | 7 + .../examples/fpschart/fpschart.lpr | 1 - .../examples/fpschart/mainform.lfm | 109 +++++++++++-- .../examples/fpschart/mainform.pas | 37 ++++- .../fpspreadsheet/examples/fpschart/t1.xls | Bin 0 -> 97792 bytes .../fpspreadsheet/examples/fpschart/t2.ods | Bin 0 -> 12705 bytes components/fpspreadsheet/fpsopendocument.pas | 27 ++-- components/fpspreadsheet/fpspreadsheet.pas | 11 +- .../fpspreadsheet/fpspreadsheetchart.pas | 17 +- .../fpspreadsheet/fpspreadsheetgrid.pas | 17 +- components/fpspreadsheet/fpsutils.pas | 152 +++++++++++++++++- components/fpspreadsheet/xlsbiff5.pas | 4 +- components/fpspreadsheet/xlsbiff8.pas | 4 +- 13 files changed, 352 insertions(+), 34 deletions(-) create mode 100644 components/fpspreadsheet/examples/fpschart/t1.xls create mode 100644 components/fpspreadsheet/examples/fpschart/t2.ods diff --git a/components/fpspreadsheet/examples/fpschart/fpschart.lpi b/components/fpspreadsheet/examples/fpschart/fpschart.lpi index 7d8bced85..4610fff23 100644 --- a/components/fpspreadsheet/examples/fpschart/fpschart.lpi +++ b/components/fpspreadsheet/examples/fpschart/fpschart.lpi @@ -4,6 +4,7 @@ + @@ -72,6 +73,9 @@ + + + @@ -79,6 +83,9 @@ + + + diff --git a/components/fpspreadsheet/examples/fpschart/fpschart.lpr b/components/fpspreadsheet/examples/fpschart/fpschart.lpr index a0cd3af67..fbe063756 100644 --- a/components/fpspreadsheet/examples/fpschart/fpschart.lpr +++ b/components/fpspreadsheet/examples/fpschart/fpschart.lpr @@ -13,7 +13,6 @@ uses {$R *.res} begin - Application.Title:='project1'; Application.Initialize; Application.CreateForm(TFPSChartForm, FPSChartForm); Application.Run; diff --git a/components/fpspreadsheet/examples/fpschart/mainform.lfm b/components/fpspreadsheet/examples/fpschart/mainform.lfm index 89c70905a..6260e0ad5 100644 --- a/components/fpspreadsheet/examples/fpschart/mainform.lfm +++ b/components/fpspreadsheet/examples/fpschart/mainform.lfm @@ -1,16 +1,17 @@ object FPSChartForm: TFPSChartForm - Left = 179 - Height = 331 - Top = 157 - Width = 742 + Left = 239 + Height = 382 + Top = 154 + Width = 700 Caption = 'FPSpreadsheet Chart Example' - ClientHeight = 331 - ClientWidth = 742 + ClientHeight = 382 + ClientWidth = 700 + OnCreate = FormCreate LCLVersion = '0.9.29' object MyChart: TChart - Left = 400 + Left = 352 Height = 240 - Top = 24 + Top = 136 Width = 336 AxisList = < item @@ -37,26 +38,106 @@ object FPSChartForm: TFPSChartForm object WorksheetGrid: TsWorksheetGrid Left = 16 Height = 240 - Top = 24 - Width = 360 + Top = 136 + Width = 328 Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goEditing, goSmoothScroll] TabOrder = 1 end object btnCreateGraphic: TButton - Left = 104 + Left = 464 Height = 25 - Top = 280 + Top = 56 Width = 128 Caption = 'Create Graphic' OnClick = btnCreateGraphicClick TabOrder = 2 end + object Label1: TLabel + Left = 16 + Height = 34 + Top = 8 + Width = 676 + AutoSize = False + Caption = 'Please add data to the grid or load it from a file, then choose the location of the data for the X and Y axises and click on the button "Create Graphic" to generate a chart.' + ParentColor = False + WordWrap = True + end + object editSourceFile: TFileNameEdit + Left = 152 + Height = 22 + Top = 48 + Width = 136 + DialogOptions = [] + FilterIndex = 0 + HideDirectories = False + ButtonWidth = 23 + NumGlyphs = 0 + MaxLength = 0 + TabOrder = 3 + end + object Label2: TLabel + Left = 14 + Height = 18 + Top = 51 + Width = 130 + Caption = 'Source Spreadsheet:' + ParentColor = False + end + object btnLoadSpreadsheet: TButton + Left = 320 + Height = 25 + Top = 48 + Width = 75 + Caption = 'Load' + OnClick = btnLoadSpreadsheetClick + TabOrder = 4 + end + object editXAxis: TLabeledEdit + Left = 64 + Height = 22 + Top = 80 + Width = 80 + EditLabel.AnchorSideLeft.Control = editXAxis + EditLabel.AnchorSideTop.Control = editXAxis + EditLabel.AnchorSideTop.Side = asrCenter + EditLabel.AnchorSideRight.Control = editXAxis + EditLabel.AnchorSideBottom.Control = editXAxis + EditLabel.Left = 17 + EditLabel.Height = 18 + EditLabel.Top = 82 + EditLabel.Width = 44 + EditLabel.Caption = 'X-Axis:' + EditLabel.ParentColor = False + LabelPosition = lpLeft + TabOrder = 5 + Text = 'A1:A5' + end + object EditYAxis: TLabeledEdit + Left = 208 + Height = 22 + Top = 80 + Width = 80 + EditLabel.AnchorSideLeft.Control = EditYAxis + EditLabel.AnchorSideTop.Control = EditYAxis + EditLabel.AnchorSideTop.Side = asrCenter + EditLabel.AnchorSideRight.Control = EditYAxis + EditLabel.AnchorSideBottom.Control = EditYAxis + EditLabel.Left = 161 + EditLabel.Height = 18 + EditLabel.Top = 82 + EditLabel.Width = 44 + EditLabel.Caption = 'Y-Axis:' + EditLabel.ParentColor = False + LabelPosition = lpLeft + TabOrder = 6 + Text = 'B1:B5' + end object FPSChartSource: TsWorksheetChartSource PointsNumber = 5 YFirstCellCol = 1 XSelectionDirection = fpsVerticalSelection YSelectionDirection = fpsVerticalSelection - left = 376 - top = 264 + left = 632 + top = 56 end end diff --git a/components/fpspreadsheet/examples/fpschart/mainform.pas b/components/fpspreadsheet/examples/fpschart/mainform.pas index 6b92a64f4..b9ba09255 100644 --- a/components/fpspreadsheet/examples/fpschart/mainform.pas +++ b/components/fpspreadsheet/examples/fpschart/mainform.pas @@ -6,7 +6,8 @@ interface uses Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs, - StdCtrls, Grids, fpspreadsheetchart, fpspreadsheetgrid, TAGraph, TASeries; + StdCtrls, Grids, EditBtn, ExtCtrls, fpspreadsheetchart, fpspreadsheetgrid, + TAGraph, TASeries; type @@ -14,11 +15,19 @@ type TFPSChartForm = class(TForm) btnCreateGraphic: TButton; + btnLoadSpreadsheet: TButton; + editSourceFile: TFileNameEdit; + Label1: TLabel; + Label2: TLabel; + editXAxis: TLabeledEdit; + EditYAxis: TLabeledEdit; MyChart: TChart; FPSChartSource: TsWorksheetChartSource; MyChartLineSeries: TLineSeries; WorksheetGrid: TsWorksheetGrid; procedure btnCreateGraphicClick(Sender: TObject); + procedure btnLoadSpreadsheetClick(Sender: TObject); + procedure FormCreate(Sender: TObject); private { private declarations } public @@ -30,14 +39,40 @@ var implementation +uses + // FPSpreadsheet and supported formats + fpspreadsheet, xlsbiff8, xlsbiff5, xlsbiff2, xlsxooxml, fpsopendocument; + {$R *.lfm} { TFPSChartForm } procedure TFPSChartForm.btnCreateGraphicClick(Sender: TObject); begin + FPSChartSource.LoadPropertiesFromStrings(editXAxis.Text, editYAxis.Text, '', '', ''); FPSChartSource.LoadFromWorksheetGrid(WorksheetGrid); end; +procedure TFPSChartForm.btnLoadSpreadsheetClick(Sender: TObject); +var + Format: TsSpreadsheetFormat; + lExt: string; +begin + // First some logic to detect the format from the extension + lExt := ExtractFileExt(editSourceFile.Text); + if lExt = STR_EXCEL_EXTENSION then Format := sfExcel2 + else if lExt = STR_OOXML_EXCEL_EXTENSION then Format := sfOOXML + else if lExt = STR_OPENDOCUMENT_CALC_EXTENSION then Format := sfOpenDocument + else raise Exception.Create('Invalid File Extension'); + + // Now the actual loading + WorksheetGrid.LoadFromSpreadsheetFile(editSourceFile.Text, Format); +end; + +procedure TFPSChartForm.FormCreate(Sender: TObject); +begin + editSourceFile.InitialDir := ExtractFilePath(ParamStr(0)); +end; + end. diff --git a/components/fpspreadsheet/examples/fpschart/t1.xls b/components/fpspreadsheet/examples/fpschart/t1.xls new file mode 100644 index 0000000000000000000000000000000000000000..4947be62c4870483261750cee59e49e037bead3d GIT binary patch literal 97792 zcmeI53y@XCna9ta2MiCrh=$FYm5lBNU&x|nH*pigfP=3M%A!fkqMHnGfzg4%VIU9$ z1{7TtTmn9#qC5m4f?^1Q1frL%vT9AOZd^+xq84bCRavxZK-Mi4WPjb?+@9l^J2Us5 zdwVeOUFv^scc1Qm_xYbb{e9i1=kkaDI%&_!U!S@+h?o}d>nc~0Q_M34k@f#4+2 z7n}@E0bc?Az+Zr`g1-c(g0F$U0;hrg;On3goDR+ae+~Wyd;<&sXM(f9+29;-E*J>T z1B1Zdg2CW?Z~?dwd=vZ~_y3YQc@*CQt_^fytmAOaV881~3&gf@xqn_!*c1W`duCS>P5h8_WT7!8|Yu zrg}jTyJto}Mb14=cFLKG>SstywRe{d5GUvnkCy1ATQqbA+-WSud+8BRm+iFu;$70NXQZKTTvAgv zwz8`}!)zOB5~gonoalz1Q9>VG#_>dKib?Hjk0;yXMw@SkJyzM2MfP~HwM}HM3M!2? zF#gIO?2RdZBF99q)s}hFrkszZ`VY<=nY*~f*@ znpT?2Yx!h!K38;Tj;5d8PWr%h($8rpy+_vcfS!=8Jpnz&rkg?Ae$tgoONcZDN6dGh zrc(QTQd2kk-M6XCexKab-F~0aRDR^A^!-GzfG6RH#_i+Tzh+`8)p)*1*>4=aOv(i& ziYWNz<>KHaTU#>P&3tvYF(Zfk#HKe{pBn-`-!OMG=$V+u znVn_l*b?X3<9wU<6#V7Wah5L`aK^Q@lMvvl)XyqM)laIKJaANM!nC@YhBF47f5CvE zU%`jQqwXZ%$eIbM$^j#9wH4fEj{|7Th4%BOA!mldXA!>jyj}Cp+tobe>`-_m18Wa1 zF=7AB4+bU%CNkwS-w7P#5+)O~tyDqc-d=Pb^C>Zt3Yl6+=cy<$H`#QYo~G{*NCqa& zu$M*B%-|JG;|{e+GlE9*nVug_qZ_qJqerz#tH_c@CvKC^bctvk=J|@IneG!!Gf!PO z?Xc}&G64$$6Elh=K_*sWJ6R@HO3Y|savGhIum!>ItobzMR&fK8)=ZZ0aGy?|Qagzw zQ`N>QQ^HLCs_C_94khVwLu3e(cCKiMN^Jv%F{SGl%tB8gDs3gYZhI>cnbXy!86wk` zB=t&*$}G`*WJuacq!5+05`|kt=5%#ghREE;q_LUy(#kE-CfJj9_9;Z=twfc}T3bZs zbai=#$h3u?)_iLT$-N<`*#b+-(WX-m@1pN&S{Ezy-slas+d z0TJ zCU1y(SfV+!C242mLe!(RMdN1qaNX_0x{lKc~*6D-jIj8wnST|1$bXhTSBGN-FgFhn1) zG{8XLd^t1>^3CQB+Cj{A$kOJ)wvsY2mO+nZ8R6N)49J_(l^**I%iO2 z4lSS4sHe1Le548!nt-*OU}|jn@Z_3Fjal7L(_}R&iDjBHdImxG_Ev^(FRF7p^1Hp1 zaktl2QN{7Qb}h)PmdW5vlH6pyy`6g=#k{?P!?)Mkr95vhWr}%wZ4U__60BO3@?4uo zyibLg>$GIJ)U3IVs2$r-Kec{*W99G}V^ejN7k%rzYiq`&>grO~>JFwkg%Xa44o#%z_{kgz_DIX}|G!F9kGoQc5r z7&Cw|HMap{;THpApqBw-U)KR4YyMc=`1S`;3@&o(0T$`3jJ*y@zstBog_UXG%XF6rfXh zU{y+^fNJZnAE>sftv?0)F>Ak7ZT%_Wk6HVzYU@t{f6Ur%Ra<`w_+!?7tJ?Zgz#p^r zTh-Q|0{)n_->SC$6!6Ea{Z_U0r+`0Z?YF9}KLz|TYrj=({VCv&S^KSO>rVlH%-U~N zTYn1pW7dAF+WJ$#AG7vb)z+T^{+PAjsks0PXT|-+HX}`e+u|x)_$wn`cuFkv-Vrn)}I3Yn6=-kw*D0G$E^KUwe_cf zKW6Q>s;xf-{4s04Rc-w#;E!4Rt!nE}0e{TeZ&h1=3ixBzeyiI0Q@|gy_FL7~p921v zwco0?{uJ=Xto>HC^{0S8X6?7Ctv?0)F>Ak7ZT%_Wk6HVzYU@t{f6Ur%Ra<`w_+!?7 ztJ?Zgz#p^rTh+Gc3cUaR`$gxB5Ylh&yz|bdo_cEa>eZaO`|i7U?ASqI*|KF@w{G3F zYgZ({?HXS~EI1(+q_BnIr2=i;Nz4rLyk8_!^IX7(BfL#0c?_a)r zIRZwa(4sA;2sAY{ahyJV`hyQXNZ`>&AAR=OX9;xu=ds5g`}pIJr5V&7i5A$NF!S2A zYoB}Wx!8mU4jj1Sjyqm|{q?usetX@zb&)8vXnWUPcX2CMu3QxFn4y|Eb0*5f<`k-f2M?}TvEu2cpN>SKRa+KY+fECrww+28JA-N)Te?mQ zqV4+i>-X&0Gi%l?$=ul3c=OFSWB58P>m!3$+b5oQ0uy}b&>=DFvuDp{G{bEuZjH`o zh(SAJ#*CdicT&&=nwy)kSwwLIa11{C>@(5!kw+fcxN)OYfvYfX+_+V%R>i2X@FHSu zH$Y4J2FX^l(*h`OQJ=rqVV+u+Qz!a{rBH5ixQD2O%-kH z>+1=B^wCFd8DYVK1-L+kUrW9WtR7IrP0|UI5{~9e*fzgZL3)Af3DUMO3C!WBXp5_` zef#!LKmF9TWcTjfF5G1SZas?$ROcq?lH#I;x5QNeRe|dXLgh#zQTUJB@wV{W)G32% z+o?pcGi24)jYzR+wIB+h?dHv!8Em&~*+Nv_J3REzL%fV&;@QRCg3QgGlh8I$+*`&7 z$ux>%3|hC05NRauGMr0;w&`?w@#4j=yz&ZF$a@F0z2}~L(6)=c1(};Wub^!ph6o)O ziT#ASWrRp0S<;u+5Y&sdYu2n`YD}KC&FErpLFVSpD`*>N+rmOp#Ina@aLWjhM)Gn; zUPC~eb-ayNotBCypxQNrkoy%TGS}dd-v{*&B<^bUQckIgL6O7_TGE%#k#%w z?z_~&beIqOKt$Wv^%hvry%CUrdks+_ZKU`opM1i*??_@^(eMI-^BiCh_XBNNCm%g} zbY7gkGrKneUf(;s_~MJV+;U6o*Kp!yxb+0*IXL$t>v-#1y5odDtG0{@AAIn^v8@2T ztLPUP;Y3?37w#?)Rt|HMY)!INm$vCjeo3WEL^yd;$bt9 zFI(IEVaq5+r){3BDXyTK=b{+9^}@{yhtZZz3#`mIw!EryrHUA!uhM1+c?lwJwlfn& zsl^#eXLNF;bp_o#R}5LWdEs!@@ixc0G+W0CsJ0#JQ^?ulR@;b8FGR!k%A##sKS72& zStoC=pr>@P-EL35nC1^Z{E%&IvVpC@dfjZgz<1~opMkB3cr`48;{(Vmb=oQYHtZ)b z1(rSJZhwA(my>UCjH#RRI@9bnu;t4Z$?up+7b_phkYm&}%=rxB)r2|GHsUAbNbV_{ z*luT$UBGQ%E3jTi2#=et#^7{3&Swy>Cd_%tbgz<@k&-aH1kqq3wB+1Ac_k+=sgz;3{JmzlMc^BJ<9?Ksh`bwmQp%VZ6N z;%JMLz-Byg74XMo-`&w#QV@T@c?E3)9ba-@XTv^2UIoeQ);b~q7bOqc^2Z~rz_Wmp zFTaoc;tx2lplzUtl{#A=gHyZ$3Pu7h%Bl9o+Zfepk%$7SZA6eFMkCrD^##TvUfNNo zLR*$|-8*#IWryvfVd#9cq?Xyb`}28O=P&x76NcXr{Vu=(5X> z&D$7}qo}RS*4wEC@Ba5q(V zfvndUJ2Cu@AYT$$_n?$>45X2|*DhZrUovUns~DyssjZB|)|l8Clh*Av`8%`XD6 z-pi*b)#XAGvAnnkVuFk7ComN)4R4x1XwO`jg0sSS=SS=ci1=vYJL%jos9%? zk)J~xjPZd%QhQNenR*iL5yA@YaOm_ z>Lr8M_`~%?XURT|5_)7RqA2`{f_8yv6ks!cw?3ff(B!T-lD- z6R1wyFt<6uZDkC%q-(<5)`;aTuAdOO3Rx3~B<2{+Wjz7q!+-CPBeRcevX~#Sy#Ce` zxCB`fh<7czo)AyBqLflwRumbtlK9iM3nn04P(?(vyta4x)7Jf<5DJ7>DwtopC=2iM zV{4I1=pgEx8S;dypcYO+PP*gofG2#4viL>LHDW=VWdTVf8?+MU7~b9~jd$(gtgBZ} zdDT{aP>4$1N(Hu+dR>%1d)&5dTlg|N4LfIsoU)sOB?4ygY{e9E(j9-NY?6Upoya18 zcq_%Ba?TPzh(rcbxRCJnPHDVrPxvzBls|3Vb+OOEh5ZHm)xr-VNtZ^w4%*-LY!_(T zL3@tvQ>v}M`>Wb|)i%73kwJs8MUGS|zo-y4g(N!T9!?h%=}wW&{WU>kS%BSxtiAiY zqAw3K{WiRhQH-NAk;X4syEbeJX}L4*;dC+0?iAVFUlT;u2hdi29^uO)f~S_CE%V~6 z`xx8S*wz$Eo~-F^g+H=BkV>VvUv0^cy%Zg9{oPZv)sHHm3aA3AfGVI0r~;~hDxeCe z0;)jq6fpl=<$UOF1-F3(;C65a_*ZZzxC`737J^0K9`J8qG57^o0+xb%!F}L<@BsKF zcn~}U9tO+6Bj8c69IOBJ;7RZl*a)5mzXqGYZ@^~o z4A=s;f@i@t@LRAQe9pE0uI1a`#P!dM89DT$3aA3AfGVI0r~;~hDxeCe0;+&2pbDr0 zs(>n>3aA3AfGVI0r~;~hDxeCe0;+&2pbDr0s(>n>3aA3AfGVI0r~;~hDxeCe0;+&2 zpbDr0s(>n>3aA3AfGVI0r~;~hDxeCe0;+&2pbDr0s(>n>3aA3AfGVI0r~;~hDxeCe z0;+&2pbDr0s(>n>3aA3AfGVI0r~;~hDxeCe0;+&2pbDr0s(>n>3aA3AfGVI0r~;~h zDxeCe0;+&2pbDr0s(>n>3aA3AfGUthfl)y{{~CkJV0bW@?}lJzmR#*8^$W^_%>Q_s zAX}e`5}P?KMJ|=EFCI%x^dw395w$l2Hw9yCJ8t@7#vEdOgA)D)K^ZXZ$f1bMvN0(+ z6Tv0aJSmtGTumEp%(b}7XX-cClhMGP=pZnJb62#SPf%}Nkm?|J$ESKyf2QtSuYV|% zr?k+P2iFACxc*5&jlK6*&3JX{1|9L_)fxJER4qJ4CucQbI!bK(AM? z-@X6mw|M3}duFfouC-(K%$oh8EC&mR1$8gc`egz^w!Gm?cjfy7@$Rq#*#VtB9DpVc z4z?gO6K4?Ep4rvjoC$0K0YR9+4nTWzu$hY;(B7E|;@|`{F^5$cQgnaGsM}%*#%;1;>7&J4)Mac3}_3yg8@4+o4GhS z-3Q@rXA29ZEQfF(I~2_Q&z<~tIJkGUe}-dW3pQ~E{tV{c{?B0ktq~4j2N#FCesKA# z5&vdK_%GfZoWPb&K*(>+|2NBji}T*uuTJ}4t(?JN+yC2&dKoIwZQ{3fEl>ip4MoI%stiON4!H zjbq-rRgvt^nm#gNL&6&}jguy*67N_)X@1KoJosx8;+ed;Z?7U$+8_s?6CX`SvNa_own^j&C~;&_jvr%zKc2_A>- zT;`YO$;sdhBbBA$Q;u@K%}Yh}6R9s^*`;Fx(x28CPL-CP9*d_OAs>Bo$!nifMe4ZB z#SF}|ja=J-Yo*vk!Z{rtUu`LM*Pl-6&{PfbNSH!nmwJ61S&>#OOS<^^qrsw!r=k$o z$m^;@)ELU;2ZR|xX5vRotBgWP9Bm$Gq_&lsRIPL3^p92o{SMap`O6WNif(qdkMPQ* zBhQw$*k+ypV|tJw5i6VH}((jO%-9%&Y)uim=R^=}@U6XuTnim&6oSf{pO0Zo5$DIHh>6 z4oeeDOJXTo))FA$bEd?=xTi0}%1cf^OHa2ZVz7L1?MALUtw2X zX~&C$0>QCAPeY0J#0tkIb8^i84l$pB12uZ6E

b*p?HCN*%&TiUohb&D- zmX!-rd}Yt)DINE4G+HEf04-G@+cRI=-FKsu*6-Wj+e%=#)!Gf<@z!-?jYLbDPEi=5Z<21dwTx0O1A4~I8Tapn?C*d z6E@@+p`BXZS3dhUm|hp#kn`!K2#vWAL#nBTTyj?LB}o2JB)z1o_ZvSCLf$R}`R4MW8l)BDR>Lg6+Y z3BA5=PiOYDw-4-2$~q54*afWG%8g8BS^>csBeiJ*SBVt;;63-Vru3(kzMBSNo0%IP zGk%*sEFAr)lH6TidKfQm_%|J40@5uppt6(D;8(@#(cV)i92I=fw8z=iQS$KvFz21tpw|9ZQW8gf3nou*Nz4F*0j)Ik zxq|}uQD+v$hk4)*U1K3%>p|t=kSJyf|{fL`564Srz`T^sts}WumwWyAE5I( zcHlWKjGGoCGFp*Qn0P8)1)Qde<6K&t4>-=IWY+ABd(tXU|>KChwYK$r===$P- zv)0okdXGuNqKAoMhKUXohrV@|8ZQJR%6K#!uj;IM=5z_<0$YxKFD^73Hian{KYd}$ zPG(e#-VI2gkF_2SJrQY0kZY_eKY@c5KeiRWhK`y4co74*5x}BA-ZmPv)rf{MT>)3m7ppvx( zvM#oxXT8CU%@S3yiXXztgAagz@VYNiSXfz|%-_ks=u{bnv16kdS(P4}-X$Z-@(Y1J zVYQ1E0e#AssGO(WFCQj)L^){>7CbUGd@0*jVfbx{=9I#Hogd3gqn@RZb z_PJ|RcqvosNiXK%R{=YL7p{Z0Z^XRFT|d0rlU0E1z)w`3n5~icH*XZa0gA{;IE~1G z6tTsbxd_tAXFs;pV6e#TDcNC5)qyG8qERg|2n9oFRpMD`g0~?Hf^{h>{Fdn z&5EzPY=(`ALs||Zq=r&Ue8zZeX&mE(eQ&dC+|4O@D-Kx$FU&6N<6b)A@|0FG29&Le zJ;+DDm^`xCrc<6YjAhGp4fsf^8J|C#zP9teNI^hd5q`3g%MdrGuOEyv_IZV@)g zQ;tF_E>7R85_CP$FP!pP7;mf9@|jp{KD_e9aZDiuHMXE#S{Pj*l9I zk=*={vJ9T<$(xcd0qSrdwq>*=5u@N_$|or_%04WO$E>s+q`V*5<`^?coS(ldNf1ur z^<_>*%|4=0+38>nQf=RhP==zCXle}&Rt%P+Q2J63PhiMLi*{M1oJ+te=4n{G@T!RX zOvyM{Xxowa8XY-30ROT7Gl4*J)DZrYk#xpY!Ynr|W`o3Og@;+QZrrSq;*!zgXmXL} z&oY^@P@9>(*JQWrf(p`#I~-r)8@2eoW`RpTtT<5O3GG;48f?v5+D?>WQvG%$#u2f< z@38#p*}j3qMn5Ti!bhcgD9lA(&cMZ83&Xt9V54Pe-@0pO3>Nw|^H{p)RX6CW+pT>w z>s@G4yBbx>q_ZipAxFK4HMtO2`E#a+{i&xy4csKOnuFj5>aKwJkdTn8L+u&qA_}x< z(X!61OU^`=sC@*YVb$^d8%>g2j}gPU4}h?FAEMbdc*~-m3!Nt&&`~dwy`|`xhA{a_ zFn0NTOZAe^HYpm;(sfg_!d=MDE@u5g78C_vG(44R>Litrw4_g-&{a0xuy=nIx{I02Ixw+J>(ZC_X~I1d)8t9yM_Dc?$!UF`AZs=zTONh6x99kJw*dLo7^wk0>XDc zq^>|G$X${qNY2W{LQV>_Hv^l4>@5Y!HPj^mJmkVc$O2#s3y>L*?`PfyxJ&R%NbgMT zA$&io1j${T?D@WDczpIIc0dT9vl-v-sUF|&+I-&~{kY<83$nKnB)4*QcHm=Xc5`!M za${!#J6STb^78UBf3GF~%ays=-+B%%PPX5*%*~kZ61w|j62i>N#LE0r_dde^HK=>t z-$Md}!GAltZ^Mr!es{;l!otD)Gy^E`GakU-|!`aqzKo@v-p=F#oLl;T~vy7q7h~z|6z!?gc`K^)GLKT>hu7 z`Cr+;kg__f0=L>9CV$udFmizaodD)Q3y?j~ob-E_-Ooxvav6IIFexiJ^Is$Lf2y(l zZ))uSn;OU8YJcBF_a8Ap5ND9tj|iPjOl^SxGq8)jvmiM;`HzctpDXT$^~W{N?-Bhq z{rG-Nu%BmtgMPpK-ycQpzY3^Zx!9T7n}BQ~%+5cHOb+&zds^pOk8f+?A1RB7h{ocG zrWtFJM%56<$azjqR0#bd9pf2urref6W5Nv_xR{uRN( z>zbjI3zMPEgjZF=3$#RlL>u+D>Xej}(-Z26>CkQ*NJw-au#uNQZnnTzfq{6Xc_-S7 z40a4@m#;TyY3#k^#fvy%>03B;diS@-o{wII;dvIb7`F4=50(Z{k$+KW&ermH znZC&1>!Eph*`oW}+H75UqvSNmpBEvZ)1LKoC4Ix+ocU9zVy2K0fg z1CriqYAbupksRSiAmu{ta?8FE5SL7d+l{4^afDwy^O&AS=X-3yNkjQE&$uF|QdEO)LdA#Zz0#j+iE#sSjO-Cp;xJ&OTU) zvquQx(XlZS@a-bYNSDH+)h^gkXGa{Se&Kf3BT%(4H~-ul`z1=?6K)LOtPv}(i&oga z-sRh*^7`?U&1lV(lR*KiKF`v%B;&sQgMES*oga}cMhTsmEox!2=ANliCRJmHev0a% zh@T(q^ATN*ZvzdreR<7~+OzRIXgJ8PZNoJ$WW4kn?XV6QJDZX?KUnNJ!{eH08c(@E zzzJde!4VgaM&BzL>!INqIj-DzNpJioJr^oe(XjH1Vgl(5oyp!R2)p=r?=V@fN@G+( z^g)m~Q~%EwYs@~KPYTG!m}2DTr7||RyeF-Day^*yXL2$1oEKf)Tn+0GDK!tsZ61ir zAD#rEt>$jWBU(e6`)tzvsTGY*I9Zv2^R+Z<5CS?pYFjA( z8cV<3+m@f^pQ#o?uS~agEPO7@+E0;$u+p^H@~)cSBt9(8(P+9XxAS~gYx>osC(Fpb zGZiw`&^z8rFPJ$hW4vRY%j!Lg7A>0oi>Z2X?tP}EEPDE`{zvcLE^M~GI1jS+GwEWW zd+*o_*r1id&bIXCU_$EwIDPJs>yP2;U_)hB(uRo)O64LUd$GQ+H@Ui(Qn}mAry@^I z#!g$@c{*Cb6NKW!`pDv8E8h&^(J0r*d!}CBE)j{A53RhUF*{Php&aNP)kiDN*(}{I z4K%$BkA#;3iLaAiZF?<3m$CC|sD5oOC?D5*I5h5K$??wkivugLY0r+k4)w)!CQgNyD=o&;g!e2A zA)(C_9C)Ql<%X%s6>l^vas;I62RL<23O~IYt{t&`l~5INZ_PSwJd7ZY4c zm78i%G83ZQC91?nv2%OsAzC(<1_*4bO+j>R5s?*#AoB+yMUV;me0?K3?(dpxOiSAd z6r?16$i4;A{kj+2sHE-t87^*00kY?5JQ>f3<2*+POj3QyAy9jqsU6nCbS9}Xk5i3| zHqf)+#gpHzm43;NbAr$6wBo8G!q|6yUUtFsVmkNKViu}a|FjE{d!lMAJYd1SqJGfZaZTveUg8`t@=0{Hb*hN1%Zh`KP$6YK@k3xM?H3c3S{$x(iy7^R8FQVY-SKrPGle*uAYJ(>=?Frz z2I)ud6-DxOYy5`wk0=P?hS@603IhB2r->@gBbLCHf9oM?Q z+rMvYr%jb0x(NVyK>1d3*fAEtL`Reqy>j;`=2mMbr}49FAiKub8xzr?UziLd7!m({d3Q<>^#!r?g9 zsjb#fU#pY4a%k7;(<{s1#0b}uk5&kQ4?bQ8pL`PrKfz0AHZq%*_4n~nv7?Edi>6h>!6i_((7S>?t^MrY?zR_BHJ6q*%{a@IxUj@(4lPd$sTE2U%Oi=5 z>1hQF?UfF!kUWgJ(TdB?{mi#sz9`oJV!jj+3f`F1tyB(mFSk`99c{I`5V3O@&iS~1 zL0!TdJ`a)0i^MLxT?8e(nw;k0Rtcq`u_4@}!I>$Uv~in!Vzbxd;;*k~TbQ%!@U1B6 zO_?VUIh1&#!OsQ_u66OtvM#xmz*@-s#K+|$=hhWY!3T+Kl+jxKL;6o^3SlPm#QQ08 zdr!b}vZaYmZ4l^G`B0y|3PdX&Z^>T62CAbaE|d&Jf~IG%L6dF~ZP9MrS39mHAG37= zK8w>Kw?7K0I!eHOWmKf38S#1dVUI3~i_1kMG(zAMv`rU&a3Lui_X)Uh0^2)laG}O8 zVs}U*>@j6_wURf7cjJvIf5o!`$MuZ>A6@Kf$#7xt74)h13 z7KEMWIoAjfJXS(q1I>r7(;Y=B{Tt9PFsg)`@je#VNs2YNt}}MvVU@9qvKX~CmY%TE zvT;ReZk}LC&viHuR!HK@bR5n3g=DlIm};(aR+xGL*q*RokSP)Ky)wY=jXZ60NN)RP zs!s5!PxfUIBt52}2KH(63e^&S?YoTqmpqD-#zfe+2@I~`ssdeSMWpWe8(>(}>xWWX z^fL1W4z|lSr1nZkEn66HywQrlsBx1m2d5UPN9GCDIxmH=yP0B`d}~Dun2=iwRIxLW z0KIga#lE*8lnpc!%kRsEUO>^6_x5)cBg7Slm~#h4Rqo^A;~l9Pnyp(jnlU7t8fH8%i6INg&y4oH#;xPEa@N%ntoYWu$lM(ZWKpbX?~nyHFrfdpKAgVUQ2CEP2!T5LIxFXmnht(4#zQfbE-c7hQPxbRvgJ z?pR}x(t-T4`6FlC9Csdq59*owpsWk$E&K6{lFo6`r4ZIcV&jB=BG5}13jhsHrFV{E~%>+b=C@+d0IWN|ivTD#yJIkWI&es5fx$Wt;PSY`Ku z`~Ah!YHL#qfd)6X&b$HGkQZOB_9{I3Esqraw=Y7-I7?^Z*_hLmL`2o z0h^?$6@{nrOC*(ROFUC&Z-26t_dc1yMJ%(P6wpG$#JYl7zUCPXgdZ^P))XzVmh@3W z38k}HUMtOY#>VgJi|N(k9Yad(Nf%$Y?9Tl8qn6BldO7#SVL&2m~g$BaZ4pSu5<*A2j|Ju+iBU( z0tJkv=2>IC-px4T1yXjyE@LYCg9H{SempW3%>BviHGT!+zJ^ya(KBQrO5$_WTA+Ld`&*?h${o z$tW4aFRF?z#gu#3$Ef453e?GMDaB6O85~lS&xQvyXLs7Eg<%Sk+luMDf-7$vP@e84 zj4)zdQE7CKe40yHL^f$@#4c)-(fT+UgWD0B`$=wTTyczk-;w{d-68yX^9m-^5gjdU zTO08DBpIY)>soA{A;okVoRy?{o9C-hJlTn`Xy9m|?7TzQ14Pr(lCP#TD^HC*hg{6P_;V8OiD^Zew5^zZo2srUR1loX~C_%2SBU`0S2X@oGe^?W7V}l1LCPnns49QU&LFtNBUIk&&MXzbm5dJ8^iQzUUb&OBuwH&m)^)gqq(r| zHIk-FfIbzjmg>~N*4M0LlryWNwnC6KOFU5N%rhc}86kAV7-<4e4Fh1GWKc{6x8mrm zjZ*424Xp7_Z!yEbM~K;^cz|y0AIS2dEg$#FVd)i(jrB(Mg6l8Bi;6r6_GHp{Z4+Wp z_iHCj27|~&WlqNeLGES%`R!mi?~S34o{f!7QYyj+b5UCY=prY%NCTf}B-o@ERoB5U zq1I5|a1PLiM`XV5PE?}7?!u0F85aCu)LbEZUeQHPet!jZRb8{(Lb7F_9&47jJ%7r! z$BpS#t}=YA>`v130&IbfyL9S<=!sU(O+{Pq*h*jc2Tm>-`$q_Jj(L#hP2rI{sKenYaw&duA)tOZ`#OArr1Fpih2MqRkD%{9G3P|OiO zOPycCr%t7&}a0Y2XfkCI63-+srH%m%So}UrSZX3DUWJOAm6ze`oTb@}=}J94pb%xQMCmu5Sddz>IXH!Xrq(1r7yD zhbS7w=^H5kJ=B3#M!G0J0exs`49*eJ-asN!(V|;wGj|y>GULk#RZa`ZVrxEZ@3^?!&7Ev2?428ATN~ zlK2=mfUKOG#SSWwg>N}W1q;hJ!Rh|Q{^d_^>Dq3Y*Y&05F+AGslr0P^3uhlcj9H7Z z&2_-nWMtQ`Kr63q+K`WXxpG(}>RRmZB?=$*FKf%SQVz-8y>yrswA~hLYmq`v@RCc9b)^5R%=E#my^7s@33%}Z2 zOQV!sC{NCMh0&GeBIiOF#22gsM9jzVkF@5<0V|k8Dql$~inwX!G9r#zd33^xY7saZ zGea-Xvr{pqri%SofGa0g5-F6*@ypaL%0xBrp}6MQYVEZ~*>H%nE8H2m3$8yACdq4`C_WK+(StYfDz9|8 zsA|1ShCOU5Ki=9puO;IYwzWnePm<=p0SU+ zFre2;&e1;z990|q~F^;V6axu}J2`*UR_d68B%|z4ZT(dq; zh8x{Ps?c#Z3B!4s8+Z8CxtezT$~TOTE`W{wlBS83L#)r^Y}w{(cYnKniI;MiEH&0E zbcyLj>l*Ud!*__|AoyNb>d;74;n$0D?w%BjuBgpfQto}yE?+~E)C|9VHU^weiDkrD zKq)qoRkk;DQ!y90q(q`5te8)AyHH#eiHD1o0}_afHB^EgH8dELG{3y~&8zDw&zw9TVr*}=opz-r@IlnR+J5@BnHkn&Eh zZURIfY0<04cG=o|rO6knhl#MwtPtRcE<@M1__z6L#aFZ4$|ch1<@s)qqN0;lW8Z{J zQzfAZ`#~x3n@V%^{S%_zarqMOM}c*TUySiJhP)`6gj7M<-WgMaE3L3-Z3a2;J^mZf zR2LaUCWFxw=kT#ZkFf<5)Lrm(UP6*w|TDJWUr_PCPHLch<0Aqc^#r4|t6EM98 z!l0hpxmzN=%jX};3RmKuYsNvnOsPy#-G1C(cME^NR|S{mF>8eb1(o{uUe&*m3?AN- z41mt}dj;QV279km)K*w9dKM4VSiE~+=-phQ5E_n7hSVO6G<^Y7qnOKArBUXt9a(tZ`B*Ie`fPE~f?I|^KZdCo@Kidy*@gohUlO%G3T^#MsUtscnJ=rNX9ge7 zYZU@U1iMA}(jCl%F#~f2^v$vG*G<99^+DpQAjg$}>IAz?1OYq?yR%wyv!i$^$qTV* zZQ6C6JUqDerw;CZruJM)ii!gToZHqE8KWL5YK{jAYN20kX$dhR!Xj(%qbS&Kz!OvC z-1_4j&%#LJrVm`E9;{^WX)Fb|6qb;Lj5P*xfdF)H!-njY-R}q?QdDVdTPUQDPa<m7N(W|$zRH0 zERVD|J=-cWnyG@G95+CYCRdd{6Si$DC~DA+4mFc5?Qs^-ani_3v2GNoNk$A`SR-jH zu>|$)!`rm=&j6ZZstYBY1|4@yqbz3S5t_B|@`|2<%P_Q@Z>=H~Vu8<TGR>-Pbdz)x1<-rS-vTvB>&rHu$-AY1ik#eR*zsw*n*TYG^Zy1Ado!Qs5Kg6OTa^L*~Zn ztjG*C)s=}B$W8@38y6LMU0|Kiftc+k1`2BGcF91evPeDW07@O62^-Bqcya@R{|lds z8+WFTR!I%)XH61cad>mkVl$;P@q*$Y^f3x^ub4Q*}ja^p5k3;l^$&im@-iBPoRWr+6#hqlzjp-#_wsb(7)DAlr z(UJ&H^r(L$p1xE%Lz-e77_pg9S}c+e3p^XeTNi&D{^l~hN3#yIODjwI0?e5QfPlR1{~mQ`nwdepZ80TEqz+t#6}CAEiY`%}YSr>7qVu9&8;zHd5ja@&!{+-)n* z68zkB{cvkOM(7Hzm)SIoW{ zwuVj~o0zn3Lx;_czv51b!>5YvnggvZ%tlHa@T1N+7 zKz$~El#C)MXSyU#5DGkegM~kk8Katuo1eB}isOd;=wUak8JYVbS&-LbRWh#=GjV#i zF}0odOP}A-J($Lkq`WAa6@8Nx%|E-CfhudilTN)YX@GK*)S2egE!bbE1@5TIxSbwo zg@mC$0J*-E2%aTQKjoT@g0+)A2F<{6520q%mG`FJzK4LG9QV}KU&Gz6rUMTYEJUH9 zpi~g<2LT!e3+lh=*>@xHoBSke|7rD`3e-J!`Io5Q760Tv|4zsL;r;hX@RL)0Pssiy zk$1&EasGpz{eJ~_zoGd{R_}^`g8m|B|FdI$Swa2LM7+DM{1fGOvi5)D+|#vxiORp> z{DZvx-$?&#SH!;{{UUS!uPE*Rg7S;p{og3}^zL7B{x2y1AKCi{*w0z;JEicR?)^(R z?k0!XFY@=#k^X7;JEi5GarjGi?xy-L{^3u%`}%w8{hx%FUv}B3cmJVq$IZB>zx=fN z>FxKIl7IGp=A-}KHvbdl_Z9K}1?HD1(f;#w=1S>MEC>JKUJd>3 NZ~tx?P6OPZ{Xgs||HuFU literal 0 HcmV?d00001 diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas index ec8618f9c..a542544fd 100755 --- a/components/fpspreadsheet/fpsopendocument.pas +++ b/components/fpspreadsheet/fpsopendocument.pas @@ -189,7 +189,8 @@ begin //process each cell of the row CellNode:=RowNode.FindNode('table:table-cell'); - while Assigned(CellNode) do begin + while Assigned(CellNode) do + begin ParamColsRepeated:=GetAttrValue(CellNode,'table:number-columns-repeated'); if ParamColsRepeated='' then ParamColsRepeated:='1'; @@ -200,11 +201,9 @@ begin for ColsCount:=0 to StrToInt(ParamColsRepeated)-1 do begin if ParamValueType='string' then ReadLabel(Row+RowsCount,Col+ColsCount,CellNode) - else - if ParamFormula<>'' then + else if ParamFormula<>'' then ReadFormula(Row+RowsCount,Col+ColsCount,CellNode) - else - if ParamValueType='float' then + else if ParamValueType='float' then ReadNumber(Row+RowsCount,Col+ColsCount,CellNode); end; //for ColsCount end; //for RowsCount @@ -226,7 +225,8 @@ end; procedure TsSpreadOpenDocReader.ReadFormula(ARow: Word; ACol : Word; ACellNode : TDOMNode); begin - + // For now just read the number + ReadNumber(ARow, ACol, ACellNode); end; procedure TsSpreadOpenDocReader.ReadLabel(ARow: Word; ACol : Word; ACellNode : TDOMNode); @@ -237,14 +237,21 @@ end; procedure TsSpreadOpenDocReader.ReadNumber(ARow: Word; ACol : Word; ACellNode : TDOMNode); var FSettings: TFormatSettings; - Value: String; + Value, Str: String; + lNumber: Double; begin FSettings.DecimalSeparator:='.'; Value:=GetAttrValue(ACellNode,'office:value'); - if UpperCase(Value)='1.#INF' then begin + if UpperCase(Value)='1.#INF' then + begin FWorkSheet.WriteNumber(Arow,ACol,1.0/0.0); - end else begin - FWorkSheet.WriteNumber(Arow,ACol,StrToFloat(GetAttrValue(ACellNode,'office:value'),FSettings)); + end + else + begin + // Don't merge, or else we can't debug + Str := GetAttrValue(ACellNode,'office:value'); + lNumber := StrToFloat(Str,FSettings); + FWorkSheet.WriteNumber(Arow,ACol,lNumber); end; end; diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index 089faaacd..cfcaaad29 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -74,7 +74,14 @@ type TCellContentType = (cctEmpty, cctFormula, cctRPNFormula, cctNumber, cctUTF8String); - {@@ Cell structure for TsWorksheet } + {@@ Cell structure for TsWorksheet + + Never suppose that all *Value fields are valid, + only one of the ContentTypes is valid. For other fields + use TWorksheet.ReadAsUTF8Text and similar methods + + @see TWorksheet.ReadAsUTF8Text + } TCell = record Col: Byte; // zero-based @@ -211,6 +218,8 @@ procedure RegisterSpreadFormat( AWriterClass: TsSpreadWriterClass; AFormat: TsSpreadsheetFormat); + + implementation uses diff --git a/components/fpspreadsheet/fpspreadsheetchart.pas b/components/fpspreadsheet/fpspreadsheetchart.pas index d2e020184..87725a5fa 100644 --- a/components/fpspreadsheet/fpspreadsheetchart.pas +++ b/components/fpspreadsheet/fpspreadsheetchart.pas @@ -19,12 +19,10 @@ uses // FPSpreadsheet Visual fpspreadsheetgrid, // FPSpreadsheet - fpspreadsheet; + fpspreadsheet, fpsutils; type - TsSelectionDirection = (fpsVerticalSelection, fpsHorizontalSelection); - {@@ Chart data source designed to work together with TChart from Lazarus to display the data. @@ -60,6 +58,7 @@ type constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure LoadFromWorksheetGrid(const AValue: TsWorksheetGrid); + procedure LoadPropertiesFromStrings(AXInterval, AYInterval, AXTitle, AYTitle, ATitle: string); public published // property WorksheetGrid: TsWorksheetGrid read FWorksheetGrid write SetWorksheetGrid; @@ -205,4 +204,16 @@ begin Notify; end; +procedure TsWorksheetChartSource.LoadPropertiesFromStrings(AXInterval, + AYInterval, AXTitle, AYTitle, ATitle: string); +var + lXCount, lYCount: Integer; +begin + ParseIntervalString(AXInterval, FXFirstCellRow, FXFirstCellCol, lXCount, FXSelectionDirection); + ParseIntervalString(AYInterval, FYFirstCellRow, FYFirstCellCol, lYCount, FYSelectionDirection); + if lXCount <> lYCount then raise Exception.Create( + 'TsWorksheetChartSource.LoadPropertiesFromStrings: Interval sizes don''t match'); + FPointsNumber := lXCount; +end; + end. diff --git a/components/fpspreadsheet/fpspreadsheetgrid.pas b/components/fpspreadsheet/fpspreadsheetgrid.pas index ba72a9ea8..36ed1cd4d 100644 --- a/components/fpspreadsheet/fpspreadsheetgrid.pas +++ b/components/fpspreadsheet/fpspreadsheetgrid.pas @@ -31,6 +31,7 @@ type { methods } constructor Create(AOwner: TComponent); override; procedure LoadFromWorksheet(AWorksheet: TsWorksheet); + procedure LoadFromSpreadsheetFile(AFileName: string; AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer = 0); procedure SaveToWorksheet(AWorksheet: TsWorksheet); property DisplayFixedColRow: Boolean read FDisplayFixedColRow write SetDisplayFixedColRow; end; @@ -210,7 +211,7 @@ begin begin lCol := lCell^.Col; lRow := lCell^.Row; - lStr := lCell^.UTF8StringValue; + lStr := FWorksheet.ReadAsUTF8Text(lRow, lCol); if DisplayFixedColRow then SetCells(lCol + 1, lRow + 1, lStr) @@ -221,6 +222,20 @@ begin end; end; +procedure TsCustomWorksheetGrid.LoadFromSpreadsheetFile(AFileName: string; + AFormat: TsSpreadsheetFormat; AWorksheetIndex: Integer); +var + lWorkbook: TsWorkbook; +begin + lWorkbook := TsWorkbook.Create; + try + lWorkbook.ReadFromFile(AFileName, AFormat); + LoadFromWorksheet(lWorkbook.GetWorksheetByIndex(AWorksheetIndex)); + finally + lWorkbook.Free; + end; +end; + procedure TsCustomWorksheetGrid.SaveToWorksheet(AWorksheet: TsWorksheet); var x, y: Integer; diff --git a/components/fpspreadsheet/fpsutils.pas b/components/fpspreadsheet/fpsutils.pas index 5c477a3c8..070abefe0 100644 --- a/components/fpspreadsheet/fpsutils.pas +++ b/components/fpspreadsheet/fpsutils.pas @@ -1,3 +1,6 @@ +{ + Utility functions from FPSpreadsheet +} unit fpsutils; {$mode objfpc}{$H+} @@ -5,8 +8,13 @@ unit fpsutils; interface uses - Classes, SysUtils; + Classes, SysUtils, StrUtils; +// Exported types +type + TsSelectionDirection = (fpsVerticalSelection, fpsHorizontalSelection); + +// Endianess helper functions function WordToLE(AValue: Word): Word; function DWordToLE(AValue: Cardinal): Cardinal; function IntegerToLE(AValue: Integer): Integer; @@ -16,6 +24,17 @@ function WordLEtoN(AValue: Word): Word; function DWordLEtoN(AValue: Cardinal): Cardinal; function WideStringLEToN(const AValue: WideString): WideString; +// Other routines +function ParseIntervalString(const AStr: string; + var AFirstCellRow, AFirstCellCol, ACount: Integer; + var ADirection: TsSelectionDirection): Boolean; +function ParseCellString(const AStr: string; + var ACellRow, ACellCol: Integer): Boolean; +function ParseCellRowString(const AStr: string; + var AResult: Integer): Boolean; +function ParseCellColString(const AStr: string; + var AResult: Integer): Boolean; + implementation { @@ -114,5 +133,136 @@ begin {$ENDIF} end; +{@@ + Parses strings like A5:A10 into an selection interval information +} +function ParseIntervalString(const AStr: string; + var AFirstCellRow, AFirstCellCol, ACount: Integer; + var ADirection: TsSelectionDirection): Boolean; +var + Cells: TStringList; + LastCellRow, LastCellCol: Integer; +begin + Result := True; + + // First get the cells + Cells := TStringList.Create; + ExtractStrings([':'],[], PChar(AStr), Cells); + + // Then parse each of them + Result := ParseCellString(Cells[0], AFirstCellRow, AFirstCellCol); + if not Result then Exit; + Result := ParseCellString(Cells[1], LastCellRow, LastCellCol); + if not Result then Exit; + + if AFirstCellRow = LastCellRow then + begin + ADirection := fpsHorizontalSelection; + ACount := LastCellCol - AFirstCellCol + 1; + end + else if AFirstCellCol = LastCellCol then + begin + ADirection := fpsVerticalSelection; + ACount := LastCellRow - AFirstCellRow + 1; + end + else Exit(False); +end; + +{@@ + Parses a cell string, like 'A1' into zero-based column and row numbers + + The parser is a simple state machine, with the following states: + + 0 - Reading Column part 1 (necesserely needs a letter) + 1 - Reading Column part 2, but could be the first number as well + 2 - Reading Row +} +function ParseCellString(const AStr: string; var ACellRow, ACellCol: Integer): Boolean; +var + i: Integer; + state: Integer; + Col, Row: string; + lChar: Char; +const + cLetters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', + 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'W', 'X', 'Y', 'Z']; + cDigits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; +begin + // Starting state + Result := True; + state := 0; + Col := ''; + Row := ''; + + // Separates the string into a row and a col + for i := 0 to Length(AStr) - 1 do + begin + lChar := AStr[i + 1]; + + case state of + + 0: + begin + if lChar in cLetters then + begin + Col := lChar; + state := 1; + end + else Exit(False); + end; + + 1: + begin + if lChar in cLetters then Col := Col + lChar + else if lChar in cDigits then + begin + Row := lChar; + state := 2; + end + else Exit(False); + end; + + 2: + begin + if lChar in cDigits then Row := Row + lChar + else Exit(False); + end; + + end; + end; + + // Now parses each separetely + ParseCellRowString(Row, ACellRow); + ParseCellColString(Col, ACellCol); +end; + +function ParseCellRowString(const AStr: string; var AResult: Integer): Boolean; +begin + try + AResult := StrToInt(AStr) - 1; + except + Result := False; + end; + Result := True; +end; + +function ParseCellColString(const AStr: string; var AResult: Integer): Boolean; +const + INT_NUM_LETTERS = 26; +begin + Result := False; + AResult := 0; + + if Length(AStr) = 1 then AResult := Ord(AStr[1]) - Ord('A') + else if Length(AStr) = 2 then + begin + AResult := (Ord(AStr[1]) - Ord('A') + 1) * INT_NUM_LETTERS + + Ord(AStr[2]) - Ord('A'); + end + else Exit(False); + + Result := True; +end; + end. diff --git a/components/fpspreadsheet/xlsbiff5.pas b/components/fpspreadsheet/xlsbiff5.pas index 51edc752a..940b10673 100755 --- a/components/fpspreadsheet/xlsbiff5.pas +++ b/components/fpspreadsheet/xlsbiff5.pas @@ -1250,9 +1250,11 @@ begin try // Only one stream is necessary for any number of worksheets OLEDocument.Stream := MemStream; - OLEStorage.ReadOLEFile(AFileName, OLEDocument); + // Check if the operation succeded + if MemStream.Size = 0 then raise Exception.Create('FPSpreadsheet: Reading the OLE document failed'); + // Rewind the stream and read from it MemStream.Position := 0; ReadFromStream(MemStream, AData); diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas index 3de7d01d1..4566ec521 100755 --- a/components/fpspreadsheet/xlsbiff8.pas +++ b/components/fpspreadsheet/xlsbiff8.pas @@ -1234,9 +1234,11 @@ begin try // Only one stream is necessary for any number of worksheets OLEDocument.Stream := MemStream; - OLEStorage.ReadOLEFile(AFileName, OLEDocument,'Workbook'); + // Check if the operation succeded + if MemStream.Size = 0 then raise Exception.Create('FPSpreadsheet: Reading the OLE document failed'); + // Rewind the stream and read from it MemStream.Position := 0; ReadFromStream(MemStream, AData);