GnumericToExcel.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     /**
131      * @type {Number} cmax - maximum number of columns
132      */
133     cmax: false,
134     /**
135      * @type {Object} rmax - maximum number of rows
136      */
137     rmax : false,
138        /**
139      * @type {String} stylesheetID id of stylesheet created to render spreadsheat
140      */
141     stylesheetID : false,
142     /**
143      * @type {Number} rowOffset - used by table importer to enable multiple tables to be improted
144      */
145     
146     rowOffset : 0,
147     
148     /**
149      * load:
150      * run the connection, parse document and fire load event..
151      * can be run multiple times with new data..
152      * 
153     */
154     
155     load : function(url)
156     {
157         this.url = url || this.url;
158         if (!this.url) {
159             return;
160         }
161         // reset stufff..
162         this.doc = false;
163         this.sheet = false;
164         this.grid = false;
165         this.colInfo = false;
166         this.rowInfo = false;
167         this.cmax = false;
168         this.rmax = false;
169         
170         if (this.stylesheetID) {
171             
172             Roo.util.CSS.removeStyleSheet(this.stylesheetID);
173             this.stylesheetID = false;
174             
175         }
176         
177         _t = this;
178         var c = new Roo.data.Connection();
179         c.request({
180             url: this.url,
181             method:  'GET',
182             success : function(resp, opts) {
183                 _t.response = resp;
184                 _t.doc = resp.responseXML;
185                 _t.parseDoc();
186                 _t.parseStyles();
187                 _t.overlayStyles();
188                 _t.applyData();
189     
190                 _t.fireEvent('load', _t);
191             },
192             failure : function()
193             {
194                 Roo.MessageBox.alert("Error", "Failed to Load Template for Spreadsheet");
195             }
196         });
197         
198
199     },
200     
201     
202      
203     
204     
205     /**
206      * toRC:
207      * convert 'A1' style position to row/column reference
208      * 
209      * @arg {String} k cell name
210      * @return {Object}  as { r: {Number} , c: {Number}  }
211      */
212     
213     toRC : function(k)
214     {
215           var c = k.charCodeAt(0)-64;
216         var n = k.substring(1);
217         if (k.charCodeAt(1) > 64) {
218             c *=26;
219             c+=k.charCodeAt(1)-64;
220             n = k.substring(2);
221         }
222         return { c:c -1 ,r: (n*1)-1 }
223     },
224       /**
225      * rangeToRC:
226      * convert 'A1:B1' style position to array of row/column references
227      * 
228      * @arg {String} k cell range
229      * @return {Array}  as [ { r: {Number} , c: {Number}  }. { r: {Number} , c: {Number}  } ]
230      */
231     rangeToRC : function(s) {
232         var ar = s.split(':');
233         return [ this.toRC(ar[0]) , this.toRC(ar[1])]
234     },
235     
236     
237     
238    
239     
240     /**
241      * parseDoc:
242      * convert XML document into cells and other data..
243      * 
244      */
245     parseDoc : function() 
246     {
247         var _t = this;
248         this.grid = {}
249         this.rmax = 1;
250         this.cmax = 1;
251         
252         this.sheet = _t.doc.getElementsByTagNameNS('*','Sheet')[0];
253         
254         
255         this.cellholder = this.sheet.getElementsByTagNameNS('*','Cells')[0];
256         var cells = this.sheet.getElementsByTagNameNS('*','Cell');
257
258         
259         
260         Roo.each(cells, function(c) {
261            // Roo.log(c);
262             var row = c.getAttribute('Row') * 1;
263             var col = c.getAttribute('Col') * 1;
264             _t.cmax = Math.max(col+1, _t.cmax);
265             _t.rmax = Math.max(row+1, _t.rmax);
266             var vt = c.getAttribute('ValueType');
267             var vf = c.getAttribute('ValueFormat');
268             var val = c.textContent;
269             
270             if (typeof(_t.grid[row]) == 'undefined') {
271                 _t.grid[row] ={};
272             }
273             _t.grid[row][col] = Roo.applyIf({
274                 valueType : vt,
275                 valueFormat : vf,
276                 value : val,
277                 dom: c,
278                 r: row,
279                 c: col
280             }, _t.defaultCell);
281         });
282        
283         for (var r = 0; r < this.rmax;r++) {
284             if (typeof(this.grid[r]) == 'undefined') {
285               this.grid[r] ={};
286             }
287             for (var c = 0; c < this.cmax;c++) {
288                 if (typeof(this.grid[r][c]) == 'undefined') {
289                     continue;
290                 }
291                 //this.print( "[" + r + "]["+c+"]=" + grid[r][c].value +'<br/>');
292             }
293         }
294         
295         var merge = this.sheet.getElementsByTagNameNS('*','Merge');
296
297         Roo.each(merge, function(c) {
298             var rc = _t.rangeToRC(c.textContent);
299             //Roo.log(JSON.stringify(rc))
300             if (typeof(_t.grid[rc[0].r][rc[0].c]) == 'undefined') {
301                 _t.grid[rc[0].r][rc[0].c] =  Roo.applyIf({ r : rc[0].r, c : rc[0].c }, _t.defaultCell);
302             }
303                 
304             _t.grid[rc[0].r][rc[0].c].colspan = (rc[1].c - rc[0].c) + 1;
305             _t.grid[rc[0].r][rc[0].c].rowspan = (rc[1].r - rc[0].r) + 1;
306             for(var r = (rc[0].r); r < (rc[1].r+1); r++) {
307                for(var c = rc[0].c; c < (rc[1].c+1); c++) {
308                     //Roo.log('adding alias : ' + r+','+c);
309                    _t.grid[r][c] = _t.grid[rc[0].r][rc[0].c];
310                }
311            }
312             
313             
314         });
315         // read colinfo..
316         var ci = this.sheet.getElementsByTagNameNS('*','ColInfo');
317         this.colInfo = {};
318         this.colInfoDom = {};
319         
320         Roo.each(ci, function(c) {
321             var count = c.getAttribute('Count') || 1;
322             var s =  c.getAttribute('No')*1;
323             for(var i =0; i < count; i++) {
324                 _t.colInfo[s+i] = Math.floor(c.getAttribute('Unit')*1);
325                 _t.colInfoDom[s+i] = c;
326             }
327         });
328         
329         
330         ci = this.sheet.getElementsByTagNameNS('*','RowInfo');
331         
332         this.rowInfo = {};
333         Roo.each(ci, function(c) {
334             var count = c.getAttribute('Count') || 1;
335             var s =  c.getAttribute('No')*1;
336             for(var i =0; i < count; i++) {
337                 _t.rowInfo[s+i] = Math.floor(c.getAttribute('Unit')*1);
338             }
339         });
340     
341         
342         
343      
344         
345     },
346      /**
347      * overlayStyles:
348      * put the style info onto the cell data.
349      * 
350      */
351     overlayStyles : function ()
352     {
353            // apply styles.
354         var _t = this;
355         Roo.each(this.styles, function(s) {
356        
357             for (var r = s.r; r < s.r1;r++) {
358                 if (typeof(_t.grid[r]) == 'undefined') {
359                    continue;
360                 }
361                 for (var c = s.c; c < s.c1;c++) {
362                     if (c > _t.cmax) continue;
363     
364                     if (typeof(_t.grid[r][c]) == 'undefined') _t.grid[r][c] = Roo.applyIf({ r: r , c : c }, _t.defaultCell);
365                     var g=_t.grid[r][c];
366                     if (typeof(g.cls) =='undefined') {
367                         g.cls = [];
368                         g.styles = [];
369                     }
370                     if (g.cls.indexOf(s.name)  > -1) continue;
371                     g.cls.push(s.name);
372                     g.styles.push(s.dom);
373                     
374                 }
375             }
376         });
377     },
378      /**
379      * parseStyles: 
380      *  read the style information
381      * generates a stylesheet for the current file
382      * this should be disposed of really.....
383      * 
384      */
385     parseStyles : function() {
386                 
387         var srs = this.sheet.getElementsByTagNameNS('*','StyleRegion');
388         var _t  = this;
389         var ent = {};
390         
391         var map =  {
392             HAlign : function(ent,v) { 
393                 ent['text-align'] = { '1' : 'left', '8': 'center', '4' : 'right'}[v] || 'left';
394             },
395             VAlign : function(ent,v) { 
396                 ent['vertical-align'] = { '1' : 'top', '4': 'middel', '8' : 'bottom'}[v]  || 'top'
397             },
398             Fore : function(ent,v) { 
399                 var col=[];
400                 Roo.each(v.split(':'), function(c) { col.push(Math.round(parseInt(c,16)/256)); })
401                 ent['color'] = 'rgb(' + col.join(',') + ')';
402             },
403             Back : function(ent,v) { 
404                 var col=[];
405                 Roo.each(v.split(':'), function(c) { col.push(Math.round(parseInt(c,16)/256)); })
406                 ent['background-color'] = 'rgb(' + col.join(',') + ')';
407             },
408             FontUnit : function(ent,v) { 
409                 ent['font-size'] = v + 'px';
410             },
411             FontBold : function(ent,v) { 
412                 if (v*1 < 1) return;
413                 ent['font-weight'] = 'bold';
414             },
415             FontItalic : function(ent,v) { 
416                 if (v*0 < 1) return;
417                 //ent['font-weight'] = 'bold';
418             },
419             FontName : function(ent,v) { 
420                 ent['font-family'] = v;
421             },
422             BorderStyle : function(ent,v) { 
423                 var vv  = v.split('-');
424                 ent['border-'+vv[0]+'-style'] = 'solid';
425                 ent['border-'+vv[0]+'-width'] = vv[1]+'px';
426             },
427             BorderColor : function(ent,v) { 
428                 var vv  = v.split('-');
429                 var col=[];
430                 Roo.each(vv[1].split(':'), function(c) { col.push(Math.round(parseInt(c,16)/256)); })
431                 ent['border-'+vv[0]+'-color'] = 'rgb(' + col.join(',') + ')';
432             }
433         }
434         function add(e, k, v) {
435             //Roo.log(k,v);
436             e.gstyle[k] = v;
437             if (typeof(map[k]) == 'undefined') {
438                 return;
439             }
440             map[k](e.style,v);    
441         }
442         var css = {};
443         var styles = [];
444         var sid= Roo.id();
445         
446         
447         Roo.each(srs, function(sr,n)
448         {
449             ent = {
450                 c : sr.getAttribute('startCol') *1,
451                 r : sr.getAttribute('startRow')*1,
452                 c1 : (sr.getAttribute('endCol')*1) +1,
453                 r1 : (sr.getAttribute('endRow')*1) +1,
454                 style : {},  // key val of style for HTML..
455                 gstyle : {}, // key val of attributes used..
456                 name : sid +'-gstyle-' + n,
457                 dom : sr
458                 
459             };
460     
461             Roo.each(sr.getElementsByTagNameNS('*','Style')[0].attributes, function(e) { 
462                 add(ent, e.name, e.value);
463             });
464             if (sr.getElementsByTagNameNS('*','Font').length) {
465                 Roo.each(sr.getElementsByTagNameNS('*','Font')[0].attributes, function(e) { 
466                      add(ent, 'Font'+e.name, e.value);
467     
468                 });
469                 add(ent, 'FontName', sr.getElementsByTagNameNS('*','Font')[0].textContent);
470     
471             }
472             if (sr.getElementsByTagNameNS('*','StyleBorder').length) {
473                 Roo.each(sr.getElementsByTagNameNS('*','StyleBorder')[0].childNodes, function(e) {
474                     if (!e.tagName) {
475                         return;
476                     }
477                     Roo.each(e.attributes, function(ea) { 
478                         add(ent, 'Border'+ea.name, e.tagName.split(':')[1].toLowerCase() + '-' + ea.value);
479                     });
480                 })
481                     
482             }
483             styles.push(ent);
484             css['.'+ent.name] = ent.style;
485         });
486         
487         this.styles = styles;
488         
489         this.stylesheetID = sid;
490         Roo.util.CSS.createStyleSheet(css, sid);
491     },
492
493     /* ---------------------------------------  AFTER LOAD METHODS... ----------------------- */
494     /**
495      * set: 
496      * Set the value of a cell..
497      * @param {String} cell name of cell, eg. C10 or { c: 1, r :1 }
498          
499      * @param {Value} value to put in cell..
500      * @param {ValueType} type of value
501      * @param {ValueFormat} value format of cell
502      * 
503      * Cells should exist at present, we do not make them up...
504      */
505      
506     
507     set : function(cell, v, vt, vf) {
508         
509         var cs= typeof(cell) == 'string' ? this.toRC(cell) : cell;
510         //Roo.log( cs.r+ ',' + cs.c + ' = '+ v);
511         // need to generate clell if it doe
512         if (typeof(this.grid[cs.r]) == 'undefined') {
513             Roo.log('no row:' + cell);
514             this.grid[cs.r] = []; // create a row..
515             //return;
516         }
517         if (typeof(this.grid[cs.r][cs.c]) == 'undefined') {
518             Roo.log('cell not defined:' + cell);
519             this.createCell(cs.r,cs.c);
520         }
521         if (typeof(this.grid[cs.r][cs.c].dom) == 'undefined') {
522             Roo.log('no default content for cell:' + cell);
523             this.createCell(cs.r,cs.c);
524             //return;
525         }
526         this.grid[cs.r][cs.c].value=  v;
527         this.grid[cs.r][cs.c].dom.textContent=  v;
528         if (typeof(vt != 'undefined') && vt) {
529             this.grid[cs.r][cs.c].valueType = vt;
530             this.grid[cs.r][cs.c].dom.setAttribute('ValueType', vt);
531         }
532         if (typeof(vf != 'undefined') && vf) {
533             this.grid[cs.r][cs.c].valueFormat = vf;
534             this.grid[cs.r][cs.c].dom.setAttribute('ValueFormat', vf);
535         }
536         
537     },
538     
539     // private
540     copyRow : function(src, dest) {
541         if (dest == src) {
542             return;
543         }
544        // Roo.log('create Row' + dest);
545         if (typeof(this.grid[dest]) == 'undefined') {
546             this.grid[dest] = {}
547         }
548         
549            
550         for (var c = 0; c < this.cmax; c++) {
551
552             this.copyCell({ r: src, c: c } , { r: dest, c: c});
553             
554         }
555         this.rmax = Math.max(this.rmax, dest +1);
556         
557     },
558     
559     // private
560     
561     createCell: function(r,c)
562     {
563         //<gnm:Cell Row="6" Col="5" ValueType="60">Updated</gnm:Cell>    
564         var nc = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:Cell');
565         this.cellholder.appendChild(nc);
566         var lb = this.doc.createTextNode("\n");// add a line break..
567         this.cellholder.appendChild(lb);
568         
569         nc.setAttribute('Row', new String(r));
570         nc.setAttribute('Col', new String(c));
571         nc.setAttribute('ValueType', '60');
572         nc.textContent = '';
573         
574         this.grid[r][c] = Roo.applyIf({
575             valueType : '60',
576             valueFormat : '',
577             value : '',
578             dom: nc,
579             r: r,
580             c: c
581             }, _t.defaultCell);
582         
583         return nc;
584
585     },
586     
587     // private
588     copyCell : function(src, dest)
589     {
590         var old = this.grid[src.r][src.c];
591         // is it an alias...
592         if ((old.c != src.c)  || (old.r != src.r)) {
593             // only really works on horizonatal merges..
594             
595             this.grid[dest.r][dest.c] = this.grid[desc.r][old.c]; // let's hope it exists.
596             return;
597         }
598         
599         
600         var nc = Roo.apply({}, this.grid[src.r][src.c]);
601         
602         nc.value = '';
603         if (typeof(old.dom) == 'undefined') {
604             Roo.log("No cell to copy for " + Roo.encode(src));
605             return;
606         }
607         this.grid[dest.r][dest.c] = nc;
608         nc.dom = old.dom.cloneNode(true);
609         nc.dom.setAttribute('Row', dest.r);
610         nc.dom.setAttribute('Cell', dest.c);
611         nc.dom.textContent = '';
612         old.dom.parentNode.appendChild(nc.dom);
613         if (!old.styles || !old.styles.length) {
614             return;
615         }
616         //Roo.log("DEST");
617         //Roo.log(dest);
618         //Roo.log("STYLES");
619         //  .styles...
620         Roo.each(old.styles, function(s) {
621             // try and extend existing styles..
622             var er = s.getAttribute('endRow') * 1;
623             var ec = s.getAttribute('endCol') * 1;
624             //Roo.log(s);
625             if (dest.r == er) {
626                 s.setAttribute('endRow', dest.r + 1);
627             }
628             if (dest.c == ec) {
629                 s.setAttribute('endCol', dest.c + 1);
630             }
631             /*var ns = s.cloneNode(true);
632             s.parentNode.appendChild(ns);
633             ns.setAttribute('startCol', dest.c);
634             ns.setAttribute('startRow', dest.r);
635             ns.setAttribute('endCol', dest.c + 1);
636             ns.setAttribute('endRow', dest.r +1);
637             */
638         });
639         
640     },
641     
642     
643     /**
644      * applyData: 
645      * Set the value of a cell..
646      * @param {String} cell name of cell, eg. C10
647      * @param {Value} value to put in cell..
648      * 
649      * Cells should exist at present, we do not make them up...
650      */
651      
652     applyData : function(data)
653     {
654         
655         data = data || this.data;
656         for (var r = 0; r < this.rmax;r++) {
657             if (typeof(this.grid[r]) == 'undefined') continue;
658             for (var c = 0; c < this.cmax;c++) {  
659                 if (typeof(this.grid[r][c]) == 'undefined') {
660                     continue;
661                 }
662                 if (!this.grid[r][c].value.length 
663                         || !this.grid[r][c].value.match(/\{/)) {
664                     continue;
665                 }
666                 
667                 var x = new Roo.Template({ html: this.grid[r][c].value });
668                 try {
669                     var res = x.applyTemplate(data);
670                     //Roo.log("set " + r  + "," + c + ":"+res)
671                     this.set({ r: r, c: c}, x.applyTemplate(data));
672                 } catch (e) {
673                  //   Roo.log(e.toString());
674                   //  Roo.log(e);
675                     // continue?
676                 }
677                 
678             }
679         }
680             
681     },
682      
683     /**
684      * importTable: 
685      * Import a table and put it into the spreadsheet
686      * @param {HTMLTable} datagrid dom element of html table.
687      * @param {Number} xoff X offset to start rendering to
688      * @param {Number} yoff Y offset to start rendering to
689      **/
690      
691  
692     importTable : function (datagrid, xoff,yoff)
693     {
694         if (!datagrid) {
695             Roo.log("Error table not found!?");
696             return;
697         }
698         xoff = xoff || 0;
699         yoff = yoff || 0;
700         
701         var cleanHTML = function (str) {
702             
703              var ret = str;
704             ret = ret.replace(/&nbsp;/g,'.');
705             ret = ret.replace(/\n/g,'.');
706             ret = ret.replace(/\r/g,'.');
707             var i;
708             while (-1 != (i = ret.indexOf(unescape('%A0')))) {
709                 ret = ret.substring(0,i) + ' ' + ret.substring(i+1,str.length);
710             }
711             return ret;
712         };
713
714         
715         // <cell col="A" row="1">Test< / cell>
716         // <cell col="B" row="2" type="Number" format="test1">30< / cell>
717         var rowOffsets = [];
718         var rows = datagrid.getElementsByTagName('tr');
719         //alert(rows.length);
720         
721         for(var row=0;row<rows.length;row++) {
722             //var style = document.defaultView.getComputedStyle(rows[row], "");
723             
724             //if (rows[row].getAttribute('xls:height')) {
725             //    this.setRowHeight(row+y_offset, 0 + rows[row].getAttribute('xls:height'));
726             //} else {
727             //    this.setRowHeight(row+y_offset, 0 + style.height.replace(/[^0-9.]+/g,''));
728            // }
729             
730             //var coloffset = 0;
731            // if (rowOffsets[row]) {
732            //     coloffset += rowOffsets[row];
733            // }
734             var cols = rows[row].getElementsByTagName('td');
735             
736             
737             for(var col=0;col < cols.length; col++) {
738                 
739                 
740                 //var colat = col + coloffset;
741                 /*
742                 if (cols[col].getAttribute('colspan') && (cols[col].getAttribute('colspan') > 1)) {
743                     
744                     
745                     this.mergeRegion(
746                         colat,
747                         row +y_offset,
748                         colat + (cols[col].getAttribute('colspan') - 1), 
749                         row+y_offset + (
750                                 (cols[col].getAttribute('rowspan') > 1) ?
751                                     (cols[col].getAttribute('rowspan') - 1) : 0
752                                 )
753                     );
754                     
755                     
756                     
757                     coloffset += (cols[col].getAttribute('colspan') - 1);
758                 }
759                
760                 if (cols[col].getAttribute('rowspan') && (cols[col].getAttribute('rowspan') > 1)) {
761                     // this should really do a merge, but it's pretty damn complex...
762                     //this.mergeRegion(colat,row +y_offset,colat + (cols[col].getAttribute('colspan') - 1), row+y_offset);
763                     var rroff = cols[col].getAttribute('colspan')  ? (cols[col].getAttribute('colspan') -0): 1;
764                     var rr = 0;
765                     for (rr = 0; rr < cols[col].getAttribute('rowspan');rr++) {
766                         rowOffsets[rr + row] = col + rroff;
767                     }
768                     
769                 }
770                  */
771                
772                 /*
773                 var style = this.newStyle();
774                 if (style.setFrom(cols[col])) {
775                     style.add(
776                         colat+x_offset,
777                         row+y_offset,
778                         
779                         colat+x_offset + ((cols[col].getAttribute('colspan') > 1) ?
780                                     (cols[col].getAttribute('colspan') - 1) : 0),
781                         row+y_offset  + ((cols[col].getAttribute('rowspan') > 1) ?
782                                     (cols[col].getAttribute('rowspan') - 1) : 0) 
783                     );
784                 }
785                 
786                  */
787                 // skip blank cells
788                 if (!cols[col].childNodes.length) {
789                     continue;
790                 }
791                 
792                 
793                 
794                 
795                 var vt = '60';
796                 var vf = false;
797                 
798                 switch(cols[col].getAttribute('xls:type')) {
799                     case 'int':
800                         vt = 30; // int!!!!
801                         break;
802                         
803                     case 'float':
804                         vt = 40; // float!!!!
805                         if (cols[col].getAttribute('xls:floatformat')) {
806                                 vf = cols[col].getAttribute('xls:floatformat');
807                         }
808                         break;
809                         
810                     case 'date':
811                         vt = 30;
812                         //ValueFormat="d/m/yyyy" 38635  
813                         var vf = 'd/m/yyy';
814                         if (cols[col].getAttribute('xls:dateformat')) {
815                             vf= cols[col].getAttribute('xls:dateformat');
816                         }
817                         
818                        
819                         
820                         break;
821                     
822                     default:
823                        
824                         break;
825                 }
826                 /*
827                 if (cols[col].getAttribute('xls:src')) {
828                     //alert(cols[col].childNodes[0].width);
829                     if (this.writeImage(
830                         row+y_offset, 
831                         colat+x_offset+coloffset, 
832                         cols[col].getAttribute('xls:src'), 
833                         cols[col].childNodes[0].width, 
834                         cols[col].childNodes[0].height
835                         )) {
836                        
837                     }
838                     continue;
839                 }
840                 */
841                  
842                 if (!cols[col].childNodes[0].nodeValue) {
843                     continue;
844                 }
845                 if (!cols[col].childNodes[0].nodeValue.replace(/^\s*|\s*$/g,"").length) {
846                     continue;
847                 }
848                 // strip me.!
849                 var cell_value_text = cleanHTML(cols[col].childNodes[0].nodeValue);
850        
851                 if (cols[col].getAttribute('xls:percent')) {
852                     cell_value_text = '' + ((cell_value_text * 1) / 100);
853                 }
854
855                 if (cell_value_text.length && (vt == 30)) {
856                     var bits = cell_value_text.split(/-/);
857                     var cur = new Date(bits[0],bits[1]-1,bits[2]);
858                     cell_value_text = '' + Math.round((cur.getTime() - Date.UTC(1899,11,30)) / (24 * 60 * 60 * 1000));
859                 }
860
861                 
862                 
863                 if (cols[col].getAttribute('xls:formula')) {
864                     var s = cols[col].getAttribute('xls:formula');
865                     cols[col].removeAttribute('ValueType');
866                     cell_value_text = s.replace(/#row#/g,(row + yoff + 1));
867                 }
868                 this.set({ r: row + yoff, c : col + xoff }, cell_value_text, vt, vf);
869                 
870                 
871                 
872                 
873                 
874             }
875         }
876         this.rowOffset += rows.length;
877         
878     },
879        
880     /**
881      * setSheetName: 
882      * Set the sheet name.
883      * @param {String} title for sheet
884      **/
885     setSheetName : function(n)
886     {
887         /*
888         <gnm:SheetNameIndex>
889         <gnm:SheetName>Sheet1</gnm:SheetName>
890         <gnm:SheetName>Sheet2</gnm:SheetName>
891         <gnm:SheetName>Sheet3</gnm:SheetName>
892         </gnm:SheetNameIndex>
893         */
894         var sheetn = this.doc.getElementsByTagNameNS('*','SheetName')[0];
895         sheetn.textContent = n;
896         
897     },
898      /**
899      * setColumnWidth: 
900      * Set the column width
901      * @param {Number} column number (starts at '0')
902      * @param {Number} width size of column
903      **/
904     setColumnWidth : function(column, width)
905     {
906         column = column *1; 
907         width= width*1;
908         if (typeof(this.colInfoDom[column]) == 'undefined') {
909             var cols = this.doc.getElementsByTagNameNS('*','Cols')[0];
910             var ri = this.doc.createElementNS('http://www.gnumeric.org/v10.dtd', 'gnm:ColInfo');
911             ri.setAttribute('No', column);
912             ri.setAttribute('Unit', width);
913             ri.setAttribute('MarginA', 2);
914             ri.setAttribute('MarginB', 2);
915             ri.setAttribute('HardSize', 1);
916             cols.appendChild(ri);
917             this.colInfo[column] = width;
918             this.colInfoDom[column]  = ri;
919             return;
920         }
921         this.colInfoDom[column].setAttribute('Unit', width);
922         
923     },
924      /**
925      * toHTML: 
926      * Convert spreadsheet into a HTML table.
927      */
928             
929     toHTML :function()
930     {
931          var _t = this;
932         function calcWidth(sc, span)
933         {
934             var n =0;
935             for(var i =sc; i< sc+span;i++) {
936                 n+=_t.colInfo[i];
937             }   
938             return n;
939         }
940         
941         var grid = this.grid;
942         // lets do a basic dump..
943         var out = '<table style="table-layout:fixed;" cellpadding="0" cellspacing="0">';
944         for (var r = 0; r < this.rmax;r++) {
945             out += '<tr style="height:'+this.rowInfo[r]+'px;">';
946             for (var c = 0; c < this.cmax;c++) {
947                 var g = (typeof(grid[r][c]) == 'undefined') ? defaultCell  : grid[r][c];
948                 
949                 if (typeof(g.cls) =='undefined') g.cls = [];
950                 var w= calcWidth(c,g.colspan);
951                 out+=String.format('<td colspan="{0}" rowspan="{1}"  class="{4}"><div style="{3}">{2}</div></td>', 
952                     g.colspan, g.rowspan, g.value,
953                     'overflow:hidden;' + 
954                     'width:'+w+'px;' +
955                    
956                     'text-overflow:ellipsis;' +
957                     'white-space:nowrap;',
958                      g.cls.join(' ')
959     
960     
961                 );
962                 c+=(g.colspan-1);
963             }
964             out += '</tr>';
965         }
966         //Roo.log(out);
967         return out+'</table>';
968         
969         
970         
971     },
972     /**
973      * download:
974      * @param {String} name  filename to downlaod (without xls)
975      * @param {String} callback  (optional) - callback to call after callback is complete.
976      */
977     download : function(name,callback)
978     {
979         name = name || "Missing_download_filename";
980         
981         if (this.downloadURL && this.downloadURL.charAt(this.downloadURL .length-1) != '/') {
982             this.downloadURL += '/';
983         }
984         
985         var ser = new XMLSerializer();
986         var x = new Pman.Download({
987             method: 'POST',
988             params : {
989                xml : ser.serializeToString(this.doc),
990                format : 'xls', //xml
991                debug : 0
992                
993             },
994             url : (this.downloadURL || (baseURL + '/GnumericToExcel/')) + name + '.xls',
995             success : function() {
996                 Roo.MessageBox.alert("Alert", "File should have downloaded now");
997                 if (callback) {
998                     callback();
999                 }
1000             }
1001         });
1002          
1003     }
1004
1005 });