Commit 2deb6154a2b8aa7aa2503388b72ba0054d51837d

Authored by Hacene SI HADJ MOHAND
1 parent 2af1d21e

function fairfield70 et lopez90

generic_data/Functions/functions.xml
... ... @@ -60,6 +60,7 @@
60 60 <info_brief>variance() function</info_brief>
61 61 <new_kernel>#var_sm</new_kernel>
62 62 </function>
  63 +
63 64 <function name="skew_sm_(,)" args="1" kind="sliding">
64 65 <prompt>input window time in secs</prompt>
65 66 <info_brief>skewness() function</info_brief>
... ... @@ -70,20 +71,49 @@
70 71 <info_brief>smooths with a boxcar average</info_brief>
71 72 <new_kernel>#boxcar</new_kernel>
72 73 </function>
  74 +
73 75 <!-- <function name="shiftN_(,)" args="1" kind="amda">
74 76 <prompt>input number of points N to delay by</prompt>
75 77 <info_brief>Delays array by N points back (N &lt; 0) and forth (N &gt; 0)</info_brief>
76 78 </function>-->
  79 +
77 80 <function name="shiftT_(,)" args="1" kind="amda">
78 81 <prompt>input time interval T in secs to delay by</prompt>
79 82 <info_brief>Delays array by T secs back (T &lt; 0) and forth (T &gt; 0))</info_brief>
80 83 <new_kernel>#timeShift</new_kernel>
81 84 </function>
  85 +
82 86 <function name="Valfven(,)" params="2" kind="physics">
83 87 <prompt>Alfven velocity Valfven(density[cm^โป3], mag[nT])</prompt>
84 88 <info_brief>Alfven velocity Valfven(density[cm^โป3], mag[nT])</info_brief>
85 89 <new_kernel>alfvenVelocity</new_kernel>
86 90 </function>
  91 +
  92 + <function name="fairfield70(,)" params="3" kind="physics">
  93 + <prompt>FAIRFIELD 1970 model of neutral sheet position Z = fairfield70(y_sm, z_sm, x_ss)
  94 + where y_sm and z_sm are the solar magnetospheric coordinates of the spacecraft
  95 + and x_ss is geomagnetic latitude of the sun</prompt>
  96 +
  97 + <info_brief>FAIRFIELD 1970 model of neutral sheet position Z = fairfield70(y_sm, z_sm, x_ss)
  98 + where y_sm and z_sm are the solar magnetospheric coordinates of the spacecraft
  99 + and x_ss is geomagnetic latitude of the sun</info_brief>
  100 + <new_kernel>fairfield70</new_kernel>
  101 + </function>
  102 +
  103 + <function name="lopez90(,)" params="4" kind="physics">
  104 + <prompt>
  105 + Lopez 1990 model of magnetic latitude of the neutral sheet MLAT = lopez90(Kp, phi, R, DTA)
  106 + where Kp is the 3-hour magnetic index, phi the magnetic local time in degrees (phi = 0ยฐ at midnight)
  107 + R is the radial distance in RE and DTA is the dipole tilt angle
  108 + </prompt>
  109 + <info_brief>
  110 + Lopez 1990 model of magnetic latitude of the neutral sheet MLAT = lopez90(Kp, phi, R, DTA)
  111 + where Kp is the 3-hour magnetic index, phi the magnetic local time in degrees (phi = 0ยฐ at midnight)
  112 + R is the radial distance in RE and DTA is the dipole tilt angle
  113 + </info_brief>
  114 + <new_kernel>lopez90</new_kernel>
  115 + </function>
  116 +
87 117 <!-- <function name="gsegsm_()" argv="vector" kind="amda">
88 118 <prompt/>
89 119 <info_brief>GSE to GSM transformation</info_brief>
... ... @@ -93,10 +123,12 @@
93 123 <prompt/>
94 124 <info_brief>GSE to SM transformation</info_brief>
95 125 </function>-->
  126 +
96 127 <function name="angle(,)" params="2" kind="vectors">
97 128 <info_brief>Angle between two vectors</info_brief>
98 129 <new_kernel>angle</new_kernel>
99 130 </function>
  131 +
100 132 <function name="cross(,)" params="2" kind="vectors">
101 133 <info_brief>Cross product</info_brief>
102 134 <new_kernel>cross</new_kernel>
... ...
js/app/views/CalculatorUI.js
... ... @@ -14,504 +14,502 @@
14 14 * @ptype calculator
15 15 */
16 16  
17   -var CalculatorData = ['1','2','3','4','5','6','7','8','9','0','(',')','[',']','+','-','*','/','^', '.','>','<', '&', '|'];
  17 +var CalculatorData = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '(', ')', '[', ']', '+', '-', '*', '/', '^', '.', '>', '<', '&', '|'];
