SimpleExcel.php
[Pman.Core] / Pman.Gnumeric.js
1 //<script type="text/javascript">
2 /**
3 * @class Pman Gnumeric.
4 *-> load up a remote xml file of a gnumeric document.
5
6 * -> convert into a usable data structure
7
8 * -> ?? apply templated values ??
9 * -> allow modification of fields
10
11 * -> render to screen.
12
13 * -> send for conversion to XLS (via ssconvert)
14
15 * Usage:
16 <pre><code>
17
18     new Pman.Gnumeric( {
19       url: rootURL + '/xxx/yyy/templates/reports/myreport.xml',
20       data: { ..... },
21       listeners : {
22           load : function()
23           {
24           
25                x.applyData({ ... }); // key value data looks for {value} in strings and replaces it..
26                
27                x.set('A3', 'test');
28                
29                mypanel.update(x.toHTML());
30                
31                x.download()       
32                
33            }
34       }
35     });
36     
37
38 </code></pre>
39
40 * @constructor
41 * @param {Object} cfg   Configuration object.
42 */
43  
44
45
46 Pman.Gnumeric = function (cfg)
47 {
48     cfg.data = cfg.data || {};
49     
50     
51     
52     
53     
54     
55     this.addEvents({
56         /**
57              * @event load
58              * Fires when source document has been loaded
59              * @param {Pman.Gnumerci} this
60              */
61             'load' : true
62     }); 
63     
64     Roo.util.Observable.call(this,cfg);
65     
66     this.defaultCell = {
67         c : 0,
68         r : 0,
69         valueType : 0,
70         valueFormat : '',
71         value : '',
72         colspan: 1,
73         rowspan: 1
74           
75     };
76      
77     this.load();
78     
79    
80     
81     
82 }
83 Roo.extend(Pman.Gnumeric, Roo.util.Observable, {
84     
85     /**
86      * @cfg {String} url the source of the Gnumeric document.
87      */
88     url : false,
89       /**
90      * @cfg {Object} data overlay data for spreadsheet - from constructor.
91      */
92     data : false,
93      /**
94      * @cfg {String} downloadURL where GnumerictoExcel.php is...
95      */
96      
97     downloadURL : false,
98     
99     /**
100      * @type {XmlDocument} doc the gnumeric xml document
101      */
102     doc : false,
103     
104     /**
105      * @type {XmlNode} sheet the 'Sheet' element 
106      */
107     sheet : false,
108     
109     /**
110      * @type {XmlNode} sheet the 'Cells' element 
111      */    
112     cellholder : false,
113     /**
114      * @type {Object} grid the map[row][col] = cellData 
115      */
116     grid : false,
117     /**
118      * @type {Object} colInfo - list of column sizes
119      */
120     colInfo : false,
121     /**
122      * @type {Object} colInfoDom - column sizes dom element
123      */
124     colInfoDom : false,
125     /**
126      * @type {Object} rowInfo - list of row sizes
127      */
128     rowInfo : false,
129      /**
130      * @type {Object} rowInfoDom - dom elements with sizes
131      */
132     rowInfoDom : false,
133     /**
134      * @type {Number} cmax - maximum number of columns
135      */
136     cmax: false,
137     /**
138      * @type {Object} rmax - maximum number of rows
139      */
140     rmax : false,
141        /**
142      * @type {String} stylesheetID id of stylesheet created to render spreadsheat
143      */
144     stylesheetID : false,
145     /**
146      * @type {Number} rowOffset - used by table importer to enable multiple tables to be improted
147      */
148     
149     rowOffset : 0,
150     
151     /**
152      * load:
153      * run the connection, parse document and fire load event..
154      * can be run multiple times with new data..
155      * 
156     */
157     
158     load : function(url)
159     {
160         this.url = url || this.url;
161         if (!this.url) {
162             return;
163         }
164         // reset stufff..
165         this.doc = false;
166         this.sheet = false;
167         this.grid = false;
168         this.colInfo = false;
169         this.colInfoDom = false;
170         this.rowInfo = false;
171         this.rowInfoDom = false;
172         this.cmax = false;
173         this.rmax = false;
174         
175         if (this.stylesheetID) {
176             
177             Roo.util.CSS.removeStyleSheet(this.stylesheetID);
178             this.stylesheetID = false;
179             
180         }
181         
182         _t = this;
183         var c = new Roo.data.Connection();
184         c.request({
185             url: this.url,
186             method:  'GET',
187             success : function(resp, opts) {
188                 _t.response = resp;
189                 _t.doc = resp.responseXML;
190                 
191                 _t.parseDoc(0);
192                 
193                 
194                 _t.applyData();
195     
196                 _t.fireEvent('load', _t);
197             },
198             failure : function()
199             {
200                 Roo.MessageBox.alert("Error", "Failed to Load Template for Spreadsheet");
201             }
202         });
203         
204
205     },
206     
207     
208      
209     RCtoCell : function(r,c)
210     {
211         // we wil only support AA not AAA
212         var top = Math.floor(c/26);
213         var bot = c % 26;
214         var cc = top > 0 ? String.fromCharCode('A'.charCodeAt(0) + top) : '';
215         cc += String.fromCharCode('A'.charCodeAt(0)  + bot);
216         return cc+'' +r;
217         
218     },
219     
220     /**
221      * toRC:
222      * convert 'A1' style position to row/column reference
223      * 
224      * @arg {String} k cell name
225      * @return {Object}  as { r: {Number} , c: {Number}  }
226      */
227     
228     toRC : function(k)
229     {
230         var c = k.charCodeAt(0)-64;
231         var n = k.substring(1);
232         if (k.charCodeAt(1) > 64) {
233             c *=26;
234             c+=k.charCodeAt(1)-64;
235             n = k.substring(2);
236         }
237         return { c:c -1 ,r: (n*1)-1 }
238     },
239       /**
240      * rangeToRC:
241      * convert 'A1:B1' style position to array of row/column references
242      * 
243      * @arg {String} k cell range
244      * @return {Array}  as [ { r: {Number} , c: {Number}  }. { r: {Number} , c: {Number}  } ]
245      */
246     rangeToRC : function(s) {
247         var ar = s.split(':');
248         return [ this.toRC(ar[0]) , this.toRC(ar[1])]
249     },
250     
251     
252     
253    
254     
255     /**
256      * parseDoc:
257      * convert XML document into cells and other data..
258      * 
259      */
260     parseDoc : function(sheetnum) 
261     {
262         var _t = this;
263         this.grid = {}
264         this.rmax = 1;
265         this.cmax = 1;
266         
267         this.sheet = _t.doc.getElementsByTagNameNS('*','Sheet')[sheetnum];
268         
269         
270         this.cellholder = this.sheet.getElementsByTagNameNS('*','Cells')[0];
271         var cells = this.sheet.getElementsByTagNameNS('*','Cell');
272
273         
274         
275         Roo.each(cells, function(c) {
276            // Roo.log(c);
277             var row = c.getAttribute('Row') * 1;
278             var col = c.getAttribute('Col') * 1;
279             _t.cmax = Math.max(col+1, _t.cmax);
280             _t.rmax = Math.max(row+1, _t.rmax);
281             var vt = c.getAttribute('ValueType');
282             var vf = c.getAttribute('ValueFormat');
283             var val = c.textContent;
284             
285             if (typeof(_t.grid[row]) == 'undefined') {
286                 _t.grid[row] ={};
287             }
288             _t.grid[row][col] = Roo.applyIf({
289                 valueType : vt,
290                 valueFormat : vf,
291                 value : val,
292                 dom: c,
293                 r: row,
294                 c: col
295             }, _t.defaultCell);
296         });
297        
298         for (var r = 0; r < this.rmax;r++) {
299             if (typeof(this.grid[r]) == 'undefined') {
300               this.grid[r] ={};
301             }
302             for (var c = 0; c < this.cmax;c++) {
303                 if (typeof(this.grid[r][c]) == 'undefined') {
304                     continue;
305                 }
306                 //this.print( "[" + r + "]["+c+"]=" + grid[r][c].value +'<br/>');
307             }
308         }
309         
310         var merge = this.sheet.getElementsByTagNameNS('*','Merge');
311
312         Roo.each(merge, function(c) {
313             var rc = _t.rangeToRC(c.textContent);
314             //Roo.log(JSON.stringify(rc));
315             if (typeof(_t.grid[rc[0].r][rc[0].c]) == 'undefined') {
316                 //Roo.log(["creating empty cell for  ",rc[0].r,  rc[0].c ]);
317                  _t.createCell(rc[0].r,  rc[0].c );
318                 //_t.grid[rc[0].r][rc[0].c] =  //Roo.applyIf({ r : rc[0].r, c : rc[0].c }, _t.defaultCell);
319             }
320                 
321             _t.grid[rc[0].r][rc[0].c].colspan = (rc[1].c - rc[0].c) + 1;
322             _t.grid[rc[0].r][rc[0].c].rowspan = (rc[1].r - rc[0].r) + 1;
323             for(var r = (rc[0].r); r < (rc[1].r+1); r++) {
324                for(var cc = rc[0].c; cc < (rc[1].c+1); cc++) {
325                     //Roo.log('adding alias : ' + r+','+c);
326                    _t.grid[r][cc] = _t.grid[rc[0].r][rc[0].c];
327                }
328            }
329             
330         });
331         // read colinfo..
332         var ci = this.sheet.getElementsByTagNameNS('*','ColInfo');
333         this.colInfo = {};
334         this.colInfoDom = {};
335         
336         Roo.each(ci, function(c) {
337             var count = c.getAttribute('Count') || 1;
338             var s =  c.getAttribute('No')*1;
339             for(var i =0; i < count; i++) {
340                 _t.colInfo[s+i] = Math.floor(c.getAttribute('Unit')*1);
341                 _t.colInfoDom[s+i] = c;
342             }
343         });
344         
345         
346         ci = this.sheet.getElementsByTagNameNS('*','RowInfo');
347         
348         this.rowInfo = {};
349         this.rowInfoDom = {};
350         Roo.each(ci, function(c) {
351             var count = c.getAttribute('Count') || 1;
352             var s =  c.getAttribute('No')*1;
353             for(var i =0; i < count; i++) {
354                 _t.rowInfoDom[s+i] = c;
355                 _t.rowInfo[s+i] = Math.floor(c.getAttribute('Unit')*1);
356             }
357         });
358     
359         _t.parseStyles();
360         _t.overlayStyles();
361                 
362         
363      
364         
365     },
366      /**
367      * overlayStyles:
368      * put the style info onto the cell data.
369      * 
370      */
371     overlayStyles : function ()
372     {
373            // apply styles.
374         var _t = this;
375         Roo.each(this.styles, function(s) {
376        
377             for (var r = s.r; r < s.r1;r++) {
378                 if (typeof(_t.grid[r]) == 'undefined') {
379                    continue;
380                 }
381                 for (var c = s.c; c < s.c1;c++) {
382                     if (c > _t.cmax) {
383                         continue;
384                     }
385     
386                     if (typeof(_t.grid[r][c]) == 'undefined') {
387                         _t.createCell(r,c);
388                         //_t.grid[r][c] = Roo.applyIf({ r: r , c : c }, _t.defaultCell);
389                     }
390                     var g=_t.grid[r][c];
391                     if (typeof(g.cls) =='undefined') {
392                         g.cls = [];
393                         g.styles = [];
394                     }
395                     if (g.cls.indexOf(s.name)  > -1) {
396                        continue;
397                     }
398                     g.cls.push(s.name);
399                     g.styles.push(s.dom);
400                     
401                 }
402             }
403         });
404     },
405      /**
406      * parseStyles: 
407      *  read the style information
408      * generates a stylesheet for the current file
409      * this should be disposed of really.....
410      * 
411      */
412     parseStyles : function() {
413                 
414         var srs = this.sheet.getElementsByTagNameNS('*','StyleRegion');
415         var _t  = this;
416         var ent = {};
417         
418         var map =  {
419             HAlign : function(ent,v) { 
420                 ent['text-align'] = { '1' : 'left', '8': 'center', '4' : 'right'}[v] || 'left';
421             },
422             VAlign : function(ent,v) { 
423                 ent['vertical-align'] = { '1' : 'top', '4': 'middle', '8' : 'bottom'}[v]  || 'top'
424             },
425             Fore : function(ent,v) { 
426                 var col=[];
427                 Roo.each(v.split(':'), function(c) { col.push(Math.round(parseInt(c,16)/256)); });
428                 ent['color'] = 'rgb(' + col.join(',') + ')';
429             },
430             Back : function(ent,v) { 
431                 var col=[];
432                 Roo.each(v.split(':'), function(c) { col.push(Math.round(parseInt(c,16)/256)); });
433                 ent['background-color'] = 'rgb(' + col.join(',') + ')';
434             },
435             FontUnit : function(ent,v) { 
436                 ent['font-size'] = v + 'px';
437             },
438             FontBold : function(ent,v) { 
439                 if (v*1 < 1) { return; }
440                 ent['font-weight'] = 'bold';
441             },
442             FontItalic : function(ent,v) { 
443                 if (v*0 < 1) { return; }
444                 //ent['font-weight'] = 'bold';
445             },
446             FontName : function(ent,v) { 
447                 ent['font-family'] = v;
448             },
449             BorderStyle : function(ent,v) { 
450                 var vv  = v.split('-');
451                 ent['border-'+vv[0]+'-style'] = 'solid';
452                 ent['border-'+vv[0]+'-width'] = vv[1]+'px';
453             },
454             BorderColor : function(ent,v) { 
455                 var vv  = v.split('-');
456                 var col=[];
457                 Roo.each(vv[1].split(':'), function(c) { col.push(Math.round(parseInt(c,16)/256)); });
458                 ent['border-'+vv[0]+'-color'] = 'rgb(' + col.join(',') + ')';
459             }
460         };
461         function add(e, k, v) {
462             //Roo.log(k,v);
463             e.gstyle[k] = v;
464             if (typeof(map[k]) == 'undefined') {
465                 return;
466             }
467             map[k](e.style,v);    
468         }
469         var css = {};
470         var styles = [];
471         var sid= Roo.id();
472         
473         
474         Roo.each(srs, function(sr,n)
475         {
476             ent = {
477                 c : sr.getAttribute('startCol') *1,
478                 r : sr.getAttribute('startRow')*1,
479                 c1 : (sr.getAttribute('endCol')*1) +1,
480                 r1 : (sr.getAttribute('endRow')*1) +1,
481                 style : {},  // key val of style for HTML..
482                 gstyle : {}, // key val of attributes used..
483                 name : sid +'-gstyle-' + n,
484                 dom : sr
485                 
486             };
487     
488             Roo.each(sr.getElementsByTagNameNS('*','Style')[0].attributes, function(e) { 
489                 add(ent, e.name, e.value);
490             });
491             if (sr.getElementsByTagNameNS('*','Font').length) {
492                 Roo.each(sr.getElementsByTagNameNS('*','Font')[0].attributes, function(e) { 
493                      add(ent, 'Font'+e.name, e.value);
494     
495                 });
496                 add(ent, 'FontName', sr.getElementsByTagNameNS('*','Font')[0].textContent);
497     
498             }
499             if (sr.getElementsByTagNameNS('*','StyleBorder').length) {
500                 Roo.each(sr.getElementsByTagNameNS('*','StyleBorder')[0].childNodes, function(e) {
501                     if (!e.tagName) {
502                         return;
503                     }
504                     Roo.each(e.attributes, function(ea) { 
505                         add(ent, 'Border'+ea.name, e.tagName.split(':')[1].toLowerCase() + '-' + ea.value);
506                     });
507                 })
508                     
509             }
510             styles.push(ent);
511             css['.'+ent.name] = ent.style;
512         });
513         
514         this.styles = styles;
515         
516         this.stylesheetID = sid;
517         Roo.util.CSS.createStyleSheet(css, sid);
518     },
519
520     
521     
522     
523     /* ---------------------------------------  AFTER LOAD METHODS... ----------------------- */
524     /**
525      * set: 
526      * Set the value of a cell..
527      * @param {String} cell name of cell, eg. C10 or { c: 1, r :1 }
528          
529      * @param {Value} value to put in cell..
530      * @param {ValueType} type of value
531      * @param {ValueFormat} value format of cell
532      * 
533      * Cells should exist at present, we do not make them up...
534      */
535      
536     
537     set : function(cell, v, vt, vf) {
538         
539         var cs= typeof(cell) == 'string' ? this.toRC(cell) : cell;
540         
541         
542         Roo.log( cs.r+ ',' + cs.c + ' = '+ v);
543         // need to generate clell if it doe
544         if (typeof(this.grid[cs.r]) == 'undefined') {
545             Roo.log('no row:' + cell);
546             this.grid[cs.r] = []; // create a row..
547             //return;
548         }
549         if (typeof(this.grid[cs.r][cs.c]) == 'undefined') {
550             Roo.log('cell not defined:' + cell);
551             this.createCell(cs.r,cs.c);
552         }
553         // cell might not be rendered yet... so if we try and create a cell, it overrides the default formating..
554         
555         if (typeof(this.grid[cs.r][cs.c].dom) == 'undefined') {
556             Roo.log('no default content for cell:' + cell);
557             Roo.log(this.grid[cs.r][cs.c]);
558             //this.createCell(cs.r,cs.c);
559             //return;
560         }
561         this.grid[cs.r][cs.c].value=  v;
562         if (this.grid[cs.r][cs.c].dom) {
563             this.grid[cs.r][cs.c].dom.textContent=  v;
564         }
565         
566         
567         if (typeof(vt) != 'undefined') {
568             this.grid[cs.r][cs.c].valueType = vt;
569             this.grid[cs.r][cs.c].dom.setAttribute('ValueType', vt);
570             if (vt === '' || vt === false) { // value type is empty for formula's
571                 this.grid[cs.r][cs.c].dom.removeAttribute('ValueType');
572             }
573         }
574         if (typeof(vf) != 'undefined' && vf !== false) {
575             this.grid[cs.r][cs.c].valueFormat = vf;
576             this.grid[cs.r][cs.c].dom.setAttribute('ValueFormat', vf);
577             if (vf === '' || vf === false) { // value type is empty for formula's
578                 this.grid[cs.r][cs.c].dom.removeAttribute('ValueFormat');
579             }
580         }
581         
582     },
583     
584     // private
585     copyRow : function(src, dest) {
586         if (dest == src) {
587             return;
588         }
589        // Roo.log('create Row' + dest);
590         if (typeof(this.grid[dest]) == 'undefined') {
591             this.grid[dest] = {}
592         }
593         
594            
595         for (var c = 0; c < this.cmax; c++) {
596
597             this.copyCell({ r: src, c: c } , { r: dest, c: c});
598             
599         }
600         this.rmax = Math.max(this.rmax, dest +1);
601         
602     },
603     
604     // private
605     
606     createCell: function(r,c)
607     {
608         //<gnm:Cell Row="6" Col="5" ValueType="60">Updated</gnm:Cell>    
609         var nc = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:Cell');
610         this.cellholder.appendChild(nc);
611         var lb = this.doc.createTextNode("\n");// add a line break..
612         this.cellholder.appendChild(lb);
613         
614         nc.setAttribute('Row', new String(r));
615         nc.setAttribute('Col', new String(c));
616         nc.setAttribute('ValueType', '60');
617         nc.textContent = '';
618         
619         this.grid[r][c] = Roo.applyIf({
620             valueType : '60',
621             valueFormat : '',
622             value : '',
623             dom: nc,
624             r: r,
625             c: c
626             }, _t.defaultCell);
627         
628         return nc;
629
630     },
631     
632     // private
633     copyCell : function(src, dest)
634     {
635         var old = this.grid[src.r][src.c];
636         // is it an alias...
637         if ((old.c != src.c)  || (old.r != src.r)) {
638             // only really works on horizonatal merges..
639             
640             this.grid[dest.r][dest.c] = this.grid[desc.r][old.c]; // let's hope it exists.
641             return;
642         }
643         
644         
645         var nc = Roo.apply({}, this.grid[src.r][src.c]);
646         
647         nc.value = '';
648         if (typeof(old.dom) == 'undefined') {
649             Roo.log("No cell to copy for " + Roo.encode(src));
650             return;
651         }
652         this.grid[dest.r][dest.c] = nc;
653         nc.dom = old.dom.cloneNode(true);
654         nc.dom.setAttribute('Row', dest.r);
655         nc.dom.setAttribute('Cell', dest.c);
656         nc.dom.textContent = '';
657         old.dom.parentNode.appendChild(nc.dom);
658         if (!old.styles || !old.styles.length) {
659             return;
660         }
661         //Roo.log("DEST");
662         //Roo.log(dest);
663         //Roo.log("STYLES");
664         //  .styles...
665         Roo.each(old.styles, function(s) {
666             // try and extend existing styles..
667             var er = s.getAttribute('endRow') * 1;
668             var ec = s.getAttribute('endCol') * 1;
669             //Roo.log(s);
670             if (dest.r == er) {
671                 s.setAttribute('endRow', dest.r + 1);
672             }
673             if (dest.c == ec) {
674                 s.setAttribute('endCol', dest.c + 1);
675             }
676             /*var ns = s.cloneNode(true);
677             s.parentNode.appendChild(ns);
678             ns.setAttribute('startCol', dest.c);
679             ns.setAttribute('startRow', dest.r);
680             ns.setAttribute('endCol', dest.c + 1);
681             ns.setAttribute('endRow', dest.r +1);
682             */
683         });
684         
685     },
686     
687     
688     /**
689      * applyData: 
690      * Set the value of a cell..
691      * @param {String} cell name of cell, eg. C10
692      * @param {Value} value to put in cell..
693      * 
694      * Cells should exist at present, we do not make them up...
695      */
696      
697     applyData : function(data)
698     {
699         
700         data = data || this.data;
701         for (var r = 0; r < this.rmax;r++) {
702             if (typeof(this.grid[r]) == 'undefined') {
703                 continue;
704             }
705             for (var c = 0; c < this.cmax;c++) {  
706                 if (typeof(this.grid[r][c]) == 'undefined') {
707                     continue;
708                 }
709                 if (!this.grid[r][c].value.length 
710                         || !this.grid[r][c].value.match(/\{/)) {
711                     continue;
712                 }
713                 
714                 var x = new Roo.Template({ html: this.grid[r][c].value });
715                 try {
716                     var res = x.applyTemplate(data);
717                     //Roo.log("set " + r  + "," + c + ":"+res)
718                     this.set({ r: r, c: c}, x.applyTemplate(data));
719                 } catch (e) {
720                  //   Roo.log(e.toString());
721                   //  Roo.log(e);
722                     // continue?
723                 }
724                 
725             }
726         }
727             
728     },
729     
730     readTableData : function(table)
731     {
732         // read the first row.
733         var tds = Roo.get(table).select('tr').item(0).select('td');
734         var maxnc = 0;
735         
736         Roo.get(table).select('tr').each(function(trs) {
737             var nc = 0;
738            
739             trs.select('td').each(function(td) {
740                 var cs = td.dom.getAttribute('colspan');
741                 cs = cs ? cs * 1 : 1;
742                 nc += cs;
743             });
744             maxnc = Math.max(nc, maxnc);
745         });
746         
747         var tr = document.createElement('tr');
748         table.appendChild(tr);
749         var ar = {};
750         for (i =0; i < maxnc; i++) {
751             ar[i] = document.createElement('td');
752             tr.appendChild(ar[i]);
753         }
754         // find the left.
755         var ret = { cols : maxnc, pos : {} };
756         for (i =0; i < maxnc; i++) {
757             ret.pos[ Roo.get(ar[i]).getLeft()] =i;
758         }
759         ret.near = function(p) {
760             // which one is nearest..
761             
762             if (this.pos[p]) {
763                 return this.pos[p];
764             }
765             var prox = 100000;
766             var match = 0;
767             for(var i in this.pos) {
768                 var dis = Math.abs(p-i);
769                 if (dis < prox) {
770                     prox = dis;
771                     match = this.pos[i];
772                 }
773             }
774             return match;
775             
776         }
777         table.removeChild(tr);
778         return ret;
779     },
780     
781      
782    
783      
784     /**
785      * importTable: 
786      * Import a table and put it into the spreadsheet
787      * @param {HTMLTable} datagrid dom element of html table.
788      * @param {Number} xoff X offset to start rendering to
789      * @param {Number} yoff Y offset to start rendering to
790      **/
791      
792  
793     importTable : function (datagrid, xoff,yoff)
794     {
795         if (!datagrid) {
796             Roo.log("Error table not found!?");
797             return;
798         }
799         xoff = xoff || 0;
800         yoff = yoff || 0;
801         
802         
803         var table_data = this.readTableData(datagrid);
804         
805         // oroginally this cleaned line breaks, but we acutally need them..
806         var cleanHTML = function (str) {
807             
808             var ret = str;
809             ret = ret.replace(/&nbsp;/g,' ');
810            // ret = ret.replace(/\n/g,'.');
811           //  ret = ret.replace(/\r/g,'.');
812             var i;
813              
814             return ret;
815         };
816
817         
818         // <cell col="A" row="1">Test< / cell>
819         // <cell col="B" row="2" type="Number" format="test1">30< / cell>
820         var rowOffsets = {};
821         var rows = datagrid.getElementsByTagName('tr');
822         //alert(rows.length);
823         
824         
825         for(var row=0;row<rows.length;row++) {
826             
827             // let's see what affect this has..
828             // it might mess things up..
829             
830             if (rows[row].getAttribute('xls:height')) {
831                 this.setRowHeight(row + yoff +1, 1* rows[row].getAttribute('xls:height'));
832             } else {
833                 this.setRowHeight( row + yoff +1, Roo.get(rows[row]).getHeight());
834             }
835             
836             var cols = rows[row].getElementsByTagName('td');
837             
838             for(var col=0;col < cols.length; col++) {
839                 
840                 if (cols[col].getAttribute('xls:width')) {
841                     this.setColumnWidth(col, 1 * cols[col].getAttribute('xls:width'));
842                 }
843                 
844                 var colspan = cols[col].getAttribute('colspan');
845                 colspan  = colspan ? colspan *1 : 1;
846                 
847                 var rowspan = cols[col].getAttribute('rowspan');
848                 rowspan = rowspan ? rowspan * 1 : 1;
849                 
850                 var realcol = table_data.near( Roo.get(cols[col]).getLeft() );
851                 
852                 
853                 
854                 if (colspan > 1 || rowspan > 1) {
855                     
856                     // getting thisese right is tricky..
857                     this.mergeRegion(
858                         realcol + xoff,
859                         row + yoff +1,
860                         realcol+ xoff + (colspan -1),
861                         row + yoff + rowspan 
862                     );
863                     
864                 }
865                 
866                 // skip blank cells
867                 // set the style first..
868                 this.parseHtmlStyle( cols[col], row + yoff, realcol + xoff   , colspan, rowspan);
869                 
870                 if (!cols[col].childNodes.length) {
871                      
872                     continue;
873                 }
874                 
875                 
876                 
877                 
878                 var vt = '60';
879                 var vf = false;
880                 var xlstype = cols[col].getAttribute('xls:type');
881                 switch(xlstype) {
882                     case 'int':
883                         vt = 30; // int!!!!
884                     
885                         break;
886                         
887                     case 'float':
888                         vt = 40; // float!!!!
889                         if (cols[col].getAttribute('xls:floatformat')) {
890                             vf = cols[col].getAttribute('xls:floatformat');
891                         }
892                         break;
893                         
894                     case 'date':
895                         vt = 30;
896                         //ValueFormat="d/m/yyyy" 38635  
897                         var vf = 'd/m/yyy';
898                         if (cols[col].getAttribute('xls:dateformat')) {
899                             vf= cols[col].getAttribute('xls:dateformat');
900                         }
901                         
902                        
903                         
904                         break;
905                     
906                     default:
907                        
908                         break;
909                 }
910                
911                 if (!cols[col].childNodes[0].nodeValue) {
912                    
913                     continue;
914                 }
915                 if (!cols[col].childNodes[0].nodeValue.replace(/^\s*|\s*$/g,"").length) {
916                   
917                     continue;
918                 }
919                 // strip me.!
920                 var cell_value_text = cleanHTML(cols[col].childNodes[0].nodeValue);
921        
922                 if (cols[col].getAttribute('xls:percent')) {
923                     cell_value_text = '' + ((cell_value_text * 1) / 100);
924                 }
925
926                 if (cell_value_text.length && (vt == 30) && xlstype == 'date') {
927                     var bits = cell_value_text.split(/-/);
928                     var cur = new Date(bits[0],bits[1]-1,bits[2]);
929                     cell_value_text = '' + Math.round((cur.getTime() - Date.UTC(1899,11,30)) / (24 * 60 * 60 * 1000));
930                 }
931
932                 
933                 
934                 if (cols[col].getAttribute('xls:formula')) {
935                     var s = cols[col].getAttribute('xls:formula');
936                     vt = '';
937                     cell_value_text = s.replace(/#row#/g,(row + yoff + 1));
938                 }
939                 this.set({ r: row + yoff, c : realcol + xoff }, cell_value_text, vt, vf);
940                  
941                   
942                 
943                 
944                 
945             }
946         }
947         this.rowOffset += rows.length;
948         
949     },
950     
951     
952     
953     parseHtmlStyle : function(dom, row, col, colspan, rowspan) {
954         
955         function toCol (rgb) {
956             
957             var ar = rgb.replace(/rgb[a]?\(/, '').replace(/\)/, '').replace(/ /, '').split(',');
958             var rcs = [];
959             ar = ar.slice(0,3);
960             Roo.each(ar, function(c) { 
961                 rcs.push((c*c).toString(16)) ;   
962             });
963             return rcs.join(':');
964             
965         }
966         
967         var el = Roo.get(dom);
968         var map =  {
969             'text-align'  : function(ent,v) { 
970                 ent['HAlign'] = { 'left' : '1', 'center' : '8' ,  'right' : '4' }[v] || '1';
971             },
972             'vertical-align': function(ent,v) { 
973                 ent['VAlign'] = { 'top' : '1', 'middel' : '8' ,  'bottom' : '4' }[v] || '1';
974             },
975             
976             'color': function(ent,v) { 
977                 ent['Fore'] = toCol(v);
978                 // this is a bit dumb.. we assume that if it's not black text, then it's shaded..
979                 if (ent['Fore'] != '0:0:0') {
980                     ent['Shade'] = 1;
981                 }
982                 
983             },
984             'background-color' : function(ent,v) { 
985                 ent['Back'] = toCol(v);
986                  
987             }
988             
989         };
990        
991         var ent = {
992                 HAlign:"1",
993                 VAlign:"2",
994                 WrapText:"0",
995                 ShrinkToFit:"0",
996                 Rotation:"0",
997                 Shade:"0",
998                 Indent:"0",
999                 Locked:"0",
1000                 Hidden:"0",
1001                 Fore:"0:0:0",
1002                 Back:"FFFF:FFFF:FFFF",
1003                 PatternColor:"0:0:0",
1004                 Format:"General"
1005         };
1006            
1007         for(var k in map) {
1008             var val = el.getStyle(k);
1009             if (!val || !val.length) {
1010                continue;
1011             }
1012             map[k](ent,val);
1013         }
1014         // special flags..
1015         if (el.dom.getAttribute('xls:wraptext')) {
1016             ent.WrapText = 1;
1017         }
1018         if (el.dom.getAttribute('xls:valign')) {
1019             ent.VAlign= 1;
1020         }
1021         if (el.dom.getAttribute('xls:halign')) {
1022             ent.HAlign= 1;
1023         }
1024         // fonts..
1025         var fmap = {
1026             
1027            
1028             'font-size' : function(ent,v) { 
1029                 ent['Unit'] = v.replace(/px/, '');
1030             },
1031             'font-weight' : function(ent,v) { 
1032                 if (v != 'bold') {
1033                    return;
1034                 }
1035                 ent['Bold'] = 1;
1036             },
1037             'font-style' : function(ent,v) { 
1038                 if (v != 'italic') {
1039                     return;
1040                 }
1041                 ent['Italic'] = 1;
1042             } 
1043         };
1044        
1045         var fent = {
1046             Unit:"10",
1047             Bold:"0",
1048             Italic:"0",
1049             Underline:"0",
1050             StrikeThrough:"0"
1051         };
1052         
1053         for(var k in fmap) {
1054             var val = el.getStyle(k);
1055             if (!val || !val.length) {
1056                continue;
1057             }
1058             fmap[k](fent,val);
1059         }
1060         var font = el.getStyle('font-family') || 'Sans';
1061         if (font.split(',').length > 1) {
1062             font = font.split(',')[1].replace(/\s+/, '');
1063         }
1064         
1065         
1066         /// -- now create elements..
1067         
1068         var objs = this.sheet.getElementsByTagNameNS('*','Styles')[0];
1069         
1070         //<gnm:StyleRegion startCol="0" startRow="0" endCol="255" endRow="65535"
1071         var sr = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:StyleRegion');
1072         objs.appendChild(sr);
1073         objs.appendChild(this.doc.createTextNode("\n"));// add a line break..
1074
1075         sr.setAttribute('startCol', col);
1076         sr.setAttribute('endCol', col+ colspan-1);
1077         sr.setAttribute('startRow', row);
1078         sr.setAttribute('endRow', row + rowspan -1);
1079         
1080         
1081         var st = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:Style');
1082         sr.appendChild(st);
1083         // do we need some defaults..
1084         for(var k in ent) {
1085             //Roo.log(k);
1086             st.setAttribute(k, ent[k]);
1087         }
1088         
1089         var fo = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:Font');
1090         st.appendChild(fo);
1091         // do we need some defaults..
1092         for(var k in fent) {
1093             fo.setAttribute(k, fent[k]);
1094         }
1095         fo.textContent  = font;
1096         
1097         var sb = false;
1098         // borders..
1099         Roo.each(['top','left','bottom','right'], function(p) {
1100             var w = el.getStyle('border-' + p + '-width').replace(/px/, '');
1101             if (!w || !w.length || (w*1) < 1) {
1102                 return;
1103             }
1104             if (!sb) {
1105                 sb= this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:StyleBorder');
1106             }
1107             var be = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:' + p[0].toUpperCase() + p.substring(1));
1108             be.setAttribute('Style', '1');
1109             be.setAttribute('Color', '0:0:0'); // fixme..
1110             sb.appendChild(be);
1111             
1112         }, this);
1113         // start adding them all together..
1114         
1115         if (sb) {
1116             st.appendChild(sb);
1117         }
1118         
1119         
1120         
1121         
1122     },
1123     
1124     /**
1125      * writeImageOld:
1126      * write an image in old gnumberic format (needs base64 data to write it)
1127      * 
1128      * 
1129      * @param {Number} row  row to put it in (rows start at 0)
1130      * @param {Number} col  column to put it in
1131      * @param {Number} data  the base64 description of the images
1132      * @param {Number} width image width
1133      * @param {Number} width image height
1134      * 
1135      */
1136     writeImageOld : function (row, col, data, width, height, type, size) 
1137     {
1138         
1139         if (!data) {
1140             throw "write Image called with missing data";
1141         }
1142         
1143         row*=1;
1144         col*=1;
1145         height*=1;
1146         width*=1;
1147         var objs = this.sheet.getElementsByTagNameNS('*','Objects')[0];
1148         var soi = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:SheetObjectImage');
1149         
1150         var colwidth = 0;
1151         var endcol=col;
1152         for ( endcol=col;endcol <100; endcol++) {
1153             if (!this.colInfo[endcol]) {
1154                 this.colInfo[endcol] = 100; // eak fudge
1155             }
1156             colwidth += this.colInfo[endcol];
1157             if (colwidth > width) {
1158                 break;
1159             }
1160         }
1161         
1162         soi.setAttribute('ObjectBound', this.RCtoCell(row,col) + ':' + this.RCtoCell(row,endcol));
1163      
1164         var ww = 0.01; // offset a bit...
1165         var hh = 0.01; //
1166         
1167         var ww2 = 1 - ((colwidth - width) / this.colInfo[endcol]);
1168         var hh2 = 0.99;
1169         
1170         var offset_str = ww + ' '  + hh + ' ' + ww2 + ' '+hh2;
1171         
1172         //alert(offset_str);
1173         soi.setAttribute('ObjectOffset', offset_str);
1174         soi.setAttribute('ObjectAnchorType','16 16 16 16');
1175         soi.setAttribute('Direction','17');
1176         soi.setAttribute('crop-top','0.000000');
1177         soi.setAttribute('crop-bottom','0.000000');
1178         soi.setAttribute('crop-left','0.000000');
1179         soi.setAttribute('crop-right','0.000000');
1180         
1181         var content = this.doc.createElement('Content');
1182         content.setAttribute('image-type', type ? type : 'jpeg');
1183         content.setAttribute('size-bytes', size);
1184         soi.appendChild(content);
1185         objs.appendChild(soi);
1186         
1187         if (typeof(this.grid[row]) == 'undefined') {
1188             this.grid[row] = [];
1189         }
1190         if (typeof(this.grid[row][col]) == 'undefined') {
1191             this.createCell(row,col);
1192         }
1193         
1194         this.grid[row][col].value=  data;
1195         this.grid[row][col].valueFormat = 'image';
1196         this.grid[row][col].imageType = type;
1197         this.grid[row][col].width = width;
1198         this.grid[row][col].height = height;
1199         
1200         var godoc = this.doc.getElementsByTagNameNS('*','GODoc')[0];
1201         
1202         if(godoc && godoc.parentNode) {
1203             godoc.parentNode.removeChild(godoc);
1204         }
1205         
1206         return true;
1207     },
1208     
1209     /**
1210      * writeImage:
1211      * write an image (needs base64 data to write it)
1212      * 
1213      * 
1214      * @param {Number} row  row to put it in (rows start at 0)
1215      * @param {Number} col  column to put it in
1216      * @param {Number} data  the base64 description of the images
1217      * @param {Number} width image width
1218      * @param {Number} width image height
1219      * 
1220      */
1221     writeImage : function (row, col, data, width, height, type) 
1222     {
1223         
1224         if (!data) {
1225             throw "write Image called with missing data";
1226         }
1227         // our default height width is 50/50 ?!
1228         //console.log('w='+width+',height='+height);
1229                 //        <gmr:Objects>
1230         row*=1;
1231         col*=1;
1232         height*=1;
1233         width*=1;
1234         var objs = this.sheet.getElementsByTagNameNS('*','Objects')[0];
1235         var soi = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:SheetObjectImage');
1236         
1237         //<gmr:SheetObjectImage 
1238         //      ObjectBound="A3:J8" 
1239         //      ObjectOffset="0.375 0.882 0.391 0.294" 
1240         //      ObjectAnchorType="16 16 16 16" 
1241         //      Direction="17" 
1242         //      crop-top="0.000000" 
1243         //      crop-bottom="0.000000" 
1244         //      crop-left="0.000000" 
1245         //      crop-right="0.000000">
1246                 
1247                 
1248         //alert(gnumeric_colRowToName(row,col));
1249                
1250         // this is where we really have fun!!!... 
1251         // since our design currently assumes the height is enough to fit
1252         // stuff in, we only really need to work out how wide it has to be..
1253         
1254         // note we should probably use centralized calcs if it fits in the first cell!
1255         
1256         // step 1 - work out how many columns it will span..
1257         // lets hope the spreadsheet is big enought..
1258         var colwidth = 0;
1259         var endcol=col;
1260         for ( endcol=col;endcol <100; endcol++) {
1261             if (!this.colInfo[endcol]) {
1262                 this.colInfo[endcol] = 100; // eak fudge
1263             }
1264             colwidth += this.colInfo[endcol];
1265             if (colwidth > width) {
1266                 break;
1267             }
1268         }
1269         
1270         soi.setAttribute('ObjectBound',
1271             //gnumeric_colRowToName(row,col) + ':' + gnumeric_colRowToName(row+1,col+1));
1272             this.RCtoCell(row,col) + ':' + this.RCtoCell(row,endcol));
1273      
1274         var ww = 0.01; // offset a bit...
1275         var hh = 0.01; //
1276         
1277         var ww2 = 1 - ((colwidth - width) / this.colInfo[endcol]);
1278         var hh2 = 0.99;
1279         
1280         var offset_str = ww + ' '  + hh + ' ' + ww2 + ' '+hh2;
1281         
1282         //alert(offset_str);
1283         soi.setAttribute('ObjectOffset', offset_str);
1284         soi.setAttribute('ObjectAnchorType','16 16 16 16');
1285         soi.setAttribute('Direction','17');
1286         soi.setAttribute('crop-top','0.000000');
1287         soi.setAttribute('crop-bottom','0.000000');
1288         soi.setAttribute('crop-left','0.000000');
1289         soi.setAttribute('crop-right','0.000000');
1290                 // <Content image-type="jpeg" size-bytes="3900">......  < / Content>
1291                 
1292         var name = 'Image' + Math.random().toString(36).substring(2);
1293         var content = this.doc.createElement('Content');
1294         content.setAttribute('image-type', type ? type : 'jpeg');
1295         content.setAttribute('name', name);
1296         soi.appendChild(content);
1297         objs.appendChild(soi);
1298         
1299         var godoc = this.doc.getElementsByTagNameNS('*','GODoc')[0];
1300         
1301         var goimage = this.doc.createElement('GOImage');
1302         goimage.setAttribute('image-type', type ? type : 'jpeg');
1303         goimage.setAttribute('name', name);
1304         goimage.setAttribute('type', 'GOPixbuf');
1305         goimage.setAttribute('width', width);
1306         goimage.setAttribute('height', height);
1307         goimage.textContent = data;
1308         
1309         godoc.appendChild(goimage);
1310         
1311         if (typeof(this.grid[row]) == 'undefined') {
1312             this.grid[row] = [];
1313         }
1314         if (typeof(this.grid[row][col]) == 'undefined') {
1315             this.createCell(row,col);
1316         }
1317         
1318         this.grid[row][col].value=  data;
1319         this.grid[row][col].valueFormat = 'image';
1320         this.grid[row][col].imageType = type;
1321         this.grid[row][col].width = width;
1322         this.grid[row][col].height = height;
1323         
1324         return true;
1325                 //< /gnm:SheetObjectImage>
1326                 // < /gnm:Objects>
1327
1328     },
1329     
1330     /**
1331      * writeFixedImageOld:
1332      * write an image in old gnumberic format (needs base64 data to write it)
1333      */
1334     writeFixedImageOld : function (startCol, startRow, endCol, endRow, type, data, width, height, size) 
1335     {
1336         if (!data) {
1337             throw "write Image called with missing data";
1338         }
1339         
1340         startCol = startCol * 1;
1341         startRow = startRow * 1;
1342         endCol = endCol * 1;
1343         endRow = endRow * 1;
1344         width = width * 1;
1345         height = height * 1;
1346         
1347         var objs = this.sheet.getElementsByTagNameNS('*','Objects')[0];
1348         var soi = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:SheetObjectImage');
1349         
1350         soi.setAttribute('ObjectBound',this.RCtoCell(startRow, startCol) + ':' + this.RCtoCell(endRow, endCol));
1351         
1352         soi.setAttribute('ObjectOffset', '0 0 0 0');
1353         soi.setAttribute('ObjectAnchorType','16 16 16 16');
1354         soi.setAttribute('Direction','17');
1355         soi.setAttribute('crop-top','0.000000');
1356         soi.setAttribute('crop-bottom','0.000000');
1357         soi.setAttribute('crop-left','0.000000');
1358         soi.setAttribute('crop-right','0.000000');
1359         
1360         var content = this.doc.createElement('Content');
1361         content.setAttribute('image-type', type ? type : 'jpeg');
1362         content.setAttribute('size-bytes', size);
1363         content.textContent = data;
1364         soi.appendChild(content);
1365         objs.appendChild(soi);
1366         
1367         if (typeof(this.grid[startRow]) == 'undefined') {
1368             this.grid[startRow] = [];
1369         }
1370         if (typeof(this.grid[startRow][startCol]) == 'undefined') {
1371             this.createCell(startRow,startCol);
1372         }
1373         
1374         this.grid[startRow][startCol].value=  data;
1375         this.grid[startRow][startCol].valueFormat = 'image';
1376         this.grid[startRow][startCol].imageType = type;
1377         this.grid[startRow][startCol].width = width;
1378         this.grid[startRow][startCol].height = height;
1379         
1380         var godoc = this.doc.getElementsByTagNameNS('*','GODoc')[0];
1381         
1382         if(godoc && godoc.parentNode) {
1383             godoc.parentNode.removeChild(godoc);
1384         }
1385         
1386         return true;
1387     },
1388     
1389     writeFixedImage : function (startCol, startRow, endCol, endRow, type, data, width, height) 
1390     {
1391         if (!data) {
1392             throw "write Image called with missing data";
1393         }
1394         
1395         startCol = startCol * 1;
1396         startRow = startRow * 1;
1397         endCol = endCol * 1;
1398         endRow = endRow * 1;
1399         width = width * 1;
1400         height = height * 1;
1401         
1402         var objs = this.sheet.getElementsByTagNameNS('*','Objects')[0];
1403         var soi = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:SheetObjectImage');
1404         
1405         soi.setAttribute('ObjectBound',this.RCtoCell(startRow, startCol) + ':' + this.RCtoCell(endRow, endCol));
1406         
1407         soi.setAttribute('ObjectOffset', '0 0 0 0');
1408         soi.setAttribute('ObjectAnchorType','16 16 16 16');
1409         soi.setAttribute('Direction','17');
1410         soi.setAttribute('crop-top','0.000000');
1411         soi.setAttribute('crop-bottom','0.000000');
1412         soi.setAttribute('crop-left','0.000000');
1413         soi.setAttribute('crop-right','0.000000');
1414         
1415         var name = 'Image' + Math.random().toString(36).substring(2);
1416         var content = this.doc.createElement('Content');
1417         content.setAttribute('image-type', type ? type : 'jpeg');
1418         content.setAttribute('name', name);
1419         soi.appendChild(content);
1420         objs.appendChild(soi);
1421         
1422         var godoc = this.doc.getElementsByTagNameNS('*','GODoc')[0];
1423         
1424         var goimage = this.doc.createElement('GOImage');
1425         goimage.setAttribute('image-type', type ? type : 'jpeg');
1426         goimage.setAttribute('name', name);
1427         goimage.setAttribute('type', 'GOPixbuf');
1428         goimage.setAttribute('width', width);
1429         goimage.setAttribute('height', height);
1430         goimage.textContent = data;
1431         
1432         godoc.appendChild(goimage);
1433         
1434         if (typeof(this.grid[startRow]) == 'undefined') {
1435             this.grid[startRow] = [];
1436         }
1437         if (typeof(this.grid[startRow][startCol]) == 'undefined') {
1438             this.createCell(startRow,startCol);
1439         }
1440         
1441         this.grid[startRow][startCol].value=  data;
1442         this.grid[startRow][startCol].valueFormat = 'image';
1443         this.grid[startRow][startCol].imageType = type;
1444         this.grid[startRow][startCol].width = width;
1445         this.grid[startRow][startCol].height = height;
1446         
1447         return true;
1448     },
1449  
1450     /**
1451      * mergeRegion:
1452      * Merge cells in the spreadsheet. (does not check if existing merges exist..)
1453      * 
1454      * @param {Number} col1  first column 
1455      * @param {Number} row1  first row
1456      * @param {Number} col2  to column 
1457      * @param {Number} row2  to row
1458      * 
1459      */
1460     mergeRegion : function (col1,row1,col2,row2)
1461     {
1462         var cell = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:Merge');
1463         //if (col1 > 50|| col2 > 50) { // do not merge cols off to right?
1464        //     return;
1465         //}
1466         
1467         cell.textContent = this.RCtoCell(row1,col1) + ':' + this.RCtoCell(row2,col2);
1468         
1469         //var merges = this.gnumeric.getElementsByTagNameNS('*','MergedRegions');
1470         var merges = this.sheet.getElementsByTagNameNS('*','MergedRegions');
1471         if (!merges || !merges.length) {
1472             merges = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd','gnm:MergedRegions');
1473             var sl = this.sheet.getElementsByTagNameNS('*','SheetLayout')[0];
1474             this.sheet.insertBefore(merges,sl);
1475         } else {
1476             merges = merges[0];
1477         }
1478         merges.appendChild(cell);
1479     
1480     },
1481     /**
1482      * setRowHeight:
1483      * Sets the height of a row.
1484      * 
1485      * @param {Number} r  the row to set the height of. (rows start at 0)
1486      * @param {Number} height (in pixels)
1487      */
1488     setRowHeight : function (r,height)
1489     {
1490         
1491         //<gmr:Rows DefaultSizePts="12.75">
1492         //   <gmr:RowInfo No="2" Unit="38.25" MarginA="0" MarginB="0" HardSize="1"/>
1493     //  < /gmr:Rows>
1494         
1495         // this doesnt handle row ranges very well.. - with 'count in them..'
1496         
1497         if (this.rowInfoDom[r]) {
1498             this.rowInfoDom[r].setAttribute('Unit', height);
1499             return;
1500         }
1501     
1502         var rows = this.sheet.getElementsByTagNameNS('*','Rows')[0]; // assume this exists..
1503         var ri = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd','gnm:RowInfo');
1504         // assume we have no rows..
1505         ri.setAttribute('No', r-1);
1506         ri.setAttribute('Unit', height);
1507         ri.setAttribute('MarginA', 0);
1508         ri.setAttribute('MarginB', 0);
1509         ri.setAttribute('HardSize', 1);
1510         rows.appendChild(ri);
1511         this.rowInfoDom[r] = ri;
1512     },
1513      
1514     /**
1515      * setSheetName: 
1516      * Set the sheet name.
1517      * @param {String} title for sheet
1518      **/
1519     setSheetName : function(name,sheet)
1520     {
1521         sheet = sheet || 0;
1522         /*
1523         <gnm:SheetNameIndex>
1524         <gnm:SheetName>Sheet1</gnm:SheetName>
1525         <gnm:SheetName>Sheet2</gnm:SheetName>
1526         <gnm:SheetName>Sheet3</gnm:SheetName>
1527         </gnm:SheetNameIndex>
1528         */
1529         // has to set sheet name on index and body..
1530         Roo.log(sheet);
1531         Roo.log(name);
1532         var sheetnames = this.doc.getElementsByTagNameNS('*','SheetName');
1533         if (sheet >=  sheetnames.length) {
1534             
1535             sheetnames[0].parentNode.appendChild(sheetnames[sheetnames.length-1].cloneNode(true));
1536             // copy body.
1537             sheetnames = this.doc.getElementsByTagNameNS('*','Sheet');
1538             sheetnames[0].parentNode.appendChild(sheetnames[sheetnames.length-1].cloneNode(true));
1539             var sn = this.doc.getElementsByTagNameNS('*','Sheet')[sheet];
1540             var cls = sn.getElementsByTagNameNS('*','Cells')[0];
1541             while (cls.childNodes.length) {
1542                 cls.removeChild(cls.firstChild);
1543             }
1544             
1545         }
1546         
1547         var sheetn = this.doc.getElementsByTagNameNS('*','SheetName')[sheet];
1548         sheetn.textContent = name;
1549         var sheetb = this.doc.getElementsByTagNameNS('*','Sheet')[sheet].getElementsByTagNameNS('*','Name')[0];
1550         sheetb.textContent = name;
1551         this.parseDoc(sheet);
1552         
1553         
1554         
1555         
1556     },
1557      /**
1558      * setColumnWidth: 
1559      * Set the column width
1560      * @param {Number} column number (starts at '0')
1561      * @param {Number} width size of column
1562      **/
1563     setColumnWidth : function(column, width)
1564     {
1565         column = column *1; 
1566         width= width*1;
1567         if (typeof(this.colInfoDom[column]) == 'undefined') {
1568             var cols = this.sheet.getElementsByTagNameNS('*','Cols')[0];
1569             var ri = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:ColInfo');
1570             ri.setAttribute('No', column);
1571             ri.setAttribute('Unit', width);
1572             ri.setAttribute('MarginA', 2);
1573             ri.setAttribute('MarginB', 2);
1574             ri.setAttribute('HardSize', 1);
1575             cols.appendChild(ri);
1576             this.colInfo[column] = width;
1577             this.colInfoDom[column]  = ri;
1578             return;
1579         }
1580         this.colInfoDom[column].setAttribute('Unit', width);
1581         
1582     },
1583     
1584     
1585     
1586     
1587     
1588      /**
1589      * toHTML: 
1590      * Convert spreadsheet into a HTML table.
1591      */
1592             
1593     toHTML :function()
1594     {
1595          var _t = this;
1596         function calcWidth(sc, span)
1597         {
1598             var n =0;
1599             for(var i =sc; i< sc+span;i++) {
1600                 n+=_t.colInfo[i];
1601             }   
1602             return n;
1603         }
1604         
1605         var grid = this.grid;
1606         // lets do a basic dump..
1607         var out = '<table style="table-layout:fixed;" cellpadding="0" cellspacing="0">';
1608         for (var r = 0; r < this.rmax;r++) {
1609             out += '<tr style="height:'+this.rowInfo[r]+'px;">';
1610             for (var c = 0; c < this.cmax;c++) {
1611                 if (typeof(grid[r][c]) == 'undefined')  {
1612                     this.createCell(r,c);
1613                     
1614                 }
1615                 var g = grid[r][c];
1616                 
1617                 if (typeof(g.cls) =='undefined') {
1618                     g.cls = [];
1619                 }
1620                 var w= calcWidth(c,g.colspan);
1621                 
1622                 var value = g.value[0] == '=' ? 'CALCULATED' : g.value;
1623                 
1624                 try {
1625                     if(
1626                         g.styles[0].firstElementChild.getAttribute('Format') == "D\\-MMM\\-YYYY;@" &&
1627                         g.value[0] != '=' &&
1628                         !isNaN(value * 1) && 
1629                         value != 0
1630                     ){
1631                         value = new Date(value * 24 * 60 * 60 * 1000 + new Date('1899-12-30').getTime()).format('d-M-Y');
1632                     }
1633                     
1634                 } catch(e) {
1635                     
1636                 }
1637                 
1638                 if(g.valueFormat == 'image') {
1639                 
1640                     out+=String.format('<td colspan="{0}" rowspan="{1}"  class="{2}"><div style="{3}"><img src="data:image/{4};base64, {5}" width="{6}" height="{7}"></div></td>', 
1641                         g.colspan, g.rowspan, g.cls.join(' '),
1642                         'overflow:hidden;' + 
1643                         'width:'+g.width+'px;' +
1644
1645                         'text-overflow:ellipsis;' +
1646                         'white-space:nowrap;',
1647                          g.imageType,
1648                          value, g.width, g.height
1649
1650                     );
1651                     c+=(g.colspan-1);
1652                     continue;
1653                 }
1654                 
1655                 out+=String.format('<td colspan="{0}" rowspan="{1}"  class="{4}"><div style="{3}">{2}</div></td>', 
1656                     g.colspan, g.rowspan, value,
1657                     'overflow:hidden;' + 
1658                     'width:'+w+'px;' +
1659                    
1660                     'text-overflow:ellipsis;' +
1661                     'white-space:nowrap;',
1662                      g.cls.join(' ')
1663     
1664     
1665                 );
1666                 c+=(g.colspan-1);
1667             }
1668             out += '</tr>';
1669         }
1670         //Roo.log(out);
1671         return out+'</table>';
1672         
1673         
1674         
1675     },
1676     /**
1677      * download:
1678      * @param {String} name  filename to downlaod (without xls)
1679      * @param {String} callback  (optional) - callback to call after callback is complete.
1680      */
1681     download : function(name,callback)
1682     {
1683         name = name || "Missing_download_filename";
1684         
1685         if (this.downloadURL && this.downloadURL.charAt(this.downloadURL.length-1) != '/') {
1686             this.downloadURL += '/';
1687         }
1688         
1689         var ser = new XMLSerializer();
1690         var x = new Pman.Download({
1691             method: 'POST',
1692             timeout : 120000, // quite a long wait.. 2 minutes.
1693             params : {
1694                xml : ser.serializeToString(this.doc),
1695                format : 'xls', //xml
1696                debug : 0
1697                
1698             },
1699             url : (this.downloadURL || (baseURL + '/GnumericToExcel/')) + name + '.xls',
1700             success : function() {
1701                 Roo.MessageBox.alert("Alert", "File should have downloaded now");
1702                 if (callback) {
1703                     callback();
1704                 }
1705             }
1706         });
1707          
1708     }
1709
1710 });