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