18 18 // var CalculatorData = ['1','2','3','4','5','6','7','8','9','0','(',')','[',']','+','-','*','/','^', '.','>','>=', '=', '<=', '<', '&', '|'];
19 19  
20 20 Ext.define('amdaUI.CalculatorUI', {
21   - extend: 'Ext.util.Observable',
22   -
23   - requires : [
24   - 'amdaModel.Constant',
25   - 'amdaModel.Function'
26   - ],
27   -
28   - alias: 'plugin.calculator',
29   -
30   - statics : {
31   - constantStore : null,
32   - functionStore : null
33   - },
34   -
35   - win: null,
36   -
37   - constructor: function(config) {
38   - Ext.apply(this, config);
39   - this.callParent(arguments);
40   - },
41   -
42   - init: function(cmp)
43   - {
44   - this.hostCmp = cmp;
45   - this.hostCmp.on({
46   - scope: this,
47   - added: function(){
48   - this.hostCmp.ownerCt.on({
49   - render: this.onRender,
50   - show: this.onShow,
51   - hide : this.onHide,
52   - scope: this });
53   - }
54   - });
55   - },
56   -
57   - onRender: function()
58   - {
59   - this.win = new Ext.Window({
60   - width: 350,
61   - height: 170,
62   - x: 380, y: 0,
63   - baseCls:'x-panel',
64   - title: 'Tools For ' + this.context + ' Construction',
65   - layout: 'fit',
66   - closable: false,
67   - collapsible: true,
68   - constrain: true,
69   - floating: true,
70   - ghost: false,
71   - renderTo: this.hostCmp.id,
72   - items: this.getFormConfig(),
73   - listeners : {
74   - boxready: function (w)
75   - {
76   - if (w.y + w.height > myDesktopApp.desktop.el.getHeight())
77   - w.el.setY((myDesktopApp.desktop.el.getHeight()-w.height > 0) ? myDesktopApp.desktop.el.getHeight()-w.height : 0);
78   - }
79   - },
80   - getConstrainVector: function(constrainTo){
81   - var me = this;
82   - if (me.constrain || me.constrainHeader) {
83   - constrainTo = constrainTo || (me.floatParent && me.floatParent.getTargetEl()) || me.container || me.el.getScopeParent();
84   - return (me.constrainHeader ? me.header.el : me.el).getConstrainVector(constrainTo);
85   - }
86   - }
87   - });
88   -
89   - //load constants store
90   - if (!amdaUI.CalculatorUI.constantStore)
91   - {
92   - amdaUI.CalculatorUI.constantStore = Ext.create('Ext.data.Store',{model: 'amdaModel.Constant'});
93   - amdaUI.CalculatorUI.constantStore.load({
94   - scope : this,
95   - callback: function(records, operation, success)
96   - {
97   - this.createAllConstantBtns();
98   - }
99   - });
100   - }
101   - else
102   - this.createAllConstantBtns();
103   -
104   - //load functions store
105   - if (!amdaUI.CalculatorUI.functionStore)
106   - {
107   - amdaUI.CalculatorUI.functionStore = Ext.create('Ext.data.Store',{model: 'amdaModel.Function'});
108   - amdaUI.CalculatorUI.functionStore.load({
109   - scope : this,
110   - callback: function(records, operation, success)
111   - {
112   - this.createAllFunctionBtns();
113   - }
114   - });
115   - }
116   - else
117   - this.createAllFunctionBtns();
118   - },
119   -
120   - onShow: function() {
121   - this.win.show();
122   - var parentWin = this.hostCmp.findParentByType('window');
123   -
124   - if (parentWin.getId() === myDesktopApp.dynamicModules.param.id) {
125   - this.win.setPosition(335,10);
126   - }
127   - else {
128   -
129   - var posX = parentWin.getWidth() - this.win.getWidth() - 30;
130   - var posY = parentWin.getHeight() - this.win.getHeight() - 110 - 30/*20*/;
131   - this.win.setPosition(posX,posY);//(420,290);
132   - }
133   - },
134   -
135   - onHide : function()
136   - {
137   - this.win.hide();
138   - },
139   -
140   - getFormConfig: function(){
141   - return {
142   - xtype: 'tabpanel',
143   - border: false, frame: true, plain: true,
144   - enableTabScroll: true,
145   - defaults: { frame: true, border: false, plain: true, autoScroll:true},
146   - activeTab: 0,
147   - items: [ {
148   - title: 'Calculator',layout: 'column',
149   - defaults: { xtype: 'button', columnWidth: .11},
150   - items: this.getItems('Calculator')
151   - } , {
152   - title: 'Constants', xtype:'tabpanel', //iconCls: 'tabs',
153   - enableTabScroll: true, tabPosition: 'bottom',
154   - defaults: { frame: true, border: false, plain: true, layout: 'column', autoScroll:true},
155   - activeTab: 0,
156   - id : 'calc_tab_const_id'
157   - }, {
158   - title: 'Functions', xtype:'tabpanel', //iconCls: 'tabs',
159   - enableTabScroll: true, tabPosition: 'bottom',
160   - defaults: { frame: true, border: false, plain: true, layout: 'column', autoScroll:true},
161   - activeTab: 0,
162   - id : 'calc_tab_func_id'
163   - }]
164   - };
165   - },
166   -
167   - /**
168   - * Prompt any argument to user before processing Formula
169   - * @param sel selected text
170   - * @param currentBtn calculator button pressed
171   - * @param params array of parameters
172   - */
173   - preProcessFormula: function(sel,currentBtn, params) {
174   -
175   - if (currentBtn.initialConfig.args!=0 && currentBtn.initialConfig.prompt!=""){
176   - // Prompt for user precision and process the result using a callback
177   - Ext.Msg.prompt('Argument',currentBtn.initialConfig.prompt, function(bt2, text){
178   - if (bt2 === 'ok'){
179   - var afterParamsText = "," + text + ")";
180   - //TODO: more than one args and prompt
181   - this.processFormula(sel,currentBtn, params, afterParamsText);
182   -
183   - }
184   - },this);
185   - } else {
186   - this.processFormula(sel,currentBtn, params, ")");
187   - }// endif prompt
188   - },
189   -
190   - processFormula : function(sel,currentBtn, params, afterParamsText){
191   - // calculation of the required number of parameters
192   - var nbParams = currentBtn.initialConfig.params;
193   - var fnText = currentBtn.text.split('(');
194   - var newConstruction = sel.beforeText + fnText[0]+"(";
195   - // if there at least one parameter selected
196   - if (params.length){
197   - for (var i=0;i<nbParams;i++) {
198   - if(i>0) {
199   - newConstruction += ",";
200   - }
201   - newConstruction += params[i];
202   - }
203   - }
204   - // we keep position
205   - var afterParameterPos = newConstruction.length;
206   - newConstruction += afterParamsText;
207   - var caretPos = newConstruction.length;
208   - newConstruction += sel.afterText;
209   - this.hostCmp.constructionField.setValue(newConstruction);
210   -
211   - // If we haven't the right number of selected parameters
212   - if (params.length < nbParams){
213   - var stringParamRequired = currentBtn.initialConfig.params+" parameter(s)";
214   - Ext.Msg.alert('Caution', 'you\'ll have to add '+ stringParamRequired +' to apply this function',
215   - function(){
216   - // set Caret Position at placement of required parameter in function
217   - this.hostCmp.constructionField.setCaretPosition(afterParameterPos);
218   - },this
219   - );
220   - } else {
221   - // set Caret Position after inserted Text
222   - this.hostCmp.constructionField.setCaretPosition(caretPos);
223   - }
224   - },
225   -
226   - /**
227   - * This method construct an array of arguments into selected text
228   - * @param selectedText the selection to parse
229   - * @param parseIndex the index to start parsing
230   - * @return the arguments array
231   - */
232   - parseArgsInFormula : function (selectedText, parseIndex) {
233   -
234   - if (!selectedText || selectedText==""){
235   - return [];
236   - } else {
237   - var params = [];
238   - var startIndex = parseIndex;
239   - var curIndex = parseIndex;
240   - var openBrace = 0;
241   - var sep = 0;
242   - var closeBrace = 0;
243   -
244   - // while there is a separator
245   - while(sep!=-1){
246   - openBrace = selectedText.indexOf("(",curIndex);
247   - sep = selectedText.indexOf(",",curIndex);
248   - closeBrace = selectedText.indexOf(")",curIndex);
249   -
250   - // if there's an open bracket and no close bracket or inversely
251   - if (openBrace!=-1 && closeBrace==-1 || openBrace==-1 && closeBrace!=-1) {
252   - // invalid selection
253   - return -1;
254   - }
255   -
256   - // if there's a separator and opening brackets into selection
257   - if (sep!=-1 && openBrace!=-1){
258   - // if brace is before separator
259   - if (openBrace<sep) {
260   - curIndex = this.getEndBracket(selectedText,openBrace+1);
261   - if (curIndex===-1){
262   - return -1;
263   - }
264   - } else {// else separator is before brace
265   - params.push(selectedText.substring(startIndex,sep));
266   - startIndex = curIndex = sep+1;
267   - }
268   - // if there's only separators into selection
269   - } else if (sep!=-1) {
270   - params.push(selectedText.substring(startIndex,sep));
271   - startIndex = curIndex = sep+1;
272   - }
273   - }
274   - params.push(selectedText.substring(startIndex,selectedText.length));
275   - return params;
276   - }
277   - },
278   -
279   - getEndBracket : function(string,indOpenBrace){
280   - // we search for the corresponding end brace (after open bracket)
281   - var currentIndex = indOpenBrace;
282   - var nextCloseBrace = 0;
283   - var nextOpenBrace = 0;
284   - var braceLevel = 1;
285   - while (nextCloseBrace!==-1 && braceLevel!==0){
286   - // get index of next opening bracket
287   - nextOpenBrace = string.indexOf("(",currentIndex);
288   - // get index of next closing bracket
289   - nextCloseBrace = string.indexOf(")",currentIndex);
290   - // if both exist
291   - if (nextOpenBrace!=-1 && nextCloseBrace!=-1) {
292   - // if opening bracket is before closing one
293   - if (nextOpenBrace<nextCloseBrace) {
294   - currentIndex = nextOpenBrace+1;
295   - braceLevel++;
296   - } else { // if closing bracket is before opening one
297   - currentIndex = nextCloseBrace+1;
298   - braceLevel--;
299   - }
300   - // if there's only a next opening bracket
301   - } else if (nextOpenBrace!=-1 && nextCloseBrace==-1) {
302   - currentIndex = nextOpenBrace+1;
303   - braceLevel++;
304   - // if there's only a next closing bracket
305   - } else if (nextOpenBrace==-1 && nextCloseBrace!=-1) {
306   - currentIndex = nextCloseBrace+1;
307   - braceLevel--;
308   - }
309   - }
310   - // if no level imbrication left return index after closing bracket of block else -1
311   - return braceLevel==0 ? currentIndex : -1;
312   - },
313   -
314   - getCalculatorBtn : function()
315   - {
316   - var btns = [];
317   -
318   - Ext.each(CalculatorData, function (c){
319   - btns.push({
320   - text: c,
321   - scope: this,
322   - handler: function(b,e){
323   - // keep selection into construction field
324   - var selection = this.hostCmp.constructionField.getSelection();
325   - // the new value of construction field
326   - var newConstruction = "";
327   - // replacement of selection into construction field by text of clicked button
328   - newConstruction = selection.beforeText + b.text;
329   - var caretPos = newConstruction.length;
330   - newConstruction += selection.afterText;
331   - this.hostCmp.constructionField.setValue(newConstruction);
332   - // set Caret Position after inserted Text
333   - this.hostCmp.constructionField.setCaretPosition(caretPos);
334   - }
335   - })
336   - },
337   - this
338   - );
339   -
340   - return btns;
341   - },
342   -
343   - createAllFunctionBtns : function()
344   - {
345   - this.createFunctionBtns('MathFunctions','Simple Maths');
346   - this.createFunctionBtns('VectorFunctions','Vector Functions');
347   - this.createFunctionBtns('TimeFunctions','Statistics');
348   - this.createFunctionBtns('FunctionsSliding','Statistics/Sliding');
349   - this.createFunctionBtns('PhysicsFunctions','Physics');
350   - this.createFunctionBtns('AmdaFunctions','Special');
351   - },
352   -
353   - createAllConstantBtns : function()
354   - {
355   - this.createConstantBtns('Space','Planets Constants');
356   - this.createConstantBtns('Physics','Physics Constants');
357   - this.createConstantBtns('Units','Units Conversion');
358   - },
359   -
360   - createConstantBtns : function(item, tabTitle)
361   - {
362   - var constTab = this.win.query('#calc_tab_const_id');
363   -
364   - if (constTab.length < 1)
365   - return;
366   -
367   - switch (item)
368   - {
369   - case 'Space' :
370   - amdaUI.CalculatorUI.constantStore.filter('kind','space');
371   - break;
372   - case 'Physics' :
373   - amdaUI.CalculatorUI.constantStore.filter('kind','physics');
374   - break;
375   - case 'Units' :
376   - amdaUI.CalculatorUI.constantStore.filter('kind','units');
377   - break;
378   - }
379   -
380   - var crtTab = constTab[0].add(
381   - {
382   - title : tabTitle,
383   - defaults: { xtype: 'button', columnWidth: .20}
384   - });
385   -
386   - amdaUI.CalculatorUI.constantStore.each( function(c){
387   - crtTab.add(
388   - {
389   - text: c.get('name'),
390   - tooltip: c.get('units') == '' ? c.get('info')+'<br/>'+c.get('value') :
391   - c.get('info')+'<br/>'+c.get('value')+' '+c.get('units'),
392   - scope: this,
393   - handler: function(b,e){
394   - // keep selection into construction field
395   - var selection = this.hostCmp.constructionField.getSelection();
396   - // the new value of construction field
397   - var newConstruction = "";
398   - // replacement of selection into construction field by text of clicked button
399   - newConstruction = selection.beforeText + '@'+b.text;
400   - var caretPos = newConstruction.length;
401   - newConstruction += selection.afterText;
402   - this.hostCmp.constructionField.setValue(newConstruction);
403   - // set Caret Position after inserted Text
404   - this.hostCmp.constructionField.setCaretPosition(caretPos);
405   - }
406   - });
407   - },this);
408   -
409   - //clear filter
410   - amdaUI.CalculatorUI.constantStore.clearFilter();
411   - },
412   -
413   - createFunctionBtns : function(item, tabTitle)
414   - {
415   - var funcTab = this.win.query('#calc_tab_func_id');
416   -
417   - if (funcTab.length < 1)
418   - return;
419   -
420   - switch (item)
421   - {
422   - case 'MathFunctions' :
423   - amdaUI.CalculatorUI.functionStore.filter('kind','math');
424   - break;
425   - case 'AmdaFunctions' :
426   - amdaUI.CalculatorUI.functionStore.filter('kind','amda');
427   - break;
428   - case 'TimeFunctions' :
429   - amdaUI.CalculatorUI.functionStore.filter('kind','time');
430   - break;
431   - case 'FunctionsSliding' :
432   - amdaUI.CalculatorUI.functionStore.filter('kind','sliding');
433   - break;
434   - case 'VectorFunctions' :
435   - amdaUI.CalculatorUI.functionStore.filter('kind','vector');
436   - break;
437   - case 'PhysicsFunctions' :
438   - amdaUI.CalculatorUI.functionStore.filter('kind','physics');
439   - break;
440   - }
441   -
442   - var crtTab = funcTab[0].add(
443   - {
444   - title : tabTitle,
445   - defaults: { xtype: 'button', columnWidth: .20}
446   - });
447   -
448   - amdaUI.CalculatorUI.functionStore.each( function(f){
449   - crtTab.add(
450   - {
451   - text: f.get('name'),
452   - args: f.get('args'),
453   - params: f.get('params'),
454   - prompt: f.get('prompt'),
455   - tooltip: f.get('info_brief'),
456   - scope: this,
457   - handler: function(b,e){
458   - var selection = this.hostCmp.constructionField.getSelection();
459   - var selectedText = selection&&selection.text!="" ? Ext.util.Format.trim(selection.text) : null;
460   - if (selectedText && selectedText!==""){
461   - selectedText.replace("[","(");
462   - selectedText.replace("{","(");
463   - selectedText.replace("}",")");
464   - selectedText.replace("]",")");
465   - }
466   - // Formula Parsing for arguments
467   - var params = this.parseArgsInFormula(selectedText,0);
  21 + extend: 'Ext.util.Observable',
  22 +
  23 + requires: [
  24 + 'amdaModel.Constant',
  25 + 'amdaModel.Function'
  26 + ],
  27 +
  28 + alias: 'plugin.calculator',
  29 +
  30 + statics: {
  31 + constantStore: null,
  32 + functionStore: null
  33 + },
  34 +
  35 + win: null,
  36 +
  37 + constructor: function (config) {
  38 + Ext.apply(this, config);
  39 + this.callParent(arguments);
  40 + },
  41 +
  42 + init: function (cmp)
  43 + {
  44 + this.hostCmp = cmp;
  45 + this.hostCmp.on({
  46 + scope: this,
  47 + added: function () {
  48 + this.hostCmp.ownerCt.on({
  49 + render: this.onRender,
  50 + show: this.onShow,
  51 + hide: this.onHide,
  52 + scope: this});
  53 + }
  54 + });
  55 + },
  56 +
  57 + onRender: function ()
  58 + {
  59 + this.win = new Ext.Window({
  60 + width: 350,
  61 + height: 170,
  62 + x: 380, y: 0,
  63 + baseCls: 'x-panel',
  64 + title: 'Tools For ' + this.context + ' Construction',
  65 + layout: 'fit',
  66 + closable: false,
  67 + collapsible: true,
  68 + constrain: true,
  69 + floating: true,
  70 + ghost: false,
  71 + renderTo: this.hostCmp.id,
  72 + items: this.getFormConfig(),
  73 + listeners: {
  74 + boxready: function (w)
  75 + {
  76 + if (w.y + w.height > myDesktopApp.desktop.el.getHeight())
  77 + w.el.setY((myDesktopApp.desktop.el.getHeight() - w.height > 0) ? myDesktopApp.desktop.el.getHeight() - w.height : 0);
  78 + }
  79 + },
  80 + getConstrainVector: function (constrainTo) {
  81 + var me = this;
  82 + if (me.constrain || me.constrainHeader) {
  83 + constrainTo = constrainTo || (me.floatParent && me.floatParent.getTargetEl()) || me.container || me.el.getScopeParent();
  84 + return (me.constrainHeader ? me.header.el : me.el).getConstrainVector(constrainTo);
  85 + }
  86 + }
  87 + });
  88 +
  89 + //load constants store
  90 + if (!amdaUI.CalculatorUI.constantStore)
  91 + {
  92 + amdaUI.CalculatorUI.constantStore = Ext.create('Ext.data.Store', {model: 'amdaModel.Constant'});
  93 + amdaUI.CalculatorUI.constantStore.load({
  94 + scope: this,
  95 + callback: function (records, operation, success)
  96 + {
  97 + this.createAllConstantBtns();
  98 + }
  99 + });
  100 + } else
  101 + this.createAllConstantBtns();
  102 +
  103 + //load functions store
  104 + if (!amdaUI.CalculatorUI.functionStore)
  105 + {
  106 + amdaUI.CalculatorUI.functionStore = Ext.create('Ext.data.Store', {model: 'amdaModel.Function'});
  107 + amdaUI.CalculatorUI.functionStore.load({
  108 + scope: this,
  109 + callback: function (records, operation, success)
  110 + {
  111 + this.createAllFunctionBtns();
  112 + }
  113 + });
  114 + } else
  115 + this.createAllFunctionBtns();
  116 + },
  117 +
  118 + onShow: function () {
  119 + this.win.show();
  120 + var parentWin = this.hostCmp.findParentByType('window');
  121 +
  122 + if (parentWin.getId() === myDesktopApp.dynamicModules.param.id) {
  123 + this.win.setPosition(335, 10);
  124 + } else {
  125 +
  126 + var posX = parentWin.getWidth() - this.win.getWidth() - 30;
  127 + var posY = parentWin.getHeight() - this.win.getHeight() - 110 - 30/*20*/;
  128 + this.win.setPosition(posX, posY);//(420,290);
  129 + }
  130 + },
  131 +
  132 + onHide: function ()
  133 + {
  134 + this.win.hide();
  135 + },
  136 +
  137 + getFormConfig: function () {
  138 + return {
  139 + xtype: 'tabpanel',
  140 + border: false, frame: true, plain: true,
  141 + enableTabScroll: true,
  142 + defaults: {frame: true, border: false, plain: true, autoScroll: true},
  143 + activeTab: 0,
  144 + items: [{
  145 + title: 'Calculator', layout: 'column',
  146 + defaults: {xtype: 'button', columnWidth: .11},
  147 + items: this.getItems('Calculator')
  148 + }, {
  149 + title: 'Constants', xtype: 'tabpanel', //iconCls: 'tabs',
  150 + enableTabScroll: true, tabPosition: 'bottom',
  151 + defaults: {frame: true, border: false, plain: true, layout: 'column', autoScroll: true},
  152 + activeTab: 0,
  153 + id: 'calc_tab_const_id'
  154 + }, {
  155 + title: 'Functions', xtype: 'tabpanel', //iconCls: 'tabs',
  156 + enableTabScroll: true, tabPosition: 'bottom',
  157 + defaults: {frame: true, border: false, plain: true, layout: 'column', autoScroll: true},
  158 + activeTab: 0,
  159 + id: 'calc_tab_func_id'
  160 + }]
  161 + };
  162 + },
  163 +
  164 + /**
  165 + * Prompt any argument to user before processing Formula
  166 + * @param sel selected text
  167 + * @param currentBtn calculator button pressed
  168 + * @param params array of parameters
  169 + */
  170 + preProcessFormula: function (sel, currentBtn, params) {
  171 +
  172 + if (currentBtn.initialConfig.args != 0 && currentBtn.initialConfig.prompt != "") {
  173 + // Prompt for user precision and process the result using a callback
  174 + Ext.Msg.prompt('Argument', currentBtn.initialConfig.prompt, function (bt2, text) {
  175 + if (bt2 === 'ok') {
  176 + var afterParamsText = "," + text + ")";
  177 + //TODO: more than one args and prompt
  178 + this.processFormula(sel, currentBtn, params, afterParamsText);
  179 +
  180 + }
  181 + }, this);
  182 + } else {
  183 + this.processFormula(sel, currentBtn, params, ")");
  184 + }// endif prompt
  185 + },
  186 +
  187 + processFormula: function (sel, currentBtn, params, afterParamsText) {
  188 + // calculation of the required number of parameters
  189 + var nbParams = currentBtn.initialConfig.params;
  190 + var fnText = currentBtn.text.split('(');
  191 + var newConstruction = sel.beforeText + fnText[0] + "(";
  192 + // if there at least one parameter selected
  193 + if (params.length) {
  194 + for (var i = 0; i < nbParams; i++) {
  195 + if (i > 0) {
  196 + newConstruction += ",";
  197 + }
  198 + newConstruction += params[i];
  199 + }
  200 + }
  201 + // we keep position
  202 + var afterParameterPos = newConstruction.length;
  203 + newConstruction += afterParamsText;
  204 + var caretPos = newConstruction.length;
  205 + newConstruction += sel.afterText;
  206 + this.hostCmp.constructionField.setValue(newConstruction);
  207 +
  208 + // If we haven't the right number of selected parameters
  209 + if (params.length < nbParams) {
  210 + var stringParamRequired = currentBtn.initialConfig.params + " parameter(s)";
  211 + Ext.Msg.alert('Caution', 'you\'ll have to add ' + stringParamRequired + ' to apply this function',
  212 + function () {
  213 + // set Caret Position at placement of required parameter in function
  214 + this.hostCmp.constructionField.setCaretPosition(afterParameterPos);
  215 + }, this
  216 + );
  217 + } else {
  218 + // set Caret Position after inserted Text
  219 + this.hostCmp.constructionField.setCaretPosition(caretPos);
  220 + }
  221 + },
  222 +
  223 + /**
  224 + * This method construct an array of arguments into selected text
  225 + * @param selectedText the selection to parse
  226 + * @param parseIndex the index to start parsing
  227 + * @return the arguments array
  228 + */
  229 + parseArgsInFormula: function (selectedText, parseIndex) {
  230 +
  231 + if (!selectedText || selectedText == "") {
  232 + return [];
  233 + } else {
  234 + var params = [];
  235 + var startIndex = parseIndex;
  236 + var curIndex = parseIndex;
  237 + var openBrace = 0;
  238 + var sep = 0;
  239 + var closeBrace = 0;
  240 +
  241 + // while there is a separator
  242 + while (sep != -1) {
  243 + openBrace = selectedText.indexOf("(", curIndex);
  244 + sep = selectedText.indexOf(",", curIndex);
  245 + closeBrace = selectedText.indexOf(")", curIndex);
  246 +
  247 + // if there's an open bracket and no close bracket or inversely
  248 + if (openBrace != -1 && closeBrace == -1 || openBrace == -1 && closeBrace != -1) {
  249 + // invalid selection
  250 + return -1;
  251 + }
  252 +
  253 + // if there's a separator and opening brackets into selection
  254 + if (sep != -1 && openBrace != -1) {
  255 + // if brace is before separator
  256 + if (openBrace < sep) {
  257 + curIndex = this.getEndBracket(selectedText, openBrace + 1);
  258 + if (curIndex === -1) {
  259 + return -1;
  260 + }
  261 + } else {// else separator is before brace
  262 + params.push(selectedText.substring(startIndex, sep));
  263 + startIndex = curIndex = sep + 1;
  264 + }
  265 + // if there's only separators into selection
  266 + } else if (sep != -1) {
  267 + params.push(selectedText.substring(startIndex, sep));
  268 + startIndex = curIndex = sep + 1;
  269 + }
  270 + }
  271 + params.push(selectedText.substring(startIndex, selectedText.length));
  272 + return params;
  273 + }
  274 + },
  275 +
  276 + getEndBracket: function (string, indOpenBrace) {
  277 + // we search for the corresponding end brace (after open bracket)
  278 + var currentIndex = indOpenBrace;
  279 + var nextCloseBrace = 0;
  280 + var nextOpenBrace = 0;
  281 + var braceLevel = 1;
  282 + while (nextCloseBrace !== -1 && braceLevel !== 0) {
  283 + // get index of next opening bracket
  284 + nextOpenBrace = string.indexOf("(", currentIndex);
  285 + // get index of next closing bracket
  286 + nextCloseBrace = string.indexOf(")", currentIndex);
  287 + // if both exist
  288 + if (nextOpenBrace != -1 && nextCloseBrace != -1) {
  289 + // if opening bracket is before closing one
  290 + if (nextOpenBrace < nextCloseBrace) {
  291 + currentIndex = nextOpenBrace + 1;
  292 + braceLevel++;
  293 + } else { // if closing bracket is before opening one
  294 + currentIndex = nextCloseBrace + 1;
  295 + braceLevel--;
  296 + }
  297 + // if there's only a next opening bracket
  298 + } else if (nextOpenBrace != -1 && nextCloseBrace == -1) {
  299 + currentIndex = nextOpenBrace + 1;
  300 + braceLevel++;
  301 + // if there's only a next closing bracket
  302 + } else if (nextOpenBrace == -1 && nextCloseBrace != -1) {
  303 + currentIndex = nextCloseBrace + 1;
  304 + braceLevel--;
  305 + }
  306 + }
  307 + // if no level imbrication left return index after closing bracket of block else -1
  308 + return braceLevel == 0 ? currentIndex : -1;
  309 + },
  310 +
  311 + getCalculatorBtn: function ()
  312 + {
  313 + var btns = [];
  314 +
  315 + Ext.each(CalculatorData, function (c) {
  316 + btns.push({
  317 + text: c,
  318 + scope: this,
  319 + handler: function (b, e) {
  320 + // keep selection into construction field
  321 + var selection = this.hostCmp.constructionField.getSelection();
  322 + // the new value of construction field
  323 + var newConstruction = "";
  324 + // replacement of selection into construction field by text of clicked button
  325 + newConstruction = selection.beforeText + b.text;
  326 + var caretPos = newConstruction.length;
  327 + newConstruction += selection.afterText;
  328 + this.hostCmp.constructionField.setValue(newConstruction);
  329 + // set Caret Position after inserted Text
  330 + this.hostCmp.constructionField.setCaretPosition(caretPos);
  331 + }
  332 + })
  333 + },
  334 + this
  335 + );
  336 +
  337 + return btns;
  338 + },
  339 +
  340 + createAllFunctionBtns: function ()
  341 + {
  342 + this.createFunctionBtns('MathFunctions', 'Simple Maths');
  343 + this.createFunctionBtns('VectorFunctions', 'Vector Functions');
  344 + this.createFunctionBtns('TimeFunctions', 'Statistics');
  345 + this.createFunctionBtns('FunctionsSliding', 'Statistics/Sliding');
  346 + this.createFunctionBtns('PhysicsFunctions', 'Physics');
  347 + this.createFunctionBtns('AmdaFunctions', 'Special');
  348 + },
  349 +
  350 + createAllConstantBtns: function ()
  351 + {
  352 + this.createConstantBtns('Space', 'Planets Constants');
  353 + this.createConstantBtns('Physics', 'Physics Constants');
  354 + this.createConstantBtns('Units', 'Units Conversion');
  355 + },
  356 +
  357 + createConstantBtns: function (item, tabTitle)
  358 + {
  359 + var constTab = this.win.query('#calc_tab_const_id');
  360 +
  361 + if (constTab.length < 1)
  362 + return;
  363 +
  364 + switch (item)
  365 + {
  366 + case 'Space' :
  367 + amdaUI.CalculatorUI.constantStore.filter('kind', 'space');
  368 + break;
  369 + case 'Physics' :
  370 + amdaUI.CalculatorUI.constantStore.filter('kind', 'physics');
  371 + break;
  372 + case 'Units' :
  373 + amdaUI.CalculatorUI.constantStore.filter('kind', 'units');
  374 + break;
  375 + }
  376 +
  377 + var crtTab = constTab[0].add(
  378 + {
  379 + title: tabTitle,
  380 + defaults: {xtype: 'button', columnWidth: .20}
  381 + });
  382 +
  383 + amdaUI.CalculatorUI.constantStore.each(function (c) {
  384 + crtTab.add(
  385 + {
  386 + text: c.get('name'),
  387 + tooltip: c.get('units') == '' ? c.get('info') + '<br/>' + c.get('value') :
  388 + c.get('info') + '<br/>' + c.get('value') + ' ' + c.get('units'),
  389 + scope: this,
  390 + handler: function (b, e) {
  391 + // keep selection into construction field
  392 + var selection = this.hostCmp.constructionField.getSelection();
  393 + // the new value of construction field
  394 + var newConstruction = "";
  395 + // replacement of selection into construction field by text of clicked button
  396 + newConstruction = selection.beforeText + '@' + b.text;
  397 + var caretPos = newConstruction.length;
  398 + newConstruction += selection.afterText;
  399 + this.hostCmp.constructionField.setValue(newConstruction);
  400 + // set Caret Position after inserted Text
  401 + this.hostCmp.constructionField.setCaretPosition(caretPos);
  402 + }
  403 + });
  404 + }, this);
  405 +
  406 + //clear filter
  407 + amdaUI.CalculatorUI.constantStore.clearFilter();
  408 + },
  409 +
  410 + createFunctionBtns: function (item, tabTitle)
  411 + {
  412 + var funcTab = this.win.query('#calc_tab_func_id');
  413 +
  414 + if (funcTab.length < 1)
  415 + return;
  416 + var width = .20;
  417 +
  418 + switch (item)
  419 + {
  420 + case 'MathFunctions' :
  421 + amdaUI.CalculatorUI.functionStore.filter('kind', 'math');
  422 + break;
  423 + case 'AmdaFunctions' :
  424 + amdaUI.CalculatorUI.functionStore.filter('kind', 'amda');
  425 + break;
  426 + case 'TimeFunctions' :
  427 + amdaUI.CalculatorUI.functionStore.filter('kind', 'time');
  428 + break;
  429 + case 'FunctionsSliding' :
  430 + amdaUI.CalculatorUI.functionStore.filter('kind', 'sliding');
  431 + break;
  432 + case 'VectorFunctions' :
  433 + amdaUI.CalculatorUI.functionStore.filter('kind', 'vector');
  434 + break;
  435 + case 'PhysicsFunctions' :
  436 + amdaUI.CalculatorUI.functionStore.filter('kind', 'physics');
  437 + width = .25;
  438 + break;
  439 + }
  440 +
  441 + var crtTab = funcTab[0].add(
  442 + {
  443 + title: tabTitle,
  444 + defaults: {xtype: 'button', columnWidth: width}
  445 + });
  446 +
  447 + amdaUI.CalculatorUI.functionStore.each(function (f) {
  448 + crtTab.add(
  449 + {
  450 + text: f.get('name'),
  451 + args: f.get('args'),
  452 + params: f.get('params'),
  453 + prompt: f.get('prompt'),
  454 + tooltip: f.get('info_brief'),
  455 + scope: this,
  456 + handler: function (b, e) {
  457 + var selection = this.hostCmp.constructionField.getSelection();
  458 + var selectedText = selection && selection.text != "" ? Ext.util.Format.trim(selection.text) : null;
  459 + if (selectedText && selectedText !== "") {
  460 + selectedText.replace("[", "(");
  461 + selectedText.replace("{", "(");
  462 + selectedText.replace("}", ")");
  463 + selectedText.replace("]", ")");
  464 + }
  465 + // Formula Parsing for arguments
  466 + var params = this.parseArgsInFormula(selectedText, 0);
468 467 // var params = selectedText ? selectedText.split(',') : [];
469   - if (params === -1) {
470   - Ext.Msg.alert("Invalid Selection", "Action aborted");
471   - }
472   - else {
473   - // calculation of the required number of parameters
474   - var nbParams = b.initialConfig.params;
475   -
476   - if (params.length>nbParams)
477   - {
478   - // Show a dialog using config options:
479   - Ext.Msg.show({
480   - title:'Caution',
481   - msg: 'you have selected more than '+nbParams+' parameter(s) to apply this function<br>Only the first will be kept, others will be deleted',
482   - buttons: Ext.Msg.OKCANCEL,
  468 + if (params === -1) {
  469 + Ext.Msg.alert("Invalid Selection", "Action aborted");
  470 + } else {
  471 + // calculation of the required number of parameters
  472 + var nbParams = b.initialConfig.params;
  473 +
  474 + if (params.length > nbParams)
  475 + {
  476 + // Show a dialog using config options:
  477 + Ext.Msg.show({
  478 + title: 'Caution',
  479 + msg: 'you have selected more than ' + nbParams + ' parameter(s) to apply this function<br>Only the first will be kept, others will be deleted',
  480 + buttons: Ext.Msg.OKCANCEL,
483 481 // animEl: 'elId',
484   - icon: Ext.MessageBox.WARNING,
485   - fn: function(bt1){
486   - if (bt1 === 'ok'){
487   - this.preProcessFormula(selection,b, params);
488   - }
489   - },
490   - scope:this
491   - });
492   - }
493   - else
494   - {
495   - this.preProcessFormula(selection,b, params);
496   - }
497   - }
498   - }
499   - });
500   - },
501   - this
502   - );
503   - //clear filter
504   - amdaUI.CalculatorUI.functionStore.clearFilter();
505   - },
506   -
507   - getItems: function(item)
508   - {
509   - switch (item)
510   - {
511   - case 'Calculator':
512   - return this.getCalculatorBtn();
513   - default: break;
514   - }
515   - return [];
516   - }
  482 + icon: Ext.MessageBox.WARNING,
  483 + fn: function (bt1) {
  484 + if (bt1 === 'ok') {
  485 + this.preProcessFormula(selection, b, params);
  486 + }
  487 + },
  488 + scope: this
  489 + });
  490 + } else
  491 + {
  492 + this.preProcessFormula(selection, b, params);
  493 + }
  494 + }
  495 + }
  496 + });
  497 + },
  498 + this
  499 + );
  500 + //clear filter
  501 + amdaUI.CalculatorUI.functionStore.clearFilter();
  502 + },
  503 +
  504 + getItems: function (item)
  505 + {
  506 + switch (item)
  507 + {
  508 + case 'Calculator':
  509 + return this.getCalculatorBtn();
  510 + default:
  511 + break;
  512 + }
  513 + return [];
  514 + }
517 515 });
... ...