Commit d18b535dda83a475a400106be1382318be8509dd

Authored by elena
1 parent f792a3de

catalog draft + context menu small modifs

generic_data/jobs.json
... ... @@ -3,14 +3,14 @@
3 3 [{"nodeType" : "bkgWorks","text" : "Plot","id" : "resPlot-treeRootNode" },
4 4 {"nodeType" : "bkgWorks","text" : "Download","id" : "resDown-treeRootNode"},
5 5 {"nodeType" : "bkgWorks","text" : "Data Mining","id" : "resSearch-treeRootNode"},
6   - {"nodeType" : "bkgWorks","text" : "Catalog","id" : "resCatalog-treeRootNode"}
  6 + {"nodeType" : "bkgWorks","text" : "Statistics","id" : "resStatistics-treeRootNode"}
7 7 ]
8 8 },
9 9 {"nodeType" : "bkgWorks", "text" : "Jobs in Progress", "id" : "bkgjobs-treeRootNode", "children" :
10 10 [{"nodeType" : "bkgWorks","text" : "Plot","id" : "bkgPlot-treeRootNode" },
11 11 {"nodeType" : "bkgWorks","text" : "Download","id" : "bkgDown-treeRootNode"},
12 12 {"nodeType" : "bkgWorks","text" : "Data Mining","id" : "bkgSearch-treeRootNode"},
13   - {"nodeType" : "bkgWorks","text" : "Catalog","id" : "bkgCatalog-treeRootNode"}
  13 + {"nodeType" : "bkgWorks","text" : "Statistics","id" : "bkgStatistics-treeRootNode"}
14 14 ]
15 15 }
16 16 ]}
... ...
js/app/AmdaApp.js
... ... @@ -20,10 +20,17 @@ Ext.define('amdaApp.AmdaApp', {
20 20 ],
21 21  
22 22 dynamicModules: {
  23 + statistics : {
  24 + id : 'statistics-win',
  25 + icon : 'icon-statistics',
  26 + title : 'Statistics',
  27 + source : 'amdaDesktop.StatisticsModule',
  28 + useLauncher : true
  29 + },
23 30 catalog : {
24 31 id : 'catalog-win',
25 32 icon : 'icon-catalog',
26   - title : 'Generate/Edit catalogs',
  33 + title : 'Manage catalogs',
27 34 source : 'amdaDesktop.CatalogModule',
28 35 useLauncher : true
29 36 },
... ... @@ -275,12 +282,13 @@ Ext.define('amdaApp.AmdaApp', {
275 282 { name: 'Create/Modify parameter', iconCls: 'edit', module: 'param-win' },
276 283 { name: 'Plot data', iconCls: 'plot', module: 'plot-win'},
277 284 { name: 'Data mining', iconCls: 'search', module: 'search-win'},
  285 + { name: 'Statistics', iconCls: 'statistics', module: 'statistics-win'},
278 286 { name: 'Download data', iconCls: 'download_manager', module: 'down-win'},
279 287 { name: 'Upload data', iconCls: 'mydata', module: 'up-win'},
280 288 { name: 'Manage TimeTables', iconCls: 'timeTable', module: 'timetab-win' },
281 289 { name: 'TimeTables operations', iconCls: 'operations', module: 'ttsOpe-win' },
282   - { name: 'Generate/Edit catalogs', iconCls: 'catalog', module: 'catalog-win'},
283   - // { name: 'Visualize catalogs', iconCls: 'visu_catalog', module: 'visucatalog-win'},
  290 + { name: 'Manage catalogs', iconCls: 'catalog', module: 'catalog-win'},
  291 + { name: 'Visualize catalogs', iconCls: 'visu_catalog', module: 'visucatalog-win'},
284 292 { name: 'Interoperability', iconCls: 'interop', module: 'interop-win' }
285 293 ]
286 294 }),
... ...
js/app/controllers/ExplorerModule.js
... ... @@ -23,6 +23,7 @@ Ext.define('amdaDesktop.ExplorerModule', {
23 23 'amdaModel.AliasNode',
24 24 'amdaModel.TimeTableNode',
25 25 'amdaModel.CatalogNode',
  26 + 'amdaModel.StatisticsNode', // singleton; not shown in the tree
26 27 'amdaModel.sharedTimeTableNode',
27 28 'amdaModel.MyDataParamNode',
28 29 'amdaModel.MyDataNode',
... ... @@ -35,7 +36,8 @@ Ext.define('amdaDesktop.ExplorerModule', {
35 36 'amdaModel.Plot',
36 37 'amdaModel.Download',
37 38 'amdaModel.TimeTable',
38   - 'amdaModel.Catalog',
  39 + 'amdaModel.Catalog',
  40 + 'amdaModel.Statistics',
39 41 'amdaModel.FileObject',
40 42 'amdaModel.FileParamObject',
41 43 'amdaModel.FilterInfo'
... ...
js/app/controllers/StatisticsModule.js 0 โ†’ 100644
... ... @@ -0,0 +1,45 @@
  1 +/**
  2 + * Project  AMDA-NG
  3 + * Name StatisticsModule.js
  4 + * @class amdaDesktop.StatisticsModule
  5 + * @extends amdaDesktop.InteractiveModule
  6 + * @brief Statistics Module controller definition
  7 + * @author elena
  8 + */
  9 +
  10 +Ext.define('amdaDesktop.StatisticsModule', {
  11 + extend: 'amdaDesktop.InteractiveModule',
  12 +
  13 + requires: [
  14 + 'amdaUI.StatisticsUI'
  15 + ],
  16 +
  17 + contentId : 'statisticsUI',
  18 +
  19 + /**
  20 + * @cfg {String} data models
  21 + * @required
  22 + */
  23 + nodeDataModel : 'amdaModel.StatisticsNode',
  24 + objectDataModel : 'amdaModel.Statistics',
  25 + /**
  26 + * @cfg {String} window definitions
  27 + * @required
  28 + */
  29 + width : 550,
  30 + height: 550,
  31 + uiType : 'panelStatistics',
  32 + helpTitle : 'Help on Statistics Module',
  33 + helpFile : 'statisticsHelp',
  34 + /**
  35 + * @override
  36 + */
  37 + createWindow : function() {
  38 + if (!this.linkedNode){
  39 + this.setLinkedNode(amdaModel.StatisticsNode);
  40 + }
  41 + this.callParent(arguments);
  42 + },
  43 +
  44 +
  45 +});
... ...
js/app/models/AliasNode.js
... ... @@ -52,14 +52,7 @@ Ext.define('amdaModel.AliasNode', {
52 52  
53 53 return menuItems;
54 54 },
55   -
56   - getAllContextMenuItems: function(){
57   - return this.allMenuItems();
58   - },
59   -
60   - getMultiContextMenuItems: function(){
61   - return this.allMenuMultiItems(amdaModel.AliasNode.objectName);
62   - },
  55 +
63 56  
64 57 create: function(alias, param) {
65 58 AmdaAction.createObject({name: alias, param: param,
... ...
js/app/models/BkgJobNode.js
... ... @@ -6,11 +6,6 @@
6 6 * @brief Basic Model of Node corresponding to Amda processes in background
7 7 * @author elena
8 8 * @version $Id: BkgJobNode.js 1963 2013-12-06 17:50:37Z elena $
9   - * @todo
10   - *******************************************************************************
11   - * FT Id : Date : Name - Description
12   - *******************************************************************************
13   - * : :08/07/2011: elena creation
14 9 */
15 10  
16 11 Ext.define('amdaModel.BkgJobNode', {
... ... @@ -25,19 +20,19 @@ Ext.define('amdaModel.BkgJobNode', {
25 20 PLOT: 'request',//'plot',
26 21 CONDITION: 'condition',
27 22 DOWNLOAD: 'download',
28   - CATALOG: 'catalog'
  23 + STATISTICS: 'statistics'
29 24 },
30 25 JOB_ROOT_NODE: {
31 26 PLOT: 'bkgPlot-treeRootNode',
32 27 CONDITION: 'bkgSearch-treeRootNode',
33 28 DOWNLOAD: 'bkgDown-treeRootNode',
34   - CATALOG: 'bkgCatalog-treeRootNode'
  29 + STATISTICS: 'bkgStatistics-treeRootNode'
35 30 },
36 31 RES_ROOT_NODE: {
37 32 PLOT: 'resPlot-treeRootNode',
38 33 CONDITION: 'resSearch-treeRootNode',
39 34 DOWNLOAD: 'resDown-treeRootNode',
40   - CATALOG: 'resCatalog-treeRootNode'
  35 + STATISTICS: 'resStatistics-treeRootNode'
41 36 },
42 37 STATUS_LIST: {
43 38 IN_PROGRESS: 'in_progress',
... ... @@ -225,12 +220,18 @@ Ext.define('amdaModel.BkgJobNode', {
225 220 var obj = null;
226 221 switch (this.get('jobType'))
227 222 {
228   - case 'condition' :
  223 + case 'condition' :
229 224 obj = Ext.create('amdaModel.Search',
230 225 {name: result.name,
231 226 resultId : result.result,
232 227 folderId : result.folder});
233 228 break;
  229 + case 'statistics' :
  230 + obj = Ext.create('amdaModel.Statistics',
  231 + {name: result.name,
  232 + resultId : result.result,
  233 + folderId : result.folder});
  234 + break;
234 235 case 'request' :
235 236 obj = Ext.create('amdaModel.Plot',
236 237 {name: result.name, format: result.format,
... ... @@ -355,8 +356,8 @@ Ext.define('amdaModel.BkgJobNode', {
355 356 case amdaModel.BkgJobNode.JOB_TYPES.DOWNLOAD:
356 357 rootNodeId = amdaModel.BkgJobNode.JOB_ROOT_NODE.DOWNLOAD;
357 358 break;
358   - case amdaModel.BkgJobNode.JOB_TYPES.CATALOG:
359   - rootNodeId = amdaModel.BkgJobNode.JOB_ROOT_NODE.CATALOG;
  359 + case amdaModel.BkgJobNode.JOB_TYPES.STATISTICS:
  360 + rootNodeId = amdaModel.BkgJobNode.JOB_ROOT_NODE.STATISTICS;
360 361 break;
361 362 default:
362 363 break;
... ... @@ -373,8 +374,8 @@ Ext.define('amdaModel.BkgJobNode', {
373 374 case amdaModel.BkgJobNode.JOB_TYPES.DOWNLOAD:
374 375 rootNodeId = amdaModel.BkgJobNode.RES_ROOT_NODE.DOWNLOAD;
375 376 break;
376   - case amdaModel.BkgJobNode.JOB_TYPES.CATALOG:
377   - rootNodeId = amdaModel.BkgJobNode.RES_ROOT_NODE.CATALOG;
  377 + case amdaModel.BkgJobNode.JOB_TYPES.STATISTICS:
  378 + rootNodeId = amdaModel.BkgJobNode.RES_ROOT_NODE.STATISTICS;
378 379 break;
379 380 default:
380 381 break;
... ...
js/app/models/Catalog.js
... ... @@ -14,9 +14,7 @@ Ext.define('amdaModel.Catalog', {
14 14 extend: 'amdaModel.TimeTable',
15 15  
16 16 fields : [
17   - { name: 'parameter' },
18   - { name: 'timeTables' }//,
19   -// { name: 'timesrc', type: 'string', defaultValue : "TimeTable" }
  17 + { name: 'parameters' }
20 18 ],
21 19  
22 20 getJsonValues : function (hasId) {
... ... @@ -25,7 +23,7 @@ Ext.define('amdaModel.Catalog', {
25 23 values.id = this.get('id');
26 24 }
27 25  
28   - values.timesrc = 'TimeTable';
  26 + values.timesrc = this.get('timesrc');
29 27 values.name = this.get('name');
30 28 values.created = this.get('created');
31 29  
... ... @@ -40,8 +38,7 @@ Ext.define('amdaModel.Catalog', {
40 38 values.folderId = this.get('folderId');
41 39 values.nbIntervals = this.get('nbIntervals');
42 40 values.cacheToken = this.get('cacheToken');
43   - values.parameter = this.get('parameter');
44   - values.timeTables = this.get('timetable');
  41 + values.parameters = this.get('parameters');
45 42 values.leaf = true;
46 43 values.nodeType = amdaModel.CatalogNode.nodeType;
47 44 return values;
... ...
js/app/models/CatalogNode.js
... ... @@ -9,7 +9,7 @@
9 9  
10 10 Ext.define('amdaModel.CatalogNode', {
11 11  
12   - extend: 'amdaModel.ExecutableNode',
  12 + extend: 'amdaModel.TimeTableNode',
13 13  
14 14 statics: {
15 15 nodeType: 'catalog',
... ... @@ -23,6 +23,45 @@ Ext.define('amdaModel.CatalogNode', {
23 23 this.set('ownerTreeId',amdaUI.ExplorerUI.RESRC_TAB.TREE_ID);
24 24 this.set('objectDataModel',amdaModel.Catalog.$className);
25 25 if (this.get('leaf')) this.set('iconCls', 'icon-catalog');
  26 + },
  27 +
  28 + localMenuItems : function() {
  29 + var menuItems =
  30 + [/*{
  31 + fnId : 'dire-shareNode',
  32 + text : 'Share content',
  33 + hidden : true
  34 + },{
  35 + fnId : 'leaf-shareLeaf',
  36 + text : 'Share '+this.self.objectName,
  37 + hidden : true
  38 + },*/{
  39 + fnId : 'leaf-download',
  40 + text : 'Download '+ this.self.objectName,
  41 + hidden : true
  42 + }/*,{
  43 + fnId : 'leaf-operations',
  44 + text : 'Operations',
  45 + hidden : true
  46 + }*/];
  47 +
  48 + return menuItems;
  49 + },
  50 +
  51 + localMultiMenuItems : function() {
  52 + var menuItems =
  53 + [/*{
  54 + fnId : 'mult-shareMulti',
  55 + text : 'Share selected '+this.self.objectName+'s'
  56 + },*/{
  57 + fnId : 'mult-downloadMulti',
  58 + text : 'Download selected '+this.self.objectName+'s'
  59 + }/*,{
  60 + fnId : 'mult-operationsMulti',
  61 + text : 'Operations'
  62 + }*/];
  63 +
  64 + return menuItems;
26 65 }
27   -
  66 +
28 67 });
... ...
js/app/models/DerivedParamNode.js
... ... @@ -53,15 +53,11 @@ Ext.define('amdaModel.DerivedParamNode', {
53 53  
54 54 getAllContextMenuItems: function(){
55 55  
56   - var menuItems = this.allMenuItems(amdaModel.DerivedParamNode.objectName);
  56 + var menuItems = this.allMenuItems();
57 57 var locMenuItems = this.localMenuItems();
58 58  
59 59 return Ext.Array.merge(menuItems,locMenuItems);
60   - },
61   -
62   - getMultiContextMenuItems: function(){
63   - return this.allMenuMultiItems(amdaModel.DerivedParamNode.objectName);
64   - },
  60 + },
65 61  
66 62 isParameter : function(){
67 63 return this.get('isParameter');
... ...
js/app/models/InteractiveNode.js
... ... @@ -369,7 +369,8 @@ Ext.define('amdaModel.InteractiveNode', {
369 369 * Generic part of Context Menu
370 370 *
371 371 */
372   - allMenuItems : function(src) {
  372 + allMenuItems : function() {
  373 + var src = this.self.objectName;
373 374 var menuItems =
374 375 [ {
375 376 fnId : 'root-createLeaf',
... ... @@ -402,16 +403,24 @@ Ext.define('amdaModel.InteractiveNode', {
402 403 return menuItems;
403 404 },
404 405  
405   - allMenuMultiItems : function(src) {
  406 + allMenuMultiItems : function() {
406 407 var menuMulti = [
407 408 {
408 409 fnId : 'mult-deleteMulti',
409   - text : 'Delete selected '+ src+'s'
  410 + text : 'Delete selected ' + this.self.objectName + 's'
410 411 }
411 412 ];
412 413 return menuMulti;
413 414 },
414 415  
  416 + getAllContextMenuItems: function(){
  417 + return this.allMenuItems();
  418 + },
  419 +
  420 + getMultiContextMenuItems: function(){
  421 + return this.allMenuMultiItems();
  422 + },
  423 +
415 424 /**
416 425 * default implementation
417 426 * no menu display if there's no override of this function
... ...
js/app/models/LocalParamNode.js
... ... @@ -126,11 +126,7 @@ Ext.define('amdaModel.LocalParamNode',
126 126 return menuItems;
127 127 },
128 128  
129   - getAllContextMenuItems: function()
130   - {
131   - return this.allMenuItems();
132   - },
133   -
  129 +
134 130 onMenuItemClick : function(menu,item,event)
135 131 {
136 132 switch (item.fnId)
... ...
js/app/models/MyDataParamNode.js
... ... @@ -23,7 +23,8 @@ Ext.define('amdaModel.MyDataParamNode', {
23 23 ],
24 24  
25 25 statics:{
26   - nodeType: 'myDataParam'
  26 + nodeType: 'myDataParam',
  27 + objectName : 'Parameter'
27 28 },
28 29  
29 30 constructor : function(config){
... ... @@ -75,12 +76,8 @@ Ext.define('amdaModel.MyDataParamNode', {
75 76 return menuItems;
76 77 },
77 78  
78   - getAllContextMenuItems: function(){
79   -
80   - var menuItems = this.allMenuItems('Parameter');
81   - var locMenuItems = this.localMenuItems();
82   -
83   - return Ext.Array.merge(menuItems,locMenuItems);
  79 + getAllContextMenuItems: function(){
  80 + return this.localMenuItems();
84 81 },
85 82  
86 83 onMenuItemClick : function(menu,item,event) {
... ...
js/app/models/PlotNode.js
... ... @@ -72,14 +72,7 @@ Ext.define('amdaModel.PlotNode', {
72 72 return menuMulti;
73 73 },
74 74  
75   - getAllContextMenuItems: function(){
76   - return this.allMenuItems();
77   - },
78   -
79   - getMultiContextMenuItems: function(){
80   - return this.allMenuMultiItems();
81   - },
82   -
  75 +
83 76 onMenuItemClick : function(menu,item,event) {
84 77 // fnId parsing :
85 78 var fnId = Ext.util.Format.substr(item.fnId, 5, item.fnId.length);
... ...
js/app/models/SearchNode.js
... ... @@ -70,14 +70,7 @@ Ext.define('amdaModel.SearchNode', {
70 70 return menuMulti;
71 71 },
72 72  
73   - getAllContextMenuItems: function(){
74   - return this.allMenuItems();
75   - },
76   -
77   - getMultiContextMenuItems: function(){
78   - return this.allMenuMultiItems();
79   - },
80   -
  73 +
81 74 onMenuItemClick : function(menu,item,event) {
82 75 // fnId parsing :
83 76 var fnId = Ext.util.Format.substr(item.fnId, 5, item.fnId.length);
... ...
js/app/models/Statistics.js 0 โ†’ 100644
... ... @@ -0,0 +1,75 @@
  1 +/**
  2 + * Project : AMDA-NG
  3 + * Name : Statistics.js
  4 + * Description : Statistics Object Definition
  5 + * @class amdaModel.Statistics
  6 + * @extends amdaModel.TimeTable
  7 + * @author elena
  8 + */
  9 +
  10 +
  11 +
  12 +Ext.define('amdaModel.Statistics', {
  13 +
  14 + extend: 'amdaModel.AmdaTimeObject',
  15 +
  16 + fields : [
  17 + { name: 'parameter' } ,
  18 + { name: 'description' }
  19 + // { name: 'timesrc', type: 'string'}
  20 + ],
  21 +
  22 + getJsonValues : function (hasId) {
  23 + var values = new Object();
  24 + if (hasId) {
  25 + values.id = this.get('id');
  26 + }
  27 +
  28 + values.timesrc = this.get('timesrc');
  29 + values.name = 'test'; //this.get('name');
  30 +
  31 +
  32 + if (this.get('description').match(/[a-z,0-9]/gi) != null) {
  33 + values.description = this.get('description');
  34 + }
  35 +// if (this.get('history').match(/[a-z,0-9]/gi) != null) {
  36 +// values.history = this.get('history');
  37 +// }
  38 + values.objName = this.get('objName');
  39 + values.objFormat = this.get('objFormat');
  40 +
  41 +// values.cacheToken = this.get('cacheToken');
  42 + values.parameter = this.get('parameter');
  43 + if (values.timesrc == amdaModel.AmdaTimeObject.inputTimeSrc[0]){
  44 + // get complete timeTables collection
  45 + var timeTables = this.get('timeTables');
  46 + // init an empty array for timeTables
  47 + values.timeTables=[];
  48 + // for each interval record
  49 + Ext.Array.each(timeTables, function(item, index, all){
  50 + if (!item.$className) {
  51 + values.timeTables[index] = {timeTableName : item.timeTableName, id : item.id};
  52 + }
  53 + // get Json simplified value
  54 + else {
  55 + values.timeTables[index] = item.getJsonValues();
  56 + }
  57 + });
  58 + } else {
  59 + values.startDate = this.get('startDate');
  60 + values.stopDate = this.get('stopDate');
  61 + values.durationDay = this.get('durationDay');
  62 + values.durationHour = this.get('durationHour');
  63 + values.durationMin = this.get('durationMin');
  64 + values.durationSec = this.get('durationSec');
  65 + }
  66 +
  67 + values.leaf = true;
  68 + values.nodeType = 'statistics';
  69 +
  70 + return values;
  71 + }
  72 +
  73 +
  74 +
  75 +});
0 76 \ No newline at end of file
... ...
js/app/models/StatisticsNode.js 0 โ†’ 100644
... ... @@ -0,0 +1,40 @@
  1 +/**
  2 + * Project : AMDA-NG
  3 + * Name : StatisticsNode.js
  4 + * @class amdaModel.StatisticsNode
  5 + * @extends amdaModel.TimeTableNode
  6 + * @brief Basic Model of Node corresponding to a amda statistics operation
  7 + * @author elena
  8 + */
  9 +
  10 +Ext.define('amdaModel.StatisticsNode', {
  11 +
  12 + extend: 'amdaModel.ExecutableNode',
  13 +
  14 + singleton: true,
  15 +
  16 +
  17 + fields: [ {name : 'downloadType', type : 'string'},
  18 + {name: 'object', type: 'object'},
  19 + {name: 'realLinkedNode', type: 'amdaModel.AmdaNode'},
  20 + {name: 'moduleId', type: 'string', defaultValue:'statistics-win'},
  21 + {name: 'nodeType', type: 'string', defaultValue: 'statistics'},
  22 + {name: 'objectDataModel', type: 'string', defaultValue:'amdaModel.Statistics'},
  23 + {name: 'jobNode', type: 'string', defaultValue: 'amdaModel.BkgJobNode'}
  24 + ],
  25 +
  26 + isExecutable: function(){
  27 + return true;
  28 + }
  29 + /*,
  30 +
  31 + constructor : function(config){//
  32 + this.callParent(arguments);
  33 + this.set('nodeType',amdaModel.StatisticsNode.nodeType);
  34 + this.set('moduleId',myDesktopApp.dynamicModules.statistics.id);
  35 + this.set('ownerTreeId',amdaUI.ExplorerUI.OPE_TAB.TREE_ID);
  36 + this.set('objectDataModel',amdaModel.Statistics.$className);
  37 +// if (this.get('leaf')) this.set('iconCls', 'icon-catalog');
  38 + }
  39 + */
  40 +});
... ...
js/app/models/TimeTableNode.js
... ... @@ -60,10 +60,10 @@ Ext.define('amdaModel.TimeTableNode', {
60 60 var menuItems =
61 61 [/*{
62 62 fnId : 'mult-shareMulti',
63   - text : 'Share selected '+amdaModel.TimeTableNode.objectName+'s'
  63 + text : 'Share selected '+this.self.objectName+'s'
64 64 },*/{
65 65 fnId : 'mult-downloadMulti',
66   - text : 'Download selected '+amdaModel.TimeTableNode.objectName+'s'
  66 + text : 'Download selected '+this.self.objectName+'s'
67 67 },{
68 68 fnId : 'mult-operationsMulti',
69 69 text : 'Operations'
... ... @@ -73,18 +73,21 @@ Ext.define('amdaModel.TimeTableNode', {
73 73 },
74 74  
75 75 getAllContextMenuItems: function(){
76   -
77   - var menuItems = this.allMenuItems(amdaModel.TimeTableNode.objectName);
  76 +
  77 + var menuItems = this.allMenuItems();
78 78 var locMenuItems = this.localMenuItems();
79   - return Ext.Array.merge(menuItems,locMenuItems);
  79 +
  80 + return Ext.Array.merge(menuItems,locMenuItems);
80 81 },
81 82  
82   - getMultiContextMenuItems: function(){
83   - var multiMenu = this.allMenuMultiItems(amdaModel.TimeTableNode.objectName);
84   - var locMultiMenuItems = this.localMultiMenuItems();
85   - return Ext.Array.merge(multiMenu,locMultiMenuItems);
  83 + getMultiContextMenuItems: function(){
  84 +
  85 + var menuItems = this.allMenuMultiItems();
  86 + var locMenuItems = this.localMultiMenuItems();
  87 +
  88 + return Ext.Array.merge(menuItems,locMenuItems);
86 89 },
87   -
  90 +
88 91 onMenuItemClick : function(menu,item,event) {
89 92  
90 93 this.callParent(arguments);
... ...
js/app/views/CatalogUI.js
... ... @@ -10,103 +10,255 @@
10 10 Ext.define('amdaUI.CatalogUI', {
11 11 extend: 'Ext.container.Container',
12 12 alias: 'widget.panelCatalog',
  13 +
  14 + isCatalog : true,
13 15  
14   - requires : [
15   -// 'amdaModel.Function'
16   - ],
17   -
18   - statics : {
19   -// functionStore : null
20   - },
21   -
22 16 constructor: function(config) {
23   - this.init(config);
24   - this.callParent(arguments);
25   - // if (this.object) this.loadObject();
  17 + this.init(config);
  18 + this.callParent(arguments);;
  19 + if (this.object) this.loadObject();
26 20 },
27 21  
28   - addParam : function(ParamName,isLeaf)
29   - {
30   - var r = Ext.create('amdaModel.AmdaObject', { name: ParamName });
31   - this.paramGrid.getStore().add(r);
32   - this.paramGrid.getSelectionModel().select(this.paramGrid.getStore().getCount()-1);
33   - },
34 22  
35   - addTT : function(TTname,TTid)
36   - {
37   - Ext.define('tempObject', {
38   - extend: 'Ext.data.Model',
39   - fields: [
40   - {name: 'name', type: 'string'},
41   - {name: 'hidden_id', type: 'string'}
42   - ]});
43   - var r = Ext.create('tempObject', { name:TTname, hidden_id : TTid });
44   - this.ttGrid.getStore().add(r);
45   - this.ttGrid.getSelectionModel().select(this.paramGrid.getStore().getCount()-1);
46   -
47   - },
48   -
49   - generateCatalog : function(){
50   - var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id);
51   - if (module)
52   - module.linkedNode.execute();
  23 + /**
  24 + * set params description into this.object
  25 + */
  26 + setParamInfo : function(parameters) {
  27 +
  28 + var params = [];
  29 + Ext.Array.each(parameters, function(item, index) {
  30 + params[index] = item;
  31 + }, this);
  32 +
  33 + this.object.set('parameters', params);
  34 +
53 35 },
54 36  
55 37 /**
56 38 * update this.object from form
57   - */
  39 + */
  40 + updateObject : function(){
  41 + // get the basic form
  42 + var basicForm = this.formPanel.getForm();
  43 + var updateStatus = true;
  44 +
  45 + var fieldsWithoutName = basicForm.getFields().items;
  46 + Ext.Array.each(fieldsWithoutName, function(item, index,allItems){
  47 + if(item !== this.fieldName) {
  48 + if (!item.isValid()) {
  49 + // set update isn't allowed
  50 + updateStatus = false;
  51 + }
  52 + }
  53 + }, this);
  54 + // if the update is allowed
  55 + if (updateStatus) {
  56 + /// real object update
  57 + // update TimeTable object with the content of form
  58 + basicForm.updateRecord(this.object);
  59 + }
  60 + // return the update status
  61 + return updateStatus;
  62 + },
58 63  
59   - updateObject : function(){
60   - // get the basic form of the left
61   - var basicForm = this.formPanel.items.items[0].getForm();
62   -
63   - var formValues = basicForm.getValues();
64   - this.object.set('name',formValues.name);
65   - this.object.set('description',formValues.description);
66   -
67   - var recs = this.paramGrid.getStore().getNewRecords();
68   - var paramArr = new Array();
69   - Ext.Array.each(recs, function(rec, index,allItems){
70   - var obj = new Object();
71   - obj.param = rec.get('name');
72   - obj.function = rec.get('function');
73   - paramArr.push(obj);
74   - });
75   - this.object.set('parameter', paramArr);
  64 +
  65 + updateCount : function() {
  66 + this.object.set('nbIntervals',this.TTGrid.getStore().getTotalCount());
  67 + this.formPanel.getForm().findField('nbIntervals').setValue(this.object.get('nbIntervals'));
  68 + },
  69 +
  70 + /**
  71 + * load object catalog into this view
  72 + */
  73 + loadObject : function(){
  74 + // load object into form
  75 + this.formPanel.getForm().loadRecord(this.object);
  76 +
  77 + this.status = null;
  78 +
  79 + var me = this;
  80 +
  81 + var onAfterInit = function(result, e) {
  82 +
  83 + if (!result || !result.success)
  84 + {
  85 + if (result.message)
  86 + myDesktopApp.errorMsg(result.message);
  87 + else
  88 + myDesktopApp.errorMsg('Unknown error during catalog cache initialisation');
  89 + return;
  90 + }
  91 +
  92 +
  93 + var fields = [], columns = [], i = 2, width, index;
76 94  
77   - // hidden_id - if real 'id' - getNewRecords (and other getRecords) methods doesn't work
78   - var tts = this.ttGrid.getStore().getNewRecords();
79   - var ttArr = new Array();
80   - Ext.Array.each(tts, function(rec, index, allItems){
81   - var obj = new Object();
82   - obj.id = rec.get('hidden_id');
83   - ttArr.push(obj);
84   - });
85   - this.object.set('timetable', ttArr);
  95 + fields[0] = Ext.create('Ext.data.Field',{ name : 'start' });
  96 + fields[1] = Ext.create('Ext.data.Field',{ name : 'stop' });
  97 +
  98 + columns[0] = Ext.create('Ext.grid.column.RowNumberer');
86 99  
87   - var updateStatus = true;
  100 + columns[1] = Ext.create('Ext.grid.column.Column', { text: 'Start Time', sortable : false, dataIndex: 'start',
  101 + width : 120, menuDisabled: true });
  102 + columns[2] = Ext.create('Ext.grid.column.Column', { text: 'Stop Time', sortable : false, dataIndex: 'stop',
  103 + width : 120, menuDisabled: true });
88 104  
89   - return updateStatus;
  105 + Ext.Array.each(result.parameters, function(obj) {
  106 + index = 'param'+i.toString();
  107 + fields[i] = Ext.create('Ext.data.Field',{ name : index });
  108 + width = 50. * parseInt(obj.size);
  109 + columns[i+1] = Ext.create('Ext.grid.column.Column', { text: obj.name, sortable : false, dataIndex: index,
  110 + width : width, menuDisabled: true });
  111 + i++;
  112 + });
  113 +
  114 +
  115 + var store = Ext.create('Ext.data.Store', {
  116 + fields: fields,
  117 + autoDestroy: false,
  118 + pageSize : 200,
  119 + buffered : true,
  120 + purgePageCount: 0,
  121 + remoteSort: true,
  122 + proxy: {
  123 + type: 'direct',
  124 + api :
  125 + {
  126 + read : AmdaAction.readTTCacheIntervals
  127 + },
  128 + // remplir automatiquement tt, sharedtt , catalog, shared catalog
  129 + extraParams : {'typeTT' : 'catalog'},
  130 + reader:
  131 + {
  132 + type: 'json',
  133 + root: 'intervals',
  134 + totalProperty : 'totalCount'
  135 + }
  136 + },
  137 + listeners: {
  138 + scope : me,
  139 + load: function(store,records) {
  140 + // myDesktopApp.EventManager.fireEvent('refresh');
  141 + me.TTGrid.getView().refresh();
  142 + me.TTGrid.getSelectionModel().refresh();
  143 + me.updateCount();
  144 + //Statistical plugin
  145 + // this.fireEvent("refresh");
  146 + }
  147 + }
  148 + });
  149 +
  150 + me.TTGrid.reconfigure(store, columns);
  151 +
  152 +//
  153 +// me.TTGrid.getSelectionModel().deselectAll();
  154 +//
  155 +// // clear filters
  156 +// me.TTGrid.getStore().clearFilter(true);
  157 +//
  158 +// //clear sort
  159 +// me.TTGrid.getStore().sorters.clear();
  160 +// //me.TTGrid.getStore().sorters = new Ext.util.MixedCollection();
  161 +//
  162 + //set cache token to the Catalog object
  163 + me.object.set('cacheToken', result.token);
  164 + me.setParamInfo(result.parameters);
  165 +
  166 + me.TTGrid.getStore().load();
  167 +
  168 + me.status = result.status;
  169 +
  170 + };
  171 +
  172 + if (this.object.get('fromPlugin'))
  173 + {
  174 + if (this.object.get('objFormat') && this.object.get('objFormat') != '')
  175 + {
  176 + //From uploaded file
  177 + //AmdaAction.initTTCacheFromUploadedFile(this.object.get('objName'), this.object.get('objFormat'), onAfterInit);
  178 + }
  179 + else
  180 + {
  181 + //From tmp object (ie Search result)
  182 + AmdaAction.initTTCacheFromTmpObject(this.object.get('folderId'), this.object.get('objName'), this.isCatalog, onAfterInit);
  183 + }
  184 + }
  185 + else
  186 + {
  187 + var typeTT = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.tt.id).linkedNode.data.nodeType;
  188 + if (this.object.get('id') == '')
  189 + {
  190 + //Init empty cache
  191 + //AmdaAction.initTTCache(onAfterInit);
  192 + }
  193 + else
  194 + {
  195 + //From existing TT file
  196 + //AmdaAction.initTTCacheFromTT(this.object.get('id'), typeTT, onAfterInit);
  197 + }
  198 + }
  199 + },
  200 + checkIntervalsStatusForSave : function(onStatusOk) {
  201 + onStatusOk();
  202 + },
  203 +
  204 + /*
  205 + * save method called by Save button
  206 + */
  207 + saveProcess : function(toRename){
  208 + var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id);
  209 +
  210 + // if the name has been modified this is a creation
  211 + if (this.fclose()) {
  212 +
  213 + if (this.object.isModified('name') || this.object.get('fromPlugin')) {
  214 +
  215 + // if object already has an id : it's a 'rename' of an existing
  216 + if (this.object.get('id')){
  217 + // the context Node is the parent node of current edited one
  218 + var contextNode = module.linkedNode.parentNode;
  219 + // link a new node to the TimeTableModule
  220 + module.createLinkedNode();
  221 + // set the contextNode
  222 + module.linkedNode.set('contextNode',contextNode);
  223 + // create a new object linked
  224 + module.createObject(this.object.getJsonValues());
  225 +
  226 + var obj = module.linkedNode.get('object');
  227 + // synchronisation of objects
  228 + this.object = obj;
  229 + if (toRename) module.linkedNode.toRename = true;
  230 + }
  231 + module.linkedNode.create({callback : function() {module.linkedNode.update();}, scope : this});
  232 + } else {
  233 + //update
  234 + module.linkedNode.update();
  235 + }
  236 + }
90 237 },
91 238  
  239 + /**
  240 + * Check if changes were made before closing window
  241 + * @return true if changes
  242 + */
  243 + fclose : function() {
  244 + if (this.status == null)
  245 + return false;
  246 +
  247 + var isDirty = this.formPanel.getForm().isDirty() || (this.status.isModified) || (this.status.nbModified > 0) || (this.status.nbNew > 0);
  248 + return isDirty;
  249 + },
  250 +
  251 +
92 252 init : function (config) {
93 253  
94   -// var functions = Ext.create('Ext.data.Store', {
95   -// fields: ['id', 'name'],
96   -// data : [
97   -// {"id":"min", "name":"MIN"},
98   -// {"id":"max", "name":"MAX"},
99   -// {"id":"mean","name":"MEAN"}
100   -// ]
101   -// });
102   -
  254 + this.object = config.object;
  255 +
103 256 this.fieldName = new Ext.form.field.Text({
104   - fieldLabel: 'Name*',
  257 + fieldLabel: 'Name',
105 258 allowBlank : false,
106 259 stripCharsRe: /(^\s+|\s+$)/g,
107 260 emptyText: 'Please no spaces!',
108 261 name: 'name',
109   - anchor: '100%',
110 262 validateOnChange: false,
111 263 validateOnBlur: false,
112 264 validFlag: false,
... ... @@ -115,209 +267,78 @@ Ext.define('amdaUI.CatalogUI', {
115 267 }
116 268 });
117 269  
118   - var ttStore = Ext.create('Ext.data.Store',
119   - {
120   - fields: [ 'name', 'hidden_id']
121   - });
122   -
123   - this.ttGrid = Ext.create('Ext.grid.Panel', {
124   - title: 'Select Time Table',
125   - height: 100,
126   - store : ttStore,
127   - columns: [
128   - { xtype: 'rownumberer' },
129   - { header: "Time Table Name", dataIndex: 'name', flex:1, sortable : false, menuDisabled: true },
130   - { menuDisabled: true, width: 30, renderer: function()
131   - {
132   - return '<div class="icon-remover" style="width: 15px; height: 15px;"></div>';
133   - }
134   - }
135   - ],
136   - listeners : {
137   - render : function(o,op) {
138   - var me = this;
139   - var el = me.getEl();
140   - var dropTarget = Ext.create('Ext.dd.DropTarget', el, {
141   - ddGroup: 'explorerTree',
142   - notifyOver : function(ddSource, e, data)
143   - {
144   - if ((data.records[0].get('nodeType') == 'timeTable' || data.records[0].get('nodeType') == 'sharedtimeTable') && (data.records[0].get('leaf')))
145   - {
146   - this.valid = true;
147   - return this.dropAllowed;
148   - }
149   - this.valid = false;
150   - return this.dropNotAllowed;
151   - },
152   - notifyDrop : function(ddSource, e, data)
153   - {
154   - if (!this.valid) return false;
155   -
156   - var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id);
157   - if (module)
158   - {
159   - module.getUiContent().addTT(data.records[0].get('text'),data.records[0].get('id'));
160   - }
161   - return true;
162   - }
163   - });
164   - },
165   -
166   - cellclick : function(grid, cell, cellIndex, record){
167   - if (cellIndex == 2)
168   - grid.getStore().remove(record);
169   - }
170   - }
171   - });
172   -
173   - var store = Ext.create('Ext.data.Store',
174   - {
175   - fields: ['name', 'function']
176   - });
177   -
178   - this.paramGrid = Ext.create('Ext.grid.Panel', {
179   - title: 'Select Parameter & Apply Function',
180   - selType : 'rowmodel',
181   - height: 200,
182   - store : store,
183   - columns: [
184   - { xtype: 'rownumberer' },
185   - { header: 'parameter', dataIndex: 'name', menuDisabled : true, sortable : false },
186   - { header: 'function', dataIndex: 'function', menuDisabled : true, sortable : false,
187   - editor: {
188   - xtype: 'combo', queryMode : 'local',
189   -// emptyText : 'please click to select function',
190   - store: [ 'min', 'max', 'mean' ],
191   - triggerAction: 'all',
192   -// lazyInit: false,
193   - listeners: {
194   - focus: function(obj) {
195   - obj.expand();
196   - }
197   - }
198   - },
199   - renderer: function(v)
200   - {
201   - if(v != null && v.length > 0 )
202   - return v;
203   - else
204   - return 'click to select';
205   - }
206   - },
207   - { menuDisabled : true, width: 30, renderer: function(){
208   - return '<div class="icon-remover" style="width: 15px; height: 15px;"></div>';
209   - }
210   - }
211   - ],
212   - plugins: [
213   - Ext.create('Ext.grid.plugin.CellEditing', {
214   - clicksToEdit: 1
215   - })
216   - ],
217   - listeners :
218   - {
219   - render : function(o,op)
220   - {
221   - var me = this;
222   - var el = me.body.dom;
223   - var dropTarget = Ext.create('Ext.dd.DropTarget', el, {
224   - ddGroup: 'explorerTree',
225   - notifyOver : function(ddSource, e, data)
226   - {
227   - if (data.records[0].data.nodeType == 'localParam' && data.records[0].get('notyet')) {
228   - this.valid = false;
229   - return this.dropNotAllowed;
230   - }
231   - if (((data.records[0].data.nodeType == 'localParam') ||
232   - (data.records[0].data.nodeType == 'remoteParam') ||
233   - (data.records[0].data.nodeType == 'remoteSimuParam') ||
234   - (data.records[0].data.nodeType == 'derivedParam') ||
235   - (data.records[0].data.nodeType == 'myDataParam') ||
236   - (data.records[0].data.nodeType == 'alias'))&&
237   - (data.records[0].isLeaf() || data.records[0].data.isParameter) &&
238   - !data.records[0].data.disable)
239   - {
240   - this.valid = true;
241   - return this.dropAllowed;
242   - }
243   -
244   - this.valid = false;
245   - return this.dropNotAllowed;
246   - },
247   - notifyDrop : function(ddSource, e, data)
248   - {
249   - if (!this.valid)
250   - return false;
251   - var nameToSent;
252   - switch (data.records[0].data.nodeType)
253   - {
254   - case 'localParam' :
255   - case 'remoteParam':
256   - case 'remoteSimuParam':
257   - nameToSent = data.records[0].get('id');
258   - if (data.records[0].get('alias')!= "" )
259   - var nameToSent = "#"+data.records[0].get('alias');
260   - break;
261   - case 'alias' :
262   - nameToSent = "#"+data.records[0].get('text');
263   - break;
264   - case 'derivedParam' :
265   - nameToSent = "ws_"+data.records[0].get('text');
266   - break;
267   - case 'myDataParam' :
268   - nameToSent = "wsd_"+data.records[0].get('text');
269   - break;
270   - default :
271   - return false;
272   - }
273   - var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id);
274   - if (module)
275   - {
276   - if (data.records[0].get('needsArgs') && !data.records[0].get('isSpectra')) {
277   - module.getUiContent().fireEvent('openParamEditor',nameToSent);
278   - }
279   - else {
280   - module.addParam(nameToSent,true);
281   - }
282   - }
283   - return true;
284   - }
285   - });
286   - },
287   - cellclick : function(grid, cell, cellIndex, record){
288   - if (cellIndex == 3)
289   - grid.getStore().remove(record);
290   - }
291   - }
292   - });
293   -
294   - this.catalogGrid = Ext.create('Ext.grid.Panel', {
295   - title: 'Catalog',
296   - height: 500,
  270 +
  271 + this.TTGrid = Ext.create('Ext.grid.Panel', {
  272 +// title: 'Catalog',
  273 + height: 530,
297 274 columns: [
298 275 { text: '', dataIndex: '' }
299 276  
300   - ]
  277 + ],
  278 + frame: true,
  279 + dockedItems: [{
  280 + xtype: 'toolbar',
  281 + items: [{
  282 + iconCls: 'icon-add',
  283 + scope: this,
  284 + handler: function(){
  285 +// cellEditing.cancelEdit();
  286 +//
  287 +// var selection = this.TTGrid.getView().getSelectionModel().getSelection()[0];
  288 +// var row = 0;
  289 +// if (selection)
  290 +// row = store.indexOf(selection) + 1;
  291 +// this.TTGrid.getSelectionModel().deselectAll();
  292 +//
  293 +// var me = this;
  294 +// AmdaAction.addTTCacheInterval({'index' : row}, function (result, e) {
  295 +// this.status = result.status;
  296 +// this.TTGrid.getStore().reload({
  297 +// callback : function(records, options, success) {
  298 +// me.TTGrid.getView().bufferedRenderer.scrollTo(row, false, function() {
  299 +// me.TTGrid.getView().select(row);
  300 +// cellEditing.startEditByPosition({row: row, column: 1});
  301 +// }, me);
  302 +// }
  303 +// });
  304 +// }, this);
  305 + }
  306 + }, {
  307 + iconCls: 'icon-delete',
  308 + disabled: true,
  309 + itemId: 'delete',
  310 + scope: this,
  311 + handler: function(){
  312 +// var selection = this.TTGrid.getView().getSelectionModel().getSelection()[0];
  313 +// if (selection) {
  314 +// var rowId = selection.get('cacheId');
  315 +// this.TTGrid.getSelectionModel().deselectAll();
  316 +// AmdaAction.removeTTCacheIntervalFromId(rowId, function (result, e) {
  317 +// this.status = result.status;
  318 +// this.TTGrid.getStore().reload();
  319 +// }, this);
  320 +// }
  321 + }
  322 + }]
  323 + }]
301 324 });
302 325  
303 326 this.formPanel = Ext.create('Ext.form.Panel', {
304   - height: 550,
305   - width: 800,
306   - layout: 'border',
307   - defaults: { layout: 'fit', border: false },
  327 + region : 'center',
  328 + layout: 'hbox',
  329 + bodyStyle: {background : '#dfe8f6'},
  330 + defaults: { border : false, align: 'stretch', bodyStyle: {background : '#dfe8f6'}, padding: '3'},
308 331 fieldDefaults: { labelWidth: 80, labelAlign : 'top' },
309 332 items: [
310 333 {
311   - xtype: 'form',
312   - region: 'center',
  334 + xtype: 'form',
313 335 flex: 1,
314 336 buttonAlign: 'left',
315   - bodyStyle: {background : '#dfe8f6'},
316   - padding: '5 5 5 5',
  337 +// title : 'Information',
317 338 layout: {type: 'vbox', pack: 'start', align: 'stretch'},
318 339 items : [
319   - this.fieldName,
320   - {
  340 + this.fieldName,
  341 + {
321 342 xtype: 'fieldcontainer',
322 343 layout: 'hbox',
323 344 items: [
... ... @@ -328,65 +349,111 @@ Ext.define(&#39;amdaUI.CatalogUI&#39;, {
328 349 },
329 350 { xtype: 'splitter' },
330 351 { xtype:'textfield', fieldLabel: 'Intervals', name: 'nbIntervals', disabled: true}
331   - ]
332   - },
333   - {
334   - xtype: 'textarea',
335   - name: 'description',
336   - fieldLabel: 'Description',
337   -// anchor: '100% 50%'
338   - },
339   -
340   - this.paramGrid,
341   - this.ttGrid
342   - ],
343   - fbar:[
344   - {
345   - type: 'button',
346   - text: 'Generate Catalog',
347   - scope : this,
348   - handler: function(button){
349   - // update object with user's values
350   - // if the return is true (object had been updated)
351   - // if(this.updateObject()){
352   - this.updateObject();
353   - this.generateCatalog();
354   - // }
355   - }
356   - },
357   - {
358   - type: 'button',
359   - text: 'Reset'
360   - }
361   - ]
  352 + ]
  353 + },
  354 + {
  355 + xtype: 'textarea',
  356 + name: 'description',
  357 + fieldLabel: 'Description',
  358 + height: 200
  359 + },
  360 + {
  361 + xtype: 'component',
  362 + height: 180
  363 + }
  364 + ],
  365 + fbar:[
  366 + {
  367 + type: 'button',
  368 + text: 'Save',
  369 + scope : this,
  370 + handler: function () {
  371 + if (this.updateObject()){
  372 +
  373 + var basicForm = this.formPanel.getForm();
  374 + // if there's at least one record in the store of TTGrid
  375 + if (this.TTGrid.getStore().getTotalCount() > 0) {
  376 + // update TimeTable object which the content of form
  377 + basicForm.updateRecord(this.object);
  378 +
  379 + var me = this;
  380 + this.checkIntervalsStatusForSave(function () {
  381 + //Name validation
  382 + var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id);
  383 + if (!module)
  384 + return;
  385 + module.linkedNode.isValidName(me.fieldName.getValue(), function (res) {
  386 + if (!res)
  387 + {
  388 + me.fieldName.validFlag = 'Error during object validation';
  389 + myDesktopApp.errorMsg(me.fieldName.validFlag);
  390 + me.fieldName.validate();
  391 + return;
  392 + }
  393 +
  394 + if (!res.valid)
  395 + {
  396 + if (res.error)
  397 + {
  398 + if (res.error.search('subtree') != -1) {
  399 + Ext.MessageBox.show({title:'Warning',
  400 + msg: res.error+'<br/>Do you want to overwrite it?',
  401 + width: 300,
  402 + buttons: Ext.MessageBox.OKCANCEL,
  403 + fn : me.overwriteProcess,
  404 + icon: Ext.MessageBox.WARNING,
  405 + scope : me
  406 + });
  407 + me.fieldName.validFlag = true;
  408 + }
  409 + else
  410 + me.fieldName.validFlag = res.error;
  411 + }
  412 + else
  413 + {
  414 + me.fieldName.validFlag = 'Invalid object name';
  415 + myDesktopApp.errorMsg(me.fieldName.validFlag);
  416 + }
  417 + me.fieldName.validate();
  418 + return;
  419 + }
  420 +
  421 + me.fieldName.validFlag = true;
  422 + me.fieldName.validate();
  423 + me.saveProcess(false);
  424 + });
  425 + });
  426 + } else {
  427 + // warning:
  428 + Ext.Msg.alert('No intervals', 'Your time table is invalid, <br>you must have at least one interval');
  429 + }
  430 + }
  431 + }
  432 + },{
  433 + type: 'button',
  434 + text: 'Share',
  435 + disabled: true
  436 + },
  437 + {
  438 + type: 'button',
  439 + text: 'Visualize'
  440 + }
  441 + ]
362 442 }, {
363   - xtype: 'form',
364   - region: 'east',
  443 + xtype: 'form',
365 444 bodyStyle: {background : '#dfe8f6'},
366   - padding: '5 5 5 5',
  445 +// padding: '3',
367 446 flex: 2,
368 447 items : [
369   - this.catalogGrid
370   - ],
371   - fbar:[
372   - {
373   - type: 'button',
374   - text: 'Save'
375   - },{
376   - type: 'button',
377   - text: 'Share',
378   - disabled: true
379   - },
380   - {
381   - type: 'button',
382   - text: 'Visualize'
383   - }
384   - ]
  448 + this.TTGrid
  449 + ]
385 450 }
386 451 ]
387 452 });
388 453  
389   -
  454 + this.TTGrid.getSelectionModel().on('selectionchange', function(selModel,selections){
  455 + this.TTGrid.down('#delete').setDisabled(selections.length === 0);
  456 + }, this);
390 457  
391 458 var myConf = {
392 459 layout: 'border',
... ...
js/app/views/StatisticsUI.js 0 โ†’ 100644
... ... @@ -0,0 +1,343 @@
  1 +/**
  2 + * Project AMDA-NG
  3 + * Name StatisticsUI.js
  4 + * @class amdaUI.statisticsUI
  5 + * @extends Ext.container.Container
  6 + * @brief Statistics Module UI definition (View)
  7 + * @author elena
  8 + */
  9 +
  10 +Ext.define('amdaUI.StatisticsUI', {
  11 + extend: 'Ext.container.Container',
  12 + alias: 'widget.panelStatistics',
  13 +
  14 + requires : [
  15 +// 'amdaModel.Function'
  16 + 'amdaUI.TimeSelectorUI'
  17 + ],
  18 +
  19 + statics : {
  20 +// functionStore : null
  21 + },
  22 +
  23 + constructor: function(config) {
  24 + this.init(config);
  25 + this.callParent(arguments);
  26 + // if (this.object) this.loadObject();
  27 + },
  28 +
  29 + addParam : function(ParamName,isLeaf)
  30 + {
  31 + var r = Ext.create('amdaModel.AmdaObject', { name: ParamName });
  32 + this.paramGrid.getStore().add(r);
  33 + this.paramGrid.getSelectionModel().select(this.paramGrid.getStore().getCount()-1);
  34 + },
  35 +
  36 + addTT : function(TTname,TTid)
  37 + {
  38 + this.timeSelector.addTT(TTname, TTid); ;
  39 +
  40 + },
  41 +
  42 + generateCatalog : function(){
  43 + var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.statistics.id);
  44 + if (module)
  45 + module.linkedNode.execute();
  46 + },
  47 +
  48 + /**
  49 + * update this.object from form
  50 + */
  51 +
  52 + updateObject : function(){
  53 + // get the basic form of the left
  54 + var basicForm = this.formPanel.items.items[0].getForm();
  55 + var updateStatus = true;
  56 +
  57 + var formValues = basicForm.getValues();
  58 + // this.object.set('name',formValues.name);
  59 + // this.object.set('description',formValues.description);
  60 +
  61 + var recs = this.paramGrid.getStore().getNewRecords();
  62 + var paramArr = new Array();
  63 + Ext.Array.each(recs, function(rec, index,allItems){
  64 + var obj = new Object();
  65 + obj.param = rec.get('name');
  66 + obj.function = rec.get('function');
  67 + paramArr.push(obj);
  68 + });
  69 + this.object.set('parameter', paramArr);
  70 +
  71 + var timeSource = formValues.timesrc_statisticsTimeSelector;
  72 +
  73 + if (timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0] // timeSource 'TimeTable'
  74 + && this.timeSelector.TTGrid.getStore().count() == 0) {
  75 + myDesktopApp.warningMsg('You\'ve chosen Time Selection `by TimeTable` but no timeTable was added!'
  76 + +'<br>You must add one or choose Time Selection `by Interval`');
  77 + return false;
  78 + }
  79 +
  80 + // basicForm.updateRecord(this.object);
  81 + this.object.set('timesrc', timeSource);
  82 + // set valid intervals into TimeTable object
  83 + if (timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0])
  84 + this.object.set('timeTables',this.timeSelector.TTGrid.getStore().data.items);
  85 +
  86 + return updateStatus;
  87 + },
  88 +
  89 + /**
  90 + * Check if changes were made before closing window
  91 + * @return true if changes
  92 + */
  93 + fclose : function() {
  94 + if (this.status == null)
  95 + return false;
  96 +
  97 + var isDirty = this.formPanel.getForm().isDirty() || (this.status.isModified) || (this.status.nbModified > 0) || (this.status.nbNew > 0);
  98 + return isDirty;
  99 + },
  100 +
  101 + /**
  102 + * View configuration
  103 + */
  104 + init : function (config) {
  105 +
  106 +// var functions = Ext.create('Ext.data.Store', {
  107 +// fields: ['id', 'name'],
  108 +// data : [
  109 +// {"id":"min", "name":"MIN"},
  110 +// {"id":"max", "name":"MAX"},
  111 +// {"id":"mean","name":"MEAN"}
  112 +// ]
  113 +// });
  114 +
  115 + this.fieldName = new Ext.form.field.Text({
  116 + fieldLabel: 'Catalog Name',
  117 + allowBlank : false,
  118 + stripCharsRe: /(^\s+|\s+$)/g,
  119 + emptyText: 'Please no spaces!',
  120 + name: 'name',
  121 +// anchor: '100%',
  122 + validateOnChange: false,
  123 + validateOnBlur: false,
  124 + validFlag: false,
  125 + validator : function() {
  126 + return this.validFlag;
  127 + }
  128 + });
  129 +
  130 + var ttStore = Ext.create('Ext.data.Store',
  131 + {
  132 + fields: [ 'name', 'hidden_id']
  133 + });
  134 +
  135 + this.timeSelector = new amdaUI.TimeSelectorUI({id: 'statisticsTimeSelector', height : 160});
  136 +
  137 + var store = Ext.create('Ext.data.Store',
  138 + {
  139 + fields: ['name', 'function']
  140 + });
  141 +
  142 + this.paramGrid = Ext.create('Ext.grid.Panel', {
  143 + title: 'Select Parameter & Apply Function',
  144 + selType : 'rowmodel',
  145 +// flex: 2,
  146 + height :250,
  147 + store : store,
  148 + columns: [
  149 + { xtype: 'rownumberer' },
  150 + { header: 'parameter', dataIndex: 'name', menuDisabled : true, sortable : false },
  151 + { header: 'function', dataIndex: 'function', menuDisabled : true, sortable : false,
  152 + editor: {
  153 + xtype: 'combo', queryMode : 'local',
  154 +// emptyText : 'please click to select function',
  155 + store: [ 'min', 'max', 'mean' ],
  156 + triggerAction: 'all',
  157 +// lazyInit: false,
  158 + listeners: {
  159 + focus: function(obj) {
  160 + obj.expand();
  161 + }
  162 + }
  163 + },
  164 + renderer: function(v)
  165 + {
  166 + if(v != null && v.length > 0 )
  167 + return v;
  168 + else
  169 + return 'click to select';
  170 + }
  171 + },
  172 + { menuDisabled : true, width: 30, renderer: function(){
  173 + return '<div class="icon-remover" style="width: 15px; height: 15px;"></div>';
  174 + }
  175 + }
  176 + ],
  177 + plugins: [
  178 + Ext.create('Ext.grid.plugin.CellEditing', {
  179 + clicksToEdit: 1
  180 + })
  181 + ],
  182 + listeners :
  183 + {
  184 + render : function(o,op)
  185 + {
  186 + var me = this;
  187 + var el = me.body.dom;
  188 + var dropTarget = Ext.create('Ext.dd.DropTarget', el, {
  189 + ddGroup: 'explorerTree',
  190 + notifyOver : function(ddSource, e, data)
  191 + {
  192 + if (data.records[0].data.nodeType == 'localParam' && data.records[0].get('notyet')) {
  193 + this.valid = false;
  194 + return this.dropNotAllowed;
  195 + }
  196 + if (((data.records[0].data.nodeType == 'localParam') ||
  197 + (data.records[0].data.nodeType == 'remoteParam') ||
  198 + (data.records[0].data.nodeType == 'remoteSimuParam') ||
  199 + (data.records[0].data.nodeType == 'derivedParam') ||
  200 + (data.records[0].data.nodeType == 'myDataParam') ||
  201 + (data.records[0].data.nodeType == 'alias'))&&
  202 + (data.records[0].isLeaf() || data.records[0].data.isParameter) &&
  203 + !data.records[0].data.disable)
  204 + {
  205 + this.valid = true;
  206 + return this.dropAllowed;
  207 + }
  208 +
  209 + this.valid = false;
  210 + return this.dropNotAllowed;
  211 + },
  212 + notifyDrop : function(ddSource, e, data)
  213 + {
  214 + if (!this.valid)
  215 + return false;
  216 + var nameToSent;
  217 + switch (data.records[0].data.nodeType)
  218 + {
  219 + case 'localParam' :
  220 + case 'remoteParam':
  221 + case 'remoteSimuParam':
  222 + nameToSent = data.records[0].get('id');
  223 + if (data.records[0].get('alias')!= "" )
  224 + var nameToSent = "#"+data.records[0].get('alias');
  225 + break;
  226 + case 'alias' :
  227 + nameToSent = "#"+data.records[0].get('text');
  228 + break;
  229 + case 'derivedParam' :
  230 + nameToSent = "ws_"+data.records[0].get('text');
  231 + break;
  232 + case 'myDataParam' :
  233 + nameToSent = "wsd_"+data.records[0].get('text');
  234 + break;
  235 + default :
  236 + return false;
  237 + }
  238 + var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.statistics.id);
  239 + if (module)
  240 + {
  241 + if (data.records[0].get('needsArgs') && !data.records[0].get('isSpectra')) {
  242 + module.getUiContent().fireEvent('openParamEditor',nameToSent);
  243 + }
  244 + else {
  245 + module.addParam(nameToSent,true);
  246 + }
  247 + }
  248 + return true;
  249 + }
  250 + });
  251 + },
  252 + cellclick : function(grid, cell, cellIndex, record){
  253 + if (cellIndex == 3)
  254 + grid.getStore().remove(record);
  255 + }
  256 + }
  257 + });
  258 +
  259 +
  260 + this.formPanel = Ext.create('Ext.form.Panel', {
  261 + region: 'center',
  262 + layout: 'hbox',
  263 +// bodyStyle: {background : '#dfe8f6'},
  264 + defaults: { bodyStyle: {background : '#dfe8f6'}, padding : '3'},
  265 + fieldDefaults: { labelWidth: 80, labelAlign : 'top' },
  266 + items: [
  267 + {
  268 + xtype: 'form',
  269 + flex : 1,
  270 + layout: {type: 'vbox', pack: 'start', align: 'stretch'},
  271 + items : [
  272 + this.paramGrid,
  273 + this.timeSelector
  274 + ]
  275 + },
  276 + {
  277 + xtype: 'form',
  278 + title: 'Additional Information',
  279 + flex : 1,
  280 + layout: {type: 'vbox', pack: 'start', align: 'stretch', padding : '3'},
  281 + items : [
  282 + this.fieldName,
  283 + {
  284 + xtype: 'textarea',
  285 + name: 'description',
  286 + fieldLabel: 'Description',
  287 + height: 200
  288 + }
  289 + ],
  290 + fbar:
  291 + [
  292 + {
  293 + type: 'button',
  294 + text: 'Generate Catalog',
  295 + scope : this,
  296 + handler: function(){
  297 + // update object with user's values
  298 + // if the return is true (object had been updated)
  299 + // if(this.updateObject()){
  300 + this.updateObject();
  301 + this.generateCatalog();
  302 + // }
  303 + }
  304 + },
  305 + {
  306 + type: 'button',
  307 + text: 'Reset',
  308 + scope : this,
  309 + handler: function() {
  310 + }
  311 + }
  312 + ]
  313 + }
  314 + ]
  315 + });
  316 +
  317 +
  318 +
  319 + var myConf = {
  320 + layout: 'border',
  321 + items: [
  322 + this.formPanel,
  323 + {
  324 + xtype: 'panel',
  325 + region: 'south',
  326 + title: 'Information',
  327 + collapsible: true,
  328 + height: 100,
  329 + autoHide: false,
  330 + bodyStyle: 'padding:5px',
  331 + iconCls: 'icon-information',
  332 + loader: {
  333 + autoLoad: true,
  334 + url: helpDir+'downloadHOWTO'
  335 + }
  336 + }
  337 + ]
  338 + };
  339 +
  340 + Ext.apply (this, Ext.apply(arguments, myConf));
  341 + }
  342 +
  343 +});
... ...
js/app/views/TabResultUI.js
... ... @@ -37,6 +37,8 @@ Ext.define(&#39;amdaUI.TabResultUI&#39;, {
37 37 break;
38 38 case 'download': var title = 'Download Results';
39 39 break;
  40 + case 'statistics': var title = 'Statistics Results';
  41 + break;
40 42 default:
41 43 }
42 44 var newConfig = {
... ... @@ -54,7 +56,7 @@ Ext.define(&#39;amdaUI.TabResultUI&#39;, {
54 56 scope : this,
55 57 beforeclose : function() {
56 58 //delete linked nodes connected to ResultModule and corresponding to this Tab
57   - var module = myDesktopApp.getLoadeModule(myDesktopApp.dynamicModules.result.id);
  59 + var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.result.id);
58 60 if (module.linkedNodes) {
59 61 var indices = new Array();
60 62 var i =0;
... ... @@ -105,6 +107,16 @@ Ext.define(&#39;amdaUI.ResultItem&#39;, {
105 107 this);
106 108 },
107 109  
  110 + saveCatalog: function(folderId,ttName) {
  111 + this.linkedNode = Ext.create('amdaModel.CatalogNode',{leaf : true});
  112 + AmdaAction.getTmpObject(
  113 + folderId,
  114 + ttName,
  115 + this.linkedNode.get('nodeType'),
  116 + this.getResultCallback,
  117 + this);
  118 + },
  119 +
108 120 getResultCallback : function(result,remoteEvent){//result, e) {
109 121 var t = remoteEvent.getTransaction();
110 122 //AKKA - catch error
... ... @@ -120,8 +132,8 @@ Ext.define(&#39;amdaUI.ResultItem&#39;, {
120 132 return;
121 133 }
122 134  
123   - var paramObj = Ext.create(this.linkedNode.get('objectDataModel'), result);
124   - paramObj.set('fromPlugin',true);
  135 + var paramObj = Ext.create(this.linkedNode.get('objectDataModel'), result);
  136 + paramObj.set('fromPlugin',true);
125 137 paramObj.set('intervals',result.intervals);
126 138 // set parameter into node
127 139 this.linkedNode.set('object',paramObj);
... ... @@ -130,7 +142,7 @@ Ext.define(&#39;amdaUI.ResultItem&#39;, {
130 142 myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.result.id, true, function (module) {
131 143 module.setLinkedNode(me.linkedNode);
132 144 // Edition of parameter into parameter Module
133   - me.linkedNode.editInModule();
  145 + me.linkedNode.editInModule();
134 146 });
135 147 },
136 148  
... ... @@ -251,6 +263,35 @@ Ext.define(&#39;amdaUI.ResultItem&#39;, {
251 263 }
252 264 ]
253 265 };
  266 + var configCat = {
  267 + intId : config.title,
  268 + height : height,
  269 + title: jobtitle,
  270 + collapsible: true,
  271 + defaultType: 'button',
  272 + items :[
  273 + {
  274 + xtype: 'label',
  275 + text: 'Catalog '
  276 + },
  277 + {
  278 + text: 'Edit/Save',
  279 + scope : this,
  280 + handler: function() {
  281 + this.saveCatalog(config.folderId,config.resultId);
  282 + }
  283 + },
  284 + {
  285 + text: 'Delete',
  286 + scope : this,
  287 + handler: function() {
  288 + this.delete(config.processId);
  289 + this.ownerCt.remove(this);
  290 + }
  291 + }
  292 + ]
  293 + };
  294 +
254 295 //TODO make this properly
255 296  
256 297 var configPlot = {
... ... @@ -329,6 +370,9 @@ Ext.define(&#39;amdaUI.ResultItem&#39;, {
329 370 case 'condition' :
330 371 Ext.apply(this, configTT);
331 372 break;
  373 + case 'statistics' :
  374 + Ext.apply(this, configCat);
  375 + break;
332 376 case 'request' :
333 377 Ext.apply(this, configPlot);
334 378 break;
... ...
js/app/views/TimeTableUI.js
... ... @@ -30,6 +30,7 @@ Ext.define(&#39;amdaUI.TimeTableUI&#39;, {
30 30 },
31 31  
32 32 status: null,
  33 + isCatalog : false,
33 34  
34 35 constructor: function(config) {
35 36 this.init(config);
... ... @@ -116,7 +117,7 @@ Ext.define(&#39;amdaUI.TimeTableUI&#39;, {
116 117 else
117 118 {
118 119 //From tmp object (ie Search result)
119   - AmdaAction.initTTCacheFromTmpObject(this.object.get('folderId'), this.object.get('objName'), onAfterInit);
  120 + AmdaAction.initTTCacheFromTmpObject(this.object.get('folderId'), this.object.get('objName'), this.isCatalog, onAfterInit);
120 121 }
121 122 }
122 123 else
... ...
js/resources/css/amda.css
... ... @@ -79,6 +79,10 @@
79 79 background-image:url( ../images/16x16/search.png ) !important;
80 80 }
81 81  
  82 +.icon-statistics {
  83 + background-image:url( ../images/16x16/statistics.png ) !important;
  84 +}
  85 +
82 86 .icon-manage-ws {
83 87 background-image:url( ../images/16x16/wsManager.png ) !important;
84 88 }
... ... @@ -385,3 +389,8 @@ p + p {
385 389 font-style: italic !important;
386 390 font-weight: bold !important;
387 391 }
  392 +
  393 +.x-item-disabled .x-form-item-label {
  394 + filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100) !important;
  395 + opacity: 1.0 !important;
  396 +}
... ...
js/resources/images/16x16/statistics.png 0 โ†’ 100644

738 Bytes

js/resources/images/16x16/visu_catalog.png 0 โ†’ 100644

838 Bytes

js/resources/images/64x64/statistics.png 0 โ†’ 100644

1.49 KB

js/resources/images/64x64/visu_catalog.png 0 โ†’ 100644

3.68 KB

php/classes/AmdaAction.php
... ... @@ -581,7 +581,10 @@ class AmdaAction {
581 581 switch ($nodeType) {
582 582 case 'timeTable' :
583 583 $objectMgr = new TimeTableMgr();
584   - break;
  584 + break;
  585 + case 'catalog' :
  586 + $objectMgr = new CatalogMgr();
  587 + break;
585 588 default:
586 589 return array("error" => $nodeType." NOT_IMPLEMENTED_YET");
587 590 }
... ... @@ -631,6 +634,9 @@ class AmdaAction {
631 634 break;
632 635 case 'timeTable' :
633 636 $objectMgr = new TimeTableMgr();
  637 + break;
  638 + case 'catalog' :
  639 + $objectMgr = new CatalogMgr();
634 640 break;
635 641 case 'condition' :
636 642 case 'request' :
... ... @@ -667,6 +673,9 @@ class AmdaAction {
667 673 break;
668 674 case 'timeTable' :
669 675 $objectMgr = new TimeTableMgr();
  676 + break;
  677 + case 'catalog' :
  678 + $objectMgr = new Catalog();
670 679 break;
671 680 case 'condition' :
672 681 case 'request' :
... ... @@ -698,6 +707,9 @@ class AmdaAction {
698 707 break;
699 708 case 'timeTable' :
700 709 $objectMgr = new TimeTableMgr();
  710 + break;
  711 + case 'catalog' :
  712 + $objectMgr = new CatalogMgr();
701 713 break;
702 714 case 'condition' :
703 715 case 'request' :
... ... @@ -726,7 +738,10 @@ class AmdaAction {
726 738 break;
727 739 case 'timeTable' :
728 740 $objectMgr = new TimeTableMgr();
729   - break;
  741 + break;
  742 + case 'catalog' :
  743 + $objectMgr = new CatalogMgr();
  744 + break;
730 745 case 'condition' :
731 746 case 'request' :
732 747 $objectMgr = new RequestMgr($obj->nodeType);
... ... @@ -747,8 +762,12 @@ class AmdaAction {
747 762 $objectMgr = new DerivedParamMgr($obj->nodeType);
748 763 break;
749 764 case 'timeTable' :
  765 + case 'sharedtimeTable' :
750 766 $objectMgr = new TimeTableMgr();
751 767 break;
  768 + case 'catalog' :
  769 + $objectMgr = new CatalogMgr();
  770 + break;
752 771 case 'condition' :
753 772 case 'request' :
754 773 $objectMgr = new RequestMgr($obj->nodeType);
... ... @@ -927,15 +946,27 @@ class AmdaAction {
927 946 return $cacheMgr->initTTCache();
928 947 }
929 948  
  949 +// public function initCatalogGridFromTmpObject($folderId, $name)
  950 +// {
  951 +// $objMgr = new CatalogMgr();
  952 +// return $objMgr->initCatalogGridFromTmpObject($folderId, $name);
  953 +// }
  954 +
930 955 public function initTTCacheFromTT($id, $type)
931 956 {
932 957 $cacheMgr = new TimeTableCacheMgr();
933 958 return $cacheMgr->initFromTT($id, $type);
934 959 }
935 960  
936   - public function initTTCacheFromTmpObject($folderId, $name)
  961 + public function initTTCacheFromTmpObject($folderId, $name, $isCatalog = false)
937 962 {
938   - $cacheMgr = new TimeTableCacheMgr();
  963 + error_reporting(E_ERROR | E_WARNING | E_PARSE);
  964 + if (!$isCatalog) $cacheMgr = new TimeTableCacheMgr();
  965 +
  966 + else $cacheMgr = new CatalogCacheMgr();
  967 +
  968 +
  969 +
939 970 return $cacheMgr->initFromTmpObject($folderId, $name);
940 971 }
941 972  
... ... @@ -947,7 +978,9 @@ class AmdaAction {
947 978  
948 979 public function readTTCacheIntervals($o)
949 980 {
950   - $cacheMgr = new TimeTableCacheMgr();
  981 + if ($o->typeTT == 'catalog') $cacheMgr = new CatalogCacheMgr();
  982 + else $cacheMgr = new TimeTableCacheMgr();
  983 +
951 984 return $cacheMgr->getIntervals($o->start,$o->limit,$o->sort,$o->filter);
952 985 }
953 986  
... ... @@ -1201,8 +1234,8 @@ class AmdaAction {
1201 1234 //AKKA - New action to clean user WS
1202 1235 public function cleanUserWS()
1203 1236 {
1204   - require_once(INTEGRATION_SRC_DIR."RequestManager.php");
1205   - return $this->executeRequest($obj, FunctionTypeEnumClass::PROCESSCLEAN);
  1237 +// require_once(INTEGRATION_SRC_DIR."RequestManager.php");
  1238 +// return $this->executeRequest($obj, FunctionTypeEnumClass::PROCESSCLEAN);
1206 1239 }
1207 1240  
1208 1241 public function deleteSpecialInfo($name)
... ...
php/classes/CatalogCacheMgr.php 0 โ†’ 100644
... ... @@ -0,0 +1,319 @@
  1 +<?php
  2 +
  3 +/**
  4 + * @class CatalogCacheMgr
  5 + */
  6 +
  7 +
  8 +class CatIntervalCacheObject extends IntervalCacheObject
  9 +{
  10 + // for catalog
  11 + private $params = array();
  12 +
  13 + public function toArray() {
  14 + $result = array(
  15 + "cacheId" => $this->id,
  16 + "start" => $this->getStartToISO(),
  17 + "stop" => $this->getStopToISO()
  18 + );
  19 + if ($this->isNew)
  20 + $result["isNew"] = true;
  21 + if ($this->isModified)
  22 + $result["isModified"] = true;
  23 +
  24 + for ($i = 0; $i < count($this->params); $i++) {
  25 + $paramObject = array();
  26 + $index = 'param'.sprintf("%d",$i+2);
  27 + $result[$index] = $this->params[$i];
  28 + }
  29 + return $result;
  30 + }
  31 +
  32 + // for catalog
  33 + public function setParams($params) {
  34 + $this->params = $params;
  35 +
  36 + }
  37 +
  38 + public function getParams() {
  39 + return $this->params;
  40 + }
  41 +
  42 + public function writeBin($handle, $paramsNumber, $paramsSizes) {
  43 + fwrite($handle,pack('L6',$this->id,$this->index,$this->start,$this->stop,$this->isNew,$this->isModified));
  44 + for ($i = 0; $i < $paramsNumber; $i++) {
  45 + $paramString = $this->params[$i];
  46 + $paramArray = explode(',',$this->params[$i]);
  47 + for ($j = 0; $j < $paramsSizes[$i]; $j++) fwrite($handle,pack('d', $paramArray[$j]));
  48 + }
  49 +
  50 + }
  51 +
  52 + public function loadBin($handle, $paramsNumber, $paramsSizes) {
  53 + $array = unpack('L6int',fread($handle,6*4));
  54 + $this->id = $array['int1'];
  55 + $this->index = $array['int2'];
  56 + $this->start = $array['int3'];
  57 + $this->stop = $array['int4'];
  58 + $this->isNew = $array['int5'];
  59 + $this->isModified = $array['int6'];
  60 +
  61 + for ($i = 0; $i < $paramsNumber; $i++) {
  62 + $this->params[$i] = null;
  63 + for ($j = 0; $j < $paramsSizes[$i]; $j++) {
  64 + $val = unpack('dval',fread($handle,8));
  65 + $this->params[$i] .= $val['val'];
  66 + if ($j != $paramsSizes[$i] - 1) $this->params[$i] .= ',';
  67 + }
  68 + }
  69 +
  70 + }
  71 +
  72 + public function dump() {
  73 + echo " => Interval : id = ".$this->id.", index = ".$this->index.", start = ".$this->start.", stop = ".$this->stop.", isNew = ".$this->isNew.", isModified = ".$this->isModified.PHP_EOL;
  74 + }
  75 +}
  76 +
  77 +class CatalogCacheObject extends TimeTableCacheObject
  78 +{
  79 + private $paramsNumber;
  80 + private $paramsSizes = array();
  81 +
  82 + public function addInterval($startIso, $stopIso, $params, $isNew = false, $index = -1) {
  83 + $interval = new CatIntervalCacheObject($this->lastId, count($this->intervals));
  84 + ++$this->lastId;
  85 + $interval->setStartFromISO($startIso);
  86 + $interval->setStopFromISO($stopIso);
  87 + // for catalog
  88 + $interval->setParams($params);
  89 +
  90 + $interval->setIsNew($isNew);
  91 + array_push($this->intervals, $interval);
  92 + if ($index < 0)
  93 + array_push($this->indexes, count($this->intervals) - 1);
  94 + else
  95 + array_splice($this->indexes, $index, 0, array(count($this->intervals) - 1));
  96 + if ($isNew)
  97 + $this->isModified = true;
  98 +
  99 + return $interval;
  100 + }
  101 +
  102 + public function setParamsNumber($number){
  103 + $this->paramsNumber = $number;
  104 + }
  105 +
  106 + public function setParamsSizes($params){
  107 + for ($i = 0; $i < $this->paramsNumber; $i++)
  108 + $this->paramsSizes[$i] = $params[$i]['size'];
  109 + }
  110 +
  111 + public function writeBin($handle) {
  112 + //Magic key ("TTC")
  113 + fwrite($handle,pack('C3',ord('T'),ord('T'),ord('C')));
  114 +
  115 + //Version
  116 + fwrite($handle,pack('L',TimeTableCacheObject::$format_version));
  117 +
  118 + //Token
  119 + for ($i = 0; $i < TimeTableCacheObject::$token_len; ++$i)
  120 + fwrite($handle,pack('C',ord($this->token[$i])));
  121 +
  122 + //Modified
  123 + fwrite($handle,pack('L',$this->isModified));
  124 +
  125 + //Filter
  126 + $this->filter->writeBin($handle);
  127 +
  128 + //Sort
  129 + $this->sort->writeBin($handle);
  130 +
  131 + //Params Number
  132 + fwrite($handle,pack('L',$this->paramsNumber));
  133 +
  134 + //Params Sizes
  135 + for ($i = 0; $i < $this->paramsNumber; $i++)
  136 + fwrite($handle,pack('L',$this->paramsSizes[$i]));
  137 +
  138 + //Intervals
  139 + fwrite($handle,pack('L2',count($this->intervals), $this->lastId));
  140 +
  141 +
  142 + foreach($this->intervals as $interval)
  143 + $interval->writeBin($handle,$this->paramsNumber,$this->paramsSizes);
  144 +
  145 + //Indexes
  146 + fwrite($handle,pack('L',count($this->indexes)));
  147 + foreach($this->indexes as $index)
  148 + fwrite($handle,pack('L',$index));
  149 + }
  150 +
  151 + public function loadBin($handle) {
  152 + //Magic key ("TTC")
  153 + if (!$res = unpack('C3key',fread($handle,3)))
  154 + return false;
  155 +
  156 + if (($res['key1'] != ord('T')) || ($res['key2'] != ord('T')) || ($res['key3'] != ord('C')))
  157 + return false;
  158 +
  159 + //Version
  160 + if (!$res = unpack('Lversion',fread($handle,4)))
  161 + return false;
  162 + if (($res['version'] != TimeTableCacheObject::$format_version))
  163 + return false;
  164 +
  165 + //Token
  166 + $token = "";
  167 + for ($i = 0; $i < TimeTableCacheObject::$token_len; ++$i)
  168 + {
  169 + if (!$res = unpack('Ctoken',fread($handle,1)))
  170 + return false;
  171 + $token .= chr($res['token']);
  172 + }
  173 + $this->token = $token;
  174 +
  175 + //Modified
  176 + if (!$res = unpack('Lmodified',fread($handle,4)))
  177 + return false;
  178 + $this->isModified = $res['modified'];
  179 +
  180 + //Filter
  181 + $this->filter->loadBin($handle);
  182 +
  183 + //Sort
  184 + $this->sort->loadBin($handle);
  185 +
  186 + //ParamsNumber
  187 + if (!$res = unpack('Lnumber',fread($handle,4)))
  188 + return false;
  189 + $this->paramsNumber = $res['number'];
  190 +
  191 + //ParamsSizes
  192 + for ($i = 0; $i < $this->paramsNumber; $i++) {
  193 + if (!$res = unpack('Lsize',fread($handle,4)))
  194 + return false;
  195 + $this->paramsSizes[$i] = $res['size'];
  196 + }
  197 +
  198 + //Intervals
  199 + $res = unpack('L2data',fread($handle,2*4));
  200 + $nbIntervals = $res['data1'];
  201 + $this->lastId = $res['data2'];
  202 +
  203 + for ($i = 0; $i < $nbIntervals; ++$i)
  204 + {
  205 + $interval = new CatIntervalCacheObject(-1);
  206 + $interval->loadBin($handle, $this->paramsNumber, $this->paramsSizes);
  207 + array_push($this->intervals, $interval);
  208 + }
  209 +
  210 + //Indexes
  211 + $res = unpack('Ldata',fread($handle,4));
  212 + $nbIndexes = $res['data'];
  213 + for ($i = 0; $i < $nbIndexes; ++$i)
  214 + {
  215 + $res = unpack('Lindex',fread($handle,4));
  216 + array_push($this->indexes, $res['index']);
  217 + }
  218 +
  219 + return true;
  220 + }
  221 +
  222 +}
  223 +
  224 +class CatalogCacheMgr extends TimeTableCacheMgr
  225 +{
  226 +
  227 + protected static $cache_file = "cacheCat";
  228 +
  229 + protected $ttMgr = null;
  230 + protected $cache = null;
  231 +
  232 + function __construct() {
  233 +
  234 + $this->ttMgr = new CatalogMgr();
  235 + }
  236 +
  237 +
  238 + public function initFromTmpObject($folderId, $name) {
  239 +
  240 + //Create new cache
  241 + $this->cache = new CatalogCacheObject();
  242 +
  243 + //Load intervals from TmpObject file (Statistics Module)
  244 + $intervals_res = $this->ttMgr->getTmpObject($folderId, $name);
  245 +
  246 + if (!isset($intervals_res))
  247 + return array('success' => false, 'message' => 'Cannot get Tmp Object');
  248 +
  249 + if (array_key_exists('intervals', $intervals_res))
  250 + {
  251 + foreach ($intervals_res['intervals'] as $interval)
  252 + {
  253 + //Add interval
  254 + $this->cache->addInterval($interval['start'], $interval['stop'], $interval['paramTable']);
  255 +
  256 + }
  257 + }
  258 +
  259 + $this->cache->setIsModified(true);
  260 +
  261 + $paramHeaders = $intervals_res['parameters'];
  262 +
  263 + $this->cache->setParamsNumber(count($paramHeaders));
  264 + $this->cache->setParamsSizes($paramHeaders);
  265 +
  266 + unset($intervals_res);
  267 +
  268 + //Update cache
  269 + $this->cache->updateIndexes();
  270 +
  271 + //Save cache file
  272 + return array('success' => $this->saveToFile(), 'token' => $this->cache->getToken(),
  273 + 'status' => $this->cache->getStatus(), 'parameters' => $paramHeaders);
  274 + }
  275 +
  276 +
  277 + protected function loadFromFile() {
  278 +
  279 + if (!file_exists($this->getCacheFilePath()))
  280 + return false;
  281 + $this->cache = new CatalogCacheObject();
  282 + $handle = fopen($this->getCacheFilePath(), 'rb');
  283 + $result = false;
  284 + if (flock($handle, LOCK_SH))
  285 + {
  286 + $this->cache->loadBin($handle);
  287 + flock( $handle, LOCK_UN );
  288 + $result = true;
  289 + }
  290 + fclose($handle);
  291 + return $result;
  292 + }
  293 +
  294 + protected function getCacheFilePath() {
  295 + return USERTTDIR.(self::$cache_file);
  296 + }
  297 +
  298 + public function saveInTT($id, $action, $token) {
  299 +
  300 + if (!$this->loadFromFile())
  301 + return array('success' => false, 'message' => 'Cannot load cache file');
  302 +
  303 + if ($token != $this->cache->getToken())
  304 + return array('success' => false, 'message' => 'Cache token check error');
  305 +
  306 + $this->cache->updateIndexes();
  307 + $this->saveToFile();
  308 +
  309 + $intervals = $this->cache->getIntervalsArray(NULL,NULL,true);
  310 +
  311 + $this->cache->reset();
  312 +
  313 + return $this->ttMgr->saveIntervals($id, $intervals, $action);
  314 + }
  315 +
  316 +
  317 +
  318 + }
  319 +?>
0 320 \ No newline at end of file
... ...
php/classes/CatalogMgr.php 0 โ†’ 100644
... ... @@ -0,0 +1,227 @@
  1 +<?php
  2 +
  3 +/**
  4 + * @class CatalogMgr
  5 + */
  6 +
  7 +class CatalogMgr extends TimeTableMgr {
  8 +
  9 + function __construct() {
  10 + parent::__construct('Tt.xml');
  11 + $this->contentRootId = 'catalog-treeRootNode';
  12 + $this->contentRootTag = 'catalogList';
  13 + $this->attributes = array('name' => '', 'intervals' => ''); // + 'parameters'
  14 + $this->optionalAttributes = array();
  15 + $this->objTagName = 'catalog';
  16 + $this->id_prefix = 'cat_'; // 'tt_' ?
  17 +
  18 + if (!file_exists($this->xmlName)) {
  19 + $this->createDom();
  20 + $this->xp = new domxpath($this->contentDom);
  21 + }
  22 + }
  23 +
  24 + public function getTmpObject($folderId, $name, $onlyDescription = false) {
  25 +
  26 + $filePath = USERWORKINGDIR.$folderId.'/'.$name.'.xml';
  27 +
  28 + if (!file_exists($filePath))
  29 + return array('error' => 'Cannot find result file');
  30 +
  31 + $dom = new DomDocument('1.0');
  32 + $dom->formatOutput = true;
  33 +
  34 + if (!$dom -> load($filePath))
  35 + return array('error' => 'Cannot load result file');
  36 + $nameNodes = $dom->getElementsByTagName('name');
  37 + if ($nameNodes->length > 0)
  38 + $attributesToReturn['name'] = $nameNodes->item(0)->nodeValue;
  39 +
  40 + $descNodes = $dom->getElementsByTagName('description');
  41 + if ($descNodes->length > 0)
  42 + $attributesToReturn['description'] = $descNodes->item(0)->nodeValue;
  43 +
  44 + $creatNodes = $dom->getElementsByTagName('created');
  45 + if ($creatNodes->length > 0)
  46 + $attributesToReturn['created'] = $creatNodes->item(0)->nodeValue;
  47 +
  48 + $histNodes = $dom->getElementsByTagName('history');
  49 + if ($histNodes->length > 0)
  50 + $attributesToReturn['history'] = $histNodes->item(0)->nodeValue;
  51 +
  52 + $attributesToReturn['objName'] = $name;
  53 + $attributesToReturn['folderId'] = $folderId;
  54 + $attributesToReturn['success'] = true;
  55 +
  56 + if (!$onlyDescription)
  57 + {
  58 + $intNodes = $dom->getElementsByTagName('intervals');
  59 + foreach ($intNodes as $intNode)
  60 + {
  61 + $startNodes = $intNode->getElementsByTagName('start');
  62 + if ($startNodes->length <= 0)
  63 + return array('error' => 'Error detected in result file');
  64 +
  65 + $stopNodes = $intNode->getElementsByTagName('stop');
  66 + if ($stopNodes->length <= 0)
  67 + return array('error' => 'Error detected in result file');
  68 +
  69 + // for catalog
  70 + $paramNodes = $intNode->getElementsByTagName('param');
  71 + $params = array();
  72 + if ($paramNodes->length > 0)
  73 + foreach ( $paramNodes as $paramNode ) $params[] = $paramNode->nodeValue;
  74 +
  75 +
  76 + $attributesToReturn['intervals'][] = array('start' => $startNodes->item(0)->nodeValue,
  77 + 'stop' => $stopNodes->item(0)->nodeValue,
  78 + 'paramTable' => $params);
  79 + }
  80 + // for catalog
  81 + $paramsNodes = $dom->getElementsByTagName('parameter');
  82 +
  83 + if ($paramsNodes->length > 0){
  84 +
  85 + $paramsArray = array();
  86 + foreach ($paramsNodes as $paramNode) {
  87 +
  88 + $oneParam = array();
  89 + foreach ($paramNode->attributes as $attr)
  90 + $oneParam[$attr->nodeName] = $attr->nodeValue;
  91 +
  92 + if (substr($paramNode->getAttribute('id'),0,8) == 'stat_cov') {
  93 + $oneParam['size'] = '1';
  94 + $oneParam['name'] = 'Flag';
  95 + }
  96 +
  97 + $paramsArray[] = $oneParam;
  98 + }
  99 + $attributesToReturn['success'] = true;
  100 + $attributesToReturn['parameters'] = $paramsArray;
  101 + }
  102 + else
  103 + return array('error' => 'No information on parameters in result file');
  104 +
  105 +
  106 + }
  107 +
  108 + return $attributesToReturn;
  109 + }
  110 +
  111 +
  112 +// public function loadIntervalsFromTT($id,$typeTT,$start = NULL, $limit = NULL)
  113 +// {
  114 +//
  115 +// if ($typeTT == 'sharedtimeTable') {
  116 +// $pathid = SHAREDPATH.'TT/'.$id;
  117 +// }
  118 +// else {
  119 +// $pathid = USERTTDIR.$id;
  120 +// }
  121 +//
  122 +// //load intervals from TT id
  123 +// if (!file_exists($pathid.'.xml'))
  124 +// return array('success' => false, 'message' => "Cannot find TT file ".$id);
  125 +//
  126 +// $this->objectDom -> load($pathid.'.xml');
  127 +//
  128 +// if (!($objToGet = $this->objectDom->getElementById($id)))
  129 +// return array('success' => false, 'message' => NO_SUCH_ID." ".$id);
  130 +//
  131 +// $xpath = new DOMXPath($this->objectDom);
  132 +// $intervals = $xpath->query('//intervals');
  133 +//
  134 +// $result = array();
  135 +//
  136 +// if (!isset($start) || !isset($limit))
  137 +// {
  138 +// foreach ($intervals as $interval)
  139 +// {
  140 +// $startTime = $interval->getElementsByTagName('start')->item(0)->nodeValue;
  141 +// $stopTime = $interval->getElementsByTagName('stop')->item(0)->nodeValue;
  142 +// array_push($result, array('start' => $startTime, 'stop' => $stopTime));
  143 +// }
  144 +// }
  145 +// else
  146 +// {
  147 +// for ($i = 0; $i < $limit; ++$i)
  148 +// {
  149 +// if ($start+$i >= $intervals->length)
  150 +// break;
  151 +// $startTime = $intervals->item($start+$i)->getElementsByTagName('start')->item(0)->nodeValue;
  152 +// $stopTime = $intervals->item($start+$i)->getElementsByTagName('stop')->item(0)->nodeValue;
  153 +// array_push($result, array('start' => $startTime, 'stop' => $stopTime));
  154 +// }
  155 +// }
  156 +//
  157 +// return array(
  158 +// 'totalCount' => $intervals->length,
  159 +// 'intervals' => $result,
  160 +// 'start' => isset($start) ? $start : 0,
  161 +// 'limit' => isset($limit) ? $limit : 0,
  162 +// 'success' => true
  163 +// );
  164 +//
  165 +// }
  166 +
  167 + /*
  168 + * catalog header
  169 + */
  170 + protected function setParamDescription($params) {
  171 +
  172 + $paramsElement = $this->objectDom->createElement('parametres');
  173 + foreach ($params as $param) {
  174 + $paramElement = $this->objectDom->createElement('param');
  175 + $attrArray = (array)$param;
  176 + foreach ($attrArray as $key => $value)
  177 + $paramElement->setAttribute($key, $value);
  178 + $paramsElement->appendChild($paramElement);
  179 + }
  180 +
  181 + return $paramsElement;
  182 + }
  183 +
  184 + protected function createIntervalElement($interval) {
  185 + $newInterval = $this->objectDom->createElement('intervals');
  186 + $newInterval->appendChild($this->objectDom->createElement('start',$interval['start']));
  187 + $newInterval->appendChild($this->objectDom->createElement('stop',$interval['stop']));
  188 + foreach ($interval as $key =>$value) {
  189 + if (substr($key,0,5) == 'param')
  190 + $newInterval->appendChild($this->objectDom->createElement('param', $value));
  191 +
  192 + }
  193 + return $newInterval;
  194 + }
  195 +
  196 + public function createObject($p, $folder){
  197 +
  198 + if ($p -> leaf)
  199 + {
  200 + $result = $this->createParameter($p, $folder);
  201 + if ($result['error'])
  202 + return $result;
  203 +
  204 + $cacheMgr = new CatalogCacheMgr();
  205 +
  206 + if (isset($p->cacheToken) && ($p->cacheToken != ''))
  207 + {
  208 + $resultSaveInt = $cacheMgr->saveInTT($result['id'], "update", $p->cacheToken);
  209 + if (!$resultSaveInt['success'])
  210 + {
  211 + if ($resultSaveInt['message'])
  212 + return array('error' => $resultSaveInt['message']);
  213 + else
  214 + return array('error' => 'Unknown error during intervals save');
  215 + }
  216 + }
  217 + return $result;
  218 + }
  219 + // else return $this->createFolder($p);
  220 + //TODO check if this is possible?
  221 + else return array('error' => 'createFolder should be called from RENAME');
  222 +
  223 + }
  224 +
  225 +
  226 +}
  227 +?>
0 228 \ No newline at end of file
... ...
php/classes/IntervalCacheObject.php 0 โ†’ 100644
... ... @@ -0,0 +1,114 @@
  1 +<?php
  2 +class IntervalCacheObject
  3 +{
  4 + protected $id = -1;
  5 + protected $index = -1;
  6 + protected $start = 0;
  7 + protected $stop = 0;
  8 + protected $isNew = false;
  9 + protected $isModified = false;
  10 +
  11 + function __construct($id, $index) {
  12 + $this->id = $id;
  13 + $this->index = $index;
  14 + }
  15 +
  16 + public function getId() {
  17 + return $this->id;
  18 + }
  19 +
  20 + public function getIndex() {
  21 + return $this->index;
  22 + }
  23 +
  24 + public function setIndex($index) {
  25 + $this->index = $index;
  26 + }
  27 +
  28 + public function getStartToStamp() {
  29 + return $this->start;
  30 + }
  31 +
  32 + public function getStartToISO() {
  33 + return CacheTools::stamp2iso($this->start);
  34 + }
  35 +
  36 + public function setStartFromStamp($stamp) {
  37 + $this->start = $stamp;
  38 + }
  39 +
  40 + public function setStartFromISO($iso) {
  41 + $this->start = CacheTools::iso2stamp($iso);
  42 + }
  43 +
  44 + public function getStopToStamp() {
  45 + return $this->stop;
  46 + }
  47 +
  48 + public function getStopToISO() {
  49 + return CacheTools::stamp2iso($this->stop);
  50 + }
  51 +
  52 + public function setStopFromStamp($stamp) {
  53 + $this->stop = $stamp;
  54 + }
  55 +
  56 + public function setStopFromISO($iso) {
  57 + $this->stop = CacheTools::iso2stamp($iso);
  58 + }
  59 +
  60 + public function getDuration() {
  61 + return ($this->stop-$this->start);
  62 + }
  63 +
  64 + public function isModified() {
  65 + return $this->isModified;
  66 + }
  67 +
  68 + public function setIsModified($isModified) {
  69 + $this->isModified = $isModified;
  70 + }
  71 +
  72 + public function isNew() {
  73 + return $this->isNew;
  74 + }
  75 +
  76 + public function setIsNew($isNew) {
  77 + $this->isNew = $isNew;
  78 + }
  79 +
  80 + public function toArray() {
  81 + $result = array(
  82 + "cacheId" => $this->id,
  83 + "start" => $this->getStartToISO(),
  84 + "stop" => $this->getStopToISO()
  85 + );
  86 + if ($this->isNew)
  87 + $result["isNew"] = true;
  88 + if ($this->isModified)
  89 + $result["isModified"] = true;
  90 +
  91 + return $result;
  92 + }
  93 +
  94 +
  95 +
  96 + public function writeBin($handle) {
  97 + fwrite($handle,pack('L6',$this->id,$this->index,$this->start,$this->stop,$this->isNew,$this->isModified));
  98 + }
  99 +
  100 + public function loadBin($handle) {
  101 + $array = unpack('L6int',fread($handle,6*4));
  102 + $this->id = $array['int1'];
  103 + $this->index = $array['int2'];
  104 + $this->start = $array['int3'];
  105 + $this->stop = $array['int4'];
  106 + $this->isNew = $array['int5'];
  107 + $this->isModified = $array['int6'];
  108 + }
  109 +
  110 + public function dump() {
  111 + echo " => Interval : id = ".$this->id.", index = ".$this->index.", start = ".$this->start.", stop = ".$this->stop.", isNew = ".$this->isNew.", isModified = ".$this->isModified.PHP_EOL;
  112 + }
  113 +}
  114 +?>
0 115 \ No newline at end of file
... ...
php/classes/TimeTableCacheMgr.php
... ... @@ -27,8 +27,8 @@ class SortPartCacheObject
27 27 public static $DIRECTION_ASC = 1;
28 28 public static $DIRECTION_DES = 2;
29 29  
30   - private $type;
31   - private $dir;
  30 + protected $type;
  31 + protected $dir;
32 32  
33 33 function __construct() {
34 34 $this->type = self::$TYPE_UNKNOWN;
... ... @@ -172,7 +172,7 @@ class SortPartCacheObject
172 172  
173 173 class SortCacheObject
174 174 {
175   - private $parts = array();
  175 + protected $parts = array();
176 176  
177 177 function __construct() {
178 178 }
... ... @@ -286,9 +286,9 @@ class FilterPartCacheObject
286 286 public static $OPERATION_GT = 2;
287 287 public static $OPERATION_EQ = 3;
288 288  
289   - private $type;
290   - private $op;
291   - private $value;
  289 + protected $type;
  290 + protected $op;
  291 + protected $value;
292 292  
293 293 function __construct() {
294 294 $this->type = self::$TYPE_UNKNOWN;
... ... @@ -470,7 +470,7 @@ class FilterPartCacheObject
470 470  
471 471 class FilterCacheObject
472 472 {
473   - private $parts = array();
  473 + protected $parts = array();
474 474  
475 475 function __construct() {
476 476  
... ... @@ -555,631 +555,12 @@ class FilterCacheObject
555 555 }
556 556 }
557 557  
558   -class IntervalCacheObject
  558 + class TimeTableCacheMgr
559 559 {
560   - private $id = -1;
561   - private $index = -1;
562   - private $start = 0;
563   - private $stop = 0;
564   - private $isNew = false;
565   - private $isModified = false;
566   -
567   - function __construct($id, $index) {
568   - $this->id = $id;
569   - $this->index = $index;
570   - }
571   -
572   - public function getId() {
573   - return $this->id;
574   - }
575   -
576   - public function getIndex() {
577   - return $this->index;
578   - }
579   -
580   - public function setIndex($index) {
581   - $this->index = $index;
582   - }
583   -
584   - public function getStartToStamp() {
585   - return $this->start;
586   - }
587   -
588   - public function getStartToISO() {
589   - return CacheTools::stamp2iso($this->start);
590   - }
591   -
592   - public function setStartFromStamp($stamp) {
593   - $this->start = $stamp;
594   - }
595   -
596   - public function setStartFromISO($iso) {
597   - $this->start = CacheTools::iso2stamp($iso);
598   - }
599   -
600   - public function getStopToStamp() {
601   - return $this->stop;
602   - }
603   -
604   - public function getStopToISO() {
605   - return CacheTools::stamp2iso($this->stop);
606   - }
607   -
608   - public function setStopFromStamp($stamp) {
609   - $this->stop = $stamp;
610   - }
611   -
612   - public function setStopFromISO($iso) {
613   - $this->stop = CacheTools::iso2stamp($iso);
614   - }
615   -
616   - public function getDuration() {
617   - return ($this->stop-$this->start);
618   - }
619   -
620   - public function isModified() {
621   - return $this->isModified;
622   - }
623   -
624   - public function setIsModified($isModified) {
625   - $this->isModified = $isModified;
626   - }
627   -
628   - public function isNew() {
629   - return $this->isNew;
630   - }
631   -
632   - public function setIsNew($isNew) {
633   - $this->isNew = $isNew;
634   - }
635   -
636   - public function toArray() {
637   - $result = array(
638   - "cacheId" => $this->id,
639   - "start" => $this->getStartToISO(),
640   - "stop" => $this->getStopToISO()
641   - );
642   - if ($this->isNew)
643   - $result["isNew"] = true;
644   - if ($this->isModified)
645   - $result["isModified"] = true;
646   -
647   - return $result;
648   - }
649   -
650   -
651   -
652   - public function writeBin($handle) {
653   - fwrite($handle,pack('L6',$this->id,$this->index,$this->start,$this->stop,$this->isNew,$this->isModified));
654   - }
655   -
656   - public function loadBin($handle) {
657   - $array = unpack('L6int',fread($handle,6*4));
658   - $this->id = $array['int1'];
659   - $this->index = $array['int2'];
660   - $this->start = $array['int3'];
661   - $this->stop = $array['int4'];
662   - $this->isNew = $array['int5'];
663   - $this->isModified = $array['int6'];
664   - }
665   -
666   - public function dump() {
667   - echo " => Interval : id = ".$this->id.", index = ".$this->index.", start = ".$this->start.", stop = ".$this->stop.", isNew = ".$this->isNew.", isModified = ".$this->isModified.PHP_EOL;
668   - }
669   -}
670   -
671   -class TimeTableCacheObject
672   -{
673   - private static $format_version = 1;
674   - private static $token_len = 8;
675   -
676   - private $token = "";
677   -
678   - private $lastId = 0;
679   -
680   - private $intervals = array();
681   - private $indexes = array();
682   -
683   - private $isModified = false;
684   -
685   - private $filter = null;
686   -
687   - private $sort = null;
688   -
689   - function __construct() {
690   - $this->token = $this->getRandomToken();
691   - $this->filter = new FilterCacheObject();
692   - $this->sort = new SortCacheObject();
693   - }
694   -
695   - public function reset() {
696   - $this->lastId = 0;
697   - $this->isModified = false;
698   - $this->intervals = array();
699   - $this->indexes = array();
700   - unset($this->filter);
701   - $this->filter = new FilterCacheObject();;
702   - unset($this->sort);
703   - $this->sort = new SortCacheObject();
704   - }
705   -
706   - public function setIsModified($isModified) {
707   - $this->isModified = $isModified;
708   - }
709   -
710   - public function addInterval($startIso, $stopIso, $isNew = false, $index = -1) {
711   - $interval = new IntervalCacheObject($this->lastId, count($this->intervals));
712   - ++$this->lastId;
713   - $interval->setStartFromISO($startIso);
714   - $interval->setStopFromISO($stopIso);
715   - $interval->setIsNew($isNew);
716   - array_push($this->intervals, $interval);
717   - if ($index < 0)
718   - array_push($this->indexes, count($this->intervals) - 1);
719   - else
720   - array_splice($this->indexes, $index, 0, array(count($this->intervals) - 1));
721   - if ($isNew)
722   - $this->isModified = true;
723   - return $interval;
724   - }
725   -
726   - public function removeIntervalFromId($id) {
727   - for ($i = 0; $i < count($this->intervals); ++$i)
728   - {
729   - if ($this->intervals[$i]->getId() == $id)
730   - {
731   - //Remove interval
732   - array_splice($this->intervals, $i, 1);
733   - //Remove interval index if exist in indexes list
734   - for ($j = 0; $j < count($this->indexes); ++$j)
735   - {
736   - if ($this->indexes[$j] == $i)
737   - {
738   - array_splice($this->indexes, $j, 1);
739   - break;
740   - }
741   - }
742   - //Update indexes list
743   - for ($j = 0; $j < count($this->indexes); ++$j)
744   - {
745   - if ($this->indexes[$j] >= $i)
746   - $this->indexes[$j]--;
747   - }
748   - $this->isModified = true;
749   - return true;
750   - }
751   - }
752   -
753   - return false;
754   - }
755   -
756   - public function modifyIntervalFromId($id, $start, $stop) {
757   - foreach ($this->intervals as $interval)
758   - {
759   - if ($interval->getId() == $id)
760   - {
761   - if (isset($start))
762   - $interval->setStartFromISO($start);
763   - if (isset($stop))
764   - $interval->setStopFromISO($stop);
765   - $interval->setIsModified(true);
766   - $this->isModified = true;
767   - return true;
768   - }
769   - }
770   -
771   - return false;
772   - }
773   -
774   - public function operationIntervals($extendTime, $shiftTime) {
775   - if (($extendTime == 0) && ($shiftTime == 0))
776   - //Nothing to do
777   - return true;
778   -
779   - for ($i = 0; $i < count($this->indexes); ++$i) {
780   - $start = $this->intervals[$this->indexes[$i]]->getStartToStamp();
781   - $start -= $extendTime;
782   - $start += $shiftTime;
783   - $this->intervals[$this->indexes[$i]]->setStartFromStamp($start);
784   -
785   - $stop = $this->intervals[$this->indexes[$i]]->getStopToStamp();
786   - $stop += $extendTime;
787   - $stop += $shiftTime;
788   - $this->intervals[$this->indexes[$i]]->setStopFromStamp($stop);
789   -
790   - $this->intervals[$this->indexes[$i]]->setIsModified(true);
791   - $this->isModified = true;
792   - }
793   -
794   - return true;
795   - }
796   -
797   - public function mergeIntervals() {
798   - $this->sort->reset();
799   -
800   - $this->sort->loadFromObject(
801   - array(
802   - (object)array("property" => "start", "direction" => "DESC")
803   - )
804   - );
805   -
806   - $this->updateIndexes();
807   -
808   - $merged_intervals = array();
809   -
810   - for ($i = 0; $i < count($this->indexes); ++$i) {
811   - if (count($merged_intervals) == 0)
812   - {
813   - array_push($merged_intervals,array(
814   - "start" => $this->intervals[$this->indexes[$i]]->getStartToStamp(),
815   - "stop" => $this->intervals[$this->indexes[$i]]->getStopToStamp(),
816   - "mod" => FALSE)
817   - );
818   - continue;
819   - }
820   - if (($merged_intervals[count($merged_intervals)-1]["stop"] >= $this->intervals[$this->indexes[$i]]->getStartToStamp()) &&
821   - ($merged_intervals[count($merged_intervals)-1]["stop"] < $this->intervals[$this->indexes[$i]]->getStopToStamp()))
822   - {
823   - $merged_intervals[count($merged_intervals)-1]["stop"] = $this->intervals[$this->indexes[$i]]->getStopToStamp();
824   - $merged_intervals[count($merged_intervals)-1]["mod"] = TRUE;
825   - }
826   - else
827   - array_push($merged_intervals,array(
828   - "start" => $this->intervals[$this->indexes[$i]]->getStartToStamp(),
829   - "stop" => $this->intervals[$this->indexes[$i]]->getStopToStamp(),
830   - "mod" => FALSE)
831   - );
832   - }
833   -
834   - $this->reset();
835   -
836   - foreach ($merged_intervals as $merged_interval) {
837   - $interval = new IntervalCacheObject($this->lastId, count($this->intervals));
838   - ++$this->lastId;
839   - $interval->setStartFromStamp($merged_interval["start"]);
840   - $interval->setStopFromStamp($merged_interval["stop"]);
841   - $interval->setIsNew($merged_interval["mod"]);
842   - if ($merged_interval["mod"])
843   - $this->isModified = true;
844   - array_push($this->intervals, $interval);
845   - array_push($this->indexes, count($this->intervals) - 1);
846   - }
847   -
848   - return true;
849   - }
850   -
851   - public function getStatistics() {
852   - $minTime = NULL;
853   - $maxTime = NULL;
854   - $minDuration = NULL;
855   - $maxDuration = NULL;
856   - $indexMinDuration = -1;
857   - $indexMaxDuration = -1;
858   -
859   - $nbValid = 0;
860   - $durationTotal = 0;
861   -
862   - //Min & Max
863   - for ($i = 0; $i < count($this->indexes); ++$i) {
864   - if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
865   - //Invalid interval
866   - continue;
867   -
868   - ++$nbValid;
869   - $durationTotal += $this->intervals[$this->indexes[$i]]->getDuration();
870   -
871   - if (!isset($minTime) || ($minTime > $this->intervals[$this->indexes[$i]]->getStartToStamp()))
872   - $minTime = $this->intervals[$this->indexes[$i]]->getStartToStamp();
873   -
874   - if (!isset($maxTime) || ($maxTime < $this->intervals[$this->indexes[$i]]->getStopToStamp()))
875   - $maxTime = $this->intervals[$this->indexes[$i]]->getStopToStamp();
876   -
877   - if (!isset($minDuration) || ($minDuration > $this->intervals[$this->indexes[$i]]->getDuration()))
878   - {
879   - $minDuration = $this->intervals[$this->indexes[$i]]->getDuration();
880   - $indexMinDuration = $i;
881   - }
882   -
883   - if (!isset($maxDuration) || ($maxDuration < $this->intervals[$this->indexes[$i]]->getDuration()))
884   - {
885   - $maxDuration = $this->intervals[$this->indexes[$i]]->getDuration();
886   - $indexMaxDuration = $i;
887   - }
888   - }
889   -
890   - if (!isset($minTime))
891   - $minTime = 0;
892   - if (!isset($maxTime))
893   - $maxTime = 0;
894   - if (!isset($minDuration))
895   - $minDuration = 0;
896   - if (!isset($maxDuration))
897   - $maxDuration = 0;
898   -
899   -
900   - //Mean
901   - if ($nbValid > 0)
902   - $mean = $durationTotal / $nbValid;
903   - else
904   - $mean = 0;
905   -
906   - //Standard deviation
907   - $pow = 0;
908   - for ($i = 0; $i < count($this->indexes); ++$i) {
909   - if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
910   - //Invalid interval
911   - continue;
912   -
913   - $pow += pow($this->intervals[$this->indexes[$i]]->getDuration()-$mean,2);
914   - }
915   - if ($nbValid > 0)
916   - $variance = $pow/$nbValid;
917   - else
918   - $variance = 0;
919   - $stdev = sqrt($variance);
920   -
921   - //Sort by duration to get median
922   - $this->sort->reset();
923   -
924   - $this->sort->loadFromObject(
925   - array(
926   - (object)array("property" => "durationSec", "direction" => "DESC")
927   - )
928   - );
929   -
930   - $this->updateIndexes();
931   -
932   - $durations = array();
933   - for ($i = 0; $i < count($this->indexes); ++$i) {
934   - if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
935   - //Invalid interval
936   - continue;
937   -
938   - array_push($durations, $this->intervals[$this->indexes[$i]]->getDuration());
939   - }
940   -
941   - if (count($durations) > 0)
942   - {
943   - if (count($durations)%2 > 0) {
944   - $median = $durations[count($durations)/2-0.5];
945   - } else { // else the number of intervals is an even number
946   - $median = ($durations[count($durations)/2-1] + $durations[count($durations)/2])/2;
947   - }
948   - }
949   - else
950   - $median = 0;
951   -
952   - //Merge intervals to get density
953   - $this->mergeIntervals();
954   -
955   - $durationMergedTotal = 0;
956   - for ($i = 0; $i < count($this->indexes); ++$i) {
957   - if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
958   - //Invalid interval
959   - continue;
960   -
961   - $durationMergedTotal += $this->intervals[$this->indexes[$i]]->getDuration();
962   - }
963   -
964   - if (($maxTime-$minTime) > 0)
965   - $density = (($durationMergedTotal/($maxTime-$minTime)));
966   - else
967   - $density = 0;
968   -
969   - return array(
970   - "minDuration" => $minDuration,
971   - "minDurationIndex"=> $indexMinDuration,
972   - "maxDuration" => $maxDuration,
973   - "maxDurationIndex"=> $indexMaxDuration,
974   - "mean" => $mean,
975   - "stdev" => $stdev,
976   - "median" => $median,
977   - "density" => $density);
978   - }
979   -
980   - public function getStatus() {
981   - $nbFiltered = count($this->intervals) - count($this->indexes);
982   -
983   - $nbModified = 0;
984   - $nbNew = 0;
985   - $nbInvalid = 0;
986   - $nbValid = 0;
987   - for ($i = 0; $i < count($this->indexes); ++$i) {
988   - if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
989   - ++$nbInvalid;
990   - else
991   - ++$nbValid;
992   - if ($this->intervals[$this->indexes[$i]]->isModified())
993   - ++$nbModified;
994   - if ($this->intervals[$this->indexes[$i]]->isNew())
995   - ++$nbNew;
996   - }
997   -
998   - return array(
999   - "nbFiltered" => $nbFiltered,
1000   - "nbModified" => $nbModified,
1001   - "nbNew" => $nbNew,
1002   - "nbInvalid" => $nbInvalid,
1003   - "nbValid" => $nbValid,
1004   - "isModified" => $this->isModified
1005   - );
1006   - }
1007   -
1008   - public function getIntervalsArray($startIndex, $limit,$skipInvalid = false) {
1009   - $intervals = array();
1010   -
1011   - if (!isset($startIndex))
1012   - $startIndex = 0;
1013   -
1014   - if (!isset($limit))
1015   - $limit = count($this->indexes);
1016   -
1017   - for ($i = 0; $i < $limit; ++$i) {
1018   - if ($startIndex+$i >= count($this->indexes))
1019   - break;
1020   - if ($skipInvalid && ($this->intervals[$this->indexes[$startIndex+$i]]->getDuration() <= 0))
1021   - continue;
1022   - array_push($intervals, $this->intervals[$this->indexes[$startIndex+$i]]->toArray());
1023   - }
1024   - return $intervals;
1025   - }
1026   -
1027   - public function getLength() {
1028   - return count($this->indexes);
1029   - }
1030   -
1031   - public function getToken() {
1032   - return $this->token;
1033   - }
1034   -
1035   - public function getFilter() {
1036   - return $this->filter;
1037   - }
1038   -
1039   - public function getSort() {
1040   - return $this->sort;
1041   - }
1042   -
1043   - public function updateIndexes() {
1044   - $this->indexes = array();
1045   -
1046   - for ($i = 0; $i < count($this->intervals); ++$i)
1047   - $this->intervals[$i]->setIndex($i);
1048   -
1049   - //Apply sort
1050   - $sort_result = $this->sort->apply($this->intervals);
1051   -
1052   - //Apply filter
1053   - for ($i = 0; $i < count($sort_result); ++$i)
1054   - {
1055   - if (!$this->filter->toFiltered($this->intervals[$sort_result[$i]]))
1056   - array_push($this->indexes,$this->intervals[$sort_result[$i]]->getIndex());
1057   - }
1058   - }
1059   -
1060   - public function writeBin($handle) {
1061   - //Magic key ("TTC")
1062   - fwrite($handle,pack('C3',ord('T'),ord('T'),ord('C')));
1063   -
1064   - //Version
1065   - fwrite($handle,pack('L',TimeTableCacheObject::$format_version));
1066   -
1067   - //Token
1068   - for ($i = 0; $i < TimeTableCacheObject::$token_len; ++$i)
1069   - fwrite($handle,pack('C',ord($this->token[$i])));
1070   -
1071   - //Modified
1072   - fwrite($handle,pack('L',$this->isModified));
1073   -
1074   - //Filter
1075   - $this->filter->writeBin($handle);
1076   -
1077   - //Sort
1078   - $this->sort->writeBin($handle);
1079   -
1080   - //Intervals
1081   - fwrite($handle,pack('L2',count($this->intervals), $this->lastId));
1082   - foreach($this->intervals as $interval)
1083   - $interval->writeBin($handle);
1084   -
1085   - //Indexes
1086   - fwrite($handle,pack('L',count($this->indexes)));
1087   - foreach($this->indexes as $index)
1088   - fwrite($handle,pack('L',$index));
1089   - }
1090   -
1091   - public function loadBin($handle) {
1092   - //Magic key ("TTC")
1093   - if (!$res = unpack('C3key',fread($handle,3)))
1094   - return false;
1095   -
1096   - if (($res['key1'] != ord('T')) || ($res['key2'] != ord('T')) || ($res['key3'] != ord('C')))
1097   - return false;
1098   -
1099   - //Version
1100   - if (!$res = unpack('Lversion',fread($handle,4)))
1101   - return false;
1102   - if (($res['version'] != TimeTableCacheObject::$format_version))
1103   - return false;
1104   -
1105   - //Token
1106   - $token = "";
1107   - for ($i = 0; $i < TimeTableCacheObject::$token_len; ++$i)
1108   - {
1109   - if (!$res = unpack('Ctoken',fread($handle,1)))
1110   - return false;
1111   - $token .= chr($res['token']);
1112   - }
1113   - $this->token = $token;
1114   -
1115   - //Modified
1116   - if (!$res = unpack('Lmodified',fread($handle,4)))
1117   - return false;
1118   - $this->isModified = $res['modified'];
1119   -
1120   - //Filter
1121   - $this->filter->loadBin($handle);
1122   -
1123   - //Sort
1124   - $this->sort->loadBin($handle);
1125   -
1126   - //Intervals
1127   - $res = unpack('L2data',fread($handle,2*4));
1128   - $nbIntervals = $res['data1'];
1129   - $this->lastId = $res['data2'];
1130   - for ($i = 0; $i < $nbIntervals; ++$i)
1131   - {
1132   - $interval = new IntervalCacheObject(-1);
1133   - $interval->loadBin($handle);
1134   - array_push($this->intervals, $interval);
1135   - }
1136   -
1137   - //Indexes
1138   - $res = unpack('Ldata',fread($handle,4));
1139   - $nbIndexes = $res['data'];
1140   - for ($i = 0; $i < $nbIndexes; ++$i)
1141   - {
1142   - $res = unpack('Lindex',fread($handle,4));
1143   - array_push($this->indexes, $res['index']);
1144   - }
1145   -
1146   - return true;
1147   - }
1148   -
1149   - private function getRandomToken() {
1150   - $letters = 'abcefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
1151   - return substr(str_shuffle($letters), 0, TimeTableCacheObject::$token_len);
1152   - }
1153   -
1154   - public function dump() {
1155   - echo " => TimeTableCacheObject : token = ".$this->token.", nb intervals = ".count($this->intervals).", last id = ".$this->lastId.", nb indexes = ".count($this->indexes).PHP_EOL;
1156   - echo PHP_EOL;
1157   -
1158   - $this->filter->dump();
1159   - echo PHP_EOL;
1160   -
1161   - $this->sort->dump();
1162   - echo PHP_EOL;
1163   -
1164   - foreach ($this->intervals as $interval)
1165   - $interval->dump();
1166   - echo PHP_EOL;
1167   -
1168   - echo " => Indexes list : ";
1169   - foreach ($this->indexes as $index)
1170   - {
1171   - echo $index.", ";
1172   - }
1173   - echo PHP_EOL;
1174   - }
1175   -}
1176   -
1177   -class TimeTableCacheMgr
1178   -{
1179   - private static $cache_file = "cacheTT";
  560 + protected static $cache_file = "cacheTT";
1180 561  
1181   - private $ttMgr = null;
1182   - private $cache = null;
  562 + protected $ttMgr = null;
  563 + protected $cache = null;
1183 564  
1184 565 function __construct() {
1185 566 $this->ttMgr = new TimeTableMgr();
... ... @@ -1449,11 +830,11 @@ class TimeTableCacheMgr
1449 830 $this->cache->dump();
1450 831 }
1451 832  
1452   - private function getCacheFilePath() {
  833 + protected function getCacheFilePath() {
1453 834 return USERTTDIR.(self::$cache_file);
1454 835 }
1455 836  
1456   - private function saveToFile() {
  837 + protected function saveToFile() {
1457 838 if (!isset($this->cache))
1458 839 return false;
1459 840 $handle = fopen($this->getCacheFilePath(), 'wb');
... ... @@ -1468,7 +849,7 @@ class TimeTableCacheMgr
1468 849 return $result;
1469 850 }
1470 851  
1471   - private function loadFromFile() {
  852 + protected function loadFromFile() {
1472 853 if (!file_exists($this->getCacheFilePath()))
1473 854 return false;
1474 855 $this->cache = new TimeTableCacheObject();
... ...
php/classes/TimeTableCacheObject.php 0 โ†’ 100644
... ... @@ -0,0 +1,509 @@
  1 +<?php
  2 +
  3 +class TimeTableCacheObject
  4 +{
  5 + protected static $format_version = 1;
  6 + protected static $token_len = 8;
  7 +
  8 + protected $token = "";
  9 +
  10 + protected $lastId = 0;
  11 +
  12 + protected $intervals = array();
  13 + protected $indexes = array();
  14 +
  15 + protected $isModified = false;
  16 +
  17 + protected $filter = null;
  18 +
  19 + protected $sort = null;
  20 +
  21 + function __construct() {
  22 + $this->token = $this->getRandomToken();
  23 + $this->filter = new FilterCacheObject();
  24 + $this->sort = new SortCacheObject();
  25 + }
  26 +
  27 + public function reset() {
  28 + $this->lastId = 0;
  29 + $this->isModified = false;
  30 + $this->intervals = array();
  31 + $this->indexes = array();
  32 + unset($this->filter);
  33 + $this->filter = new FilterCacheObject();;
  34 + unset($this->sort);
  35 + $this->sort = new SortCacheObject();
  36 + }
  37 +
  38 + public function setIsModified($isModified) {
  39 + $this->isModified = $isModified;
  40 + }
  41 +
  42 + public function addInterval($startIso, $stopIso, $isNew = false, $index = -1) {
  43 + $interval = new IntervalCacheObject($this->lastId, count($this->intervals));
  44 + ++$this->lastId;
  45 + $interval->setStartFromISO($startIso);
  46 + $interval->setStopFromISO($stopIso);
  47 + $interval->setIsNew($isNew);
  48 + array_push($this->intervals, $interval);
  49 + if ($index < 0)
  50 + array_push($this->indexes, count($this->intervals) - 1);
  51 + else
  52 + array_splice($this->indexes, $index, 0, array(count($this->intervals) - 1));
  53 + if ($isNew)
  54 + $this->isModified = true;
  55 + return $interval;
  56 + }
  57 +
  58 + public function removeIntervalFromId($id) {
  59 + for ($i = 0; $i < count($this->intervals); ++$i)
  60 + {
  61 + if ($this->intervals[$i]->getId() == $id)
  62 + {
  63 + //Remove interval
  64 + array_splice($this->intervals, $i, 1);
  65 + //Remove interval index if exist in indexes list
  66 + for ($j = 0; $j < count($this->indexes); ++$j)
  67 + {
  68 + if ($this->indexes[$j] == $i)
  69 + {
  70 + array_splice($this->indexes, $j, 1);
  71 + break;
  72 + }
  73 + }
  74 + //Update indexes list
  75 + for ($j = 0; $j < count($this->indexes); ++$j)
  76 + {
  77 + if ($this->indexes[$j] >= $i)
  78 + $this->indexes[$j]--;
  79 + }
  80 + $this->isModified = true;
  81 + return true;
  82 + }
  83 + }
  84 +
  85 + return false;
  86 + }
  87 +
  88 + public function modifyIntervalFromId($id, $start, $stop) {
  89 + foreach ($this->intervals as $interval)
  90 + {
  91 + if ($interval->getId() == $id)
  92 + {
  93 + if (isset($start))
  94 + $interval->setStartFromISO($start);
  95 + if (isset($stop))
  96 + $interval->setStopFromISO($stop);
  97 + $interval->setIsModified(true);
  98 + $this->isModified = true;
  99 + return true;
  100 + }
  101 + }
  102 +
  103 + return false;
  104 + }
  105 +
  106 + public function operationIntervals($extendTime, $shiftTime) {
  107 + if (($extendTime == 0) && ($shiftTime == 0))
  108 + //Nothing to do
  109 + return true;
  110 +
  111 + for ($i = 0; $i < count($this->indexes); ++$i) {
  112 + $start = $this->intervals[$this->indexes[$i]]->getStartToStamp();
  113 + $start -= $extendTime;
  114 + $start += $shiftTime;
  115 + $this->intervals[$this->indexes[$i]]->setStartFromStamp($start);
  116 +
  117 + $stop = $this->intervals[$this->indexes[$i]]->getStopToStamp();
  118 + $stop += $extendTime;
  119 + $stop += $shiftTime;
  120 + $this->intervals[$this->indexes[$i]]->setStopFromStamp($stop);
  121 +
  122 + $this->intervals[$this->indexes[$i]]->setIsModified(true);
  123 + $this->isModified = true;
  124 + }
  125 +
  126 + return true;
  127 + }
  128 +
  129 + public function mergeIntervals() {
  130 + $this->sort->reset();
  131 +
  132 + $this->sort->loadFromObject(
  133 + array(
  134 + (object)array("property" => "start", "direction" => "DESC")
  135 + )
  136 + );
  137 +
  138 + $this->updateIndexes();
  139 +
  140 + $merged_intervals = array();
  141 +
  142 + for ($i = 0; $i < count($this->indexes); ++$i) {
  143 + if (count($merged_intervals) == 0)
  144 + {
  145 + array_push($merged_intervals,array(
  146 + "start" => $this->intervals[$this->indexes[$i]]->getStartToStamp(),
  147 + "stop" => $this->intervals[$this->indexes[$i]]->getStopToStamp(),
  148 + "mod" => FALSE)
  149 + );
  150 + continue;
  151 + }
  152 + if (($merged_intervals[count($merged_intervals)-1]["stop"] >= $this->intervals[$this->indexes[$i]]->getStartToStamp()) &&
  153 + ($merged_intervals[count($merged_intervals)-1]["stop"] < $this->intervals[$this->indexes[$i]]->getStopToStamp()))
  154 + {
  155 + $merged_intervals[count($merged_intervals)-1]["stop"] = $this->intervals[$this->indexes[$i]]->getStopToStamp();
  156 + $merged_intervals[count($merged_intervals)-1]["mod"] = TRUE;
  157 + }
  158 + else
  159 + array_push($merged_intervals,array(
  160 + "start" => $this->intervals[$this->indexes[$i]]->getStartToStamp(),
  161 + "stop" => $this->intervals[$this->indexes[$i]]->getStopToStamp(),
  162 + "mod" => FALSE)
  163 + );
  164 + }
  165 +
  166 + $this->reset();
  167 +
  168 + foreach ($merged_intervals as $merged_interval) {
  169 + $interval = new IntervalCacheObject($this->lastId, count($this->intervals));
  170 + ++$this->lastId;
  171 + $interval->setStartFromStamp($merged_interval["start"]);
  172 + $interval->setStopFromStamp($merged_interval["stop"]);
  173 + $interval->setIsNew($merged_interval["mod"]);
  174 + if ($merged_interval["mod"])
  175 + $this->isModified = true;
  176 + array_push($this->intervals, $interval);
  177 + array_push($this->indexes, count($this->intervals) - 1);
  178 + }
  179 +
  180 + return true;
  181 + }
  182 +
  183 + public function getStatistics() {
  184 + $minTime = NULL;
  185 + $maxTime = NULL;
  186 + $minDuration = NULL;
  187 + $maxDuration = NULL;
  188 + $indexMinDuration = -1;
  189 + $indexMaxDuration = -1;
  190 +
  191 + $nbValid = 0;
  192 + $durationTotal = 0;
  193 +
  194 + //Min & Max
  195 + for ($i = 0; $i < count($this->indexes); ++$i) {
  196 + if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
  197 + //Invalid interval
  198 + continue;
  199 +
  200 + ++$nbValid;
  201 + $durationTotal += $this->intervals[$this->indexes[$i]]->getDuration();
  202 +
  203 + if (!isset($minTime) || ($minTime > $this->intervals[$this->indexes[$i]]->getStartToStamp()))
  204 + $minTime = $this->intervals[$this->indexes[$i]]->getStartToStamp();
  205 +
  206 + if (!isset($maxTime) || ($maxTime < $this->intervals[$this->indexes[$i]]->getStopToStamp()))
  207 + $maxTime = $this->intervals[$this->indexes[$i]]->getStopToStamp();
  208 +
  209 + if (!isset($minDuration) || ($minDuration > $this->intervals[$this->indexes[$i]]->getDuration()))
  210 + {
  211 + $minDuration = $this->intervals[$this->indexes[$i]]->getDuration();
  212 + $indexMinDuration = $i;
  213 + }
  214 +
  215 + if (!isset($maxDuration) || ($maxDuration < $this->intervals[$this->indexes[$i]]->getDuration()))
  216 + {
  217 + $maxDuration = $this->intervals[$this->indexes[$i]]->getDuration();
  218 + $indexMaxDuration = $i;
  219 + }
  220 + }
  221 +
  222 + if (!isset($minTime))
  223 + $minTime = 0;
  224 + if (!isset($maxTime))
  225 + $maxTime = 0;
  226 + if (!isset($minDuration))
  227 + $minDuration = 0;
  228 + if (!isset($maxDuration))
  229 + $maxDuration = 0;
  230 +
  231 +
  232 + //Mean
  233 + if ($nbValid > 0)
  234 + $mean = $durationTotal / $nbValid;
  235 + else
  236 + $mean = 0;
  237 +
  238 + //Standard deviation
  239 + $pow = 0;
  240 + for ($i = 0; $i < count($this->indexes); ++$i) {
  241 + if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
  242 + //Invalid interval
  243 + continue;
  244 +
  245 + $pow += pow($this->intervals[$this->indexes[$i]]->getDuration()-$mean,2);
  246 + }
  247 + if ($nbValid > 0)
  248 + $variance = $pow/$nbValid;
  249 + else
  250 + $variance = 0;
  251 + $stdev = sqrt($variance);
  252 +
  253 + //Sort by duration to get median
  254 + $this->sort->reset();
  255 +
  256 + $this->sort->loadFromObject(
  257 + array(
  258 + (object)array("property" => "durationSec", "direction" => "DESC")
  259 + )
  260 + );
  261 +
  262 + $this->updateIndexes();
  263 +
  264 + $durations = array();
  265 + for ($i = 0; $i < count($this->indexes); ++$i) {
  266 + if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
  267 + //Invalid interval
  268 + continue;
  269 +
  270 + array_push($durations, $this->intervals[$this->indexes[$i]]->getDuration());
  271 + }
  272 +
  273 + if (count($durations) > 0)
  274 + {
  275 + if (count($durations)%2 > 0) {
  276 + $median = $durations[count($durations)/2-0.5];
  277 + } else { // else the number of intervals is an even number
  278 + $median = ($durations[count($durations)/2-1] + $durations[count($durations)/2])/2;
  279 + }
  280 + }
  281 + else
  282 + $median = 0;
  283 +
  284 + //Merge intervals to get density
  285 + $this->mergeIntervals();
  286 +
  287 + $durationMergedTotal = 0;
  288 + for ($i = 0; $i < count($this->indexes); ++$i) {
  289 + if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
  290 + //Invalid interval
  291 + continue;
  292 +
  293 + $durationMergedTotal += $this->intervals[$this->indexes[$i]]->getDuration();
  294 + }
  295 +
  296 + if (($maxTime-$minTime) > 0)
  297 + $density = (($durationMergedTotal/($maxTime-$minTime)));
  298 + else
  299 + $density = 0;
  300 +
  301 + return array(
  302 + "minDuration" => $minDuration,
  303 + "minDurationIndex"=> $indexMinDuration,
  304 + "maxDuration" => $maxDuration,
  305 + "maxDurationIndex"=> $indexMaxDuration,
  306 + "mean" => $mean,
  307 + "stdev" => $stdev,
  308 + "median" => $median,
  309 + "density" => $density);
  310 + }
  311 +
  312 + public function getStatus() {
  313 + $nbFiltered = count($this->intervals) - count($this->indexes);
  314 +
  315 + $nbModified = 0;
  316 + $nbNew = 0;
  317 + $nbInvalid = 0;
  318 + $nbValid = 0;
  319 + for ($i = 0; $i < count($this->indexes); ++$i) {
  320 + if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
  321 + ++$nbInvalid;
  322 + else
  323 + ++$nbValid;
  324 + if ($this->intervals[$this->indexes[$i]]->isModified())
  325 + ++$nbModified;
  326 + if ($this->intervals[$this->indexes[$i]]->isNew())
  327 + ++$nbNew;
  328 + }
  329 +
  330 + return array(
  331 + "nbFiltered" => $nbFiltered,
  332 + "nbModified" => $nbModified,
  333 + "nbNew" => $nbNew,
  334 + "nbInvalid" => $nbInvalid,
  335 + "nbValid" => $nbValid,
  336 + "isModified" => $this->isModified
  337 + );
  338 + }
  339 +
  340 + public function getIntervalsArray($startIndex, $limit,$skipInvalid = false) {
  341 + $intervals = array();
  342 +
  343 + if (!isset($startIndex))
  344 + $startIndex = 0;
  345 +
  346 + if (!isset($limit))
  347 + $limit = count($this->indexes);
  348 +
  349 + for ($i = 0; $i < $limit; ++$i) {
  350 + if ($startIndex+$i >= count($this->indexes))
  351 + break;
  352 + if ($skipInvalid && ($this->intervals[$this->indexes[$startIndex+$i]]->getDuration() <= 0))
  353 + continue;
  354 + array_push($intervals, $this->intervals[$this->indexes[$startIndex+$i]]->toArray());
  355 + }
  356 + return $intervals;
  357 + }
  358 +
  359 + public function getLength() {
  360 + return count($this->indexes);
  361 + }
  362 +
  363 + public function getToken() {
  364 + return $this->token;
  365 + }
  366 +
  367 + public function getFilter() {
  368 + return $this->filter;
  369 + }
  370 +
  371 + public function getSort() {
  372 + return $this->sort;
  373 + }
  374 +
  375 + public function updateIndexes() {
  376 + $this->indexes = array();
  377 +
  378 + for ($i = 0; $i < count($this->intervals); ++$i)
  379 + $this->intervals[$i]->setIndex($i);
  380 +
  381 + //Apply sort
  382 + $sort_result = $this->sort->apply($this->intervals);
  383 +
  384 + //Apply filter
  385 + for ($i = 0; $i < count($sort_result); ++$i)
  386 + {
  387 + if (!$this->filter->toFiltered($this->intervals[$sort_result[$i]]))
  388 + array_push($this->indexes,$this->intervals[$sort_result[$i]]->getIndex());
  389 + }
  390 + }
  391 +
  392 + public function writeBin($handle) {
  393 + //Magic key ("TTC")
  394 + fwrite($handle,pack('C3',ord('T'),ord('T'),ord('C')));
  395 +
  396 + //Version
  397 + fwrite($handle,pack('L',TimeTableCacheObject::$format_version));
  398 +
  399 + //Token
  400 + for ($i = 0; $i < TimeTableCacheObject::$token_len; ++$i)
  401 + fwrite($handle,pack('C',ord($this->token[$i])));
  402 +
  403 + //Modified
  404 + fwrite($handle,pack('L',$this->isModified));
  405 +
  406 + //Filter
  407 + $this->filter->writeBin($handle);
  408 +
  409 + //Sort
  410 + $this->sort->writeBin($handle);
  411 +
  412 + //Intervals
  413 + fwrite($handle,pack('L2',count($this->intervals), $this->lastId));
  414 + foreach($this->intervals as $interval)
  415 + $interval->writeBin($handle);
  416 +
  417 + //Indexes
  418 + fwrite($handle,pack('L',count($this->indexes)));
  419 + foreach($this->indexes as $index)
  420 + fwrite($handle,pack('L',$index));
  421 + }
  422 +
  423 + public function loadBin($handle) {
  424 + //Magic key ("TTC")
  425 + if (!$res = unpack('C3key',fread($handle,3)))
  426 + return false;
  427 +
  428 + if (($res['key1'] != ord('T')) || ($res['key2'] != ord('T')) || ($res['key3'] != ord('C')))
  429 + return false;
  430 +
  431 + //Version
  432 + if (!$res = unpack('Lversion',fread($handle,4)))
  433 + return false;
  434 + if (($res['version'] != TimeTableCacheObject::$format_version))
  435 + return false;
  436 +
  437 + //Token
  438 + $token = "";
  439 + for ($i = 0; $i < TimeTableCacheObject::$token_len; ++$i)
  440 + {
  441 + if (!$res = unpack('Ctoken',fread($handle,1)))
  442 + return false;
  443 + $token .= chr($res['token']);
  444 + }
  445 + $this->token = $token;
  446 +
  447 + //Modified
  448 + if (!$res = unpack('Lmodified',fread($handle,4)))
  449 + return false;
  450 + $this->isModified = $res['modified'];
  451 +
  452 + //Filter
  453 + $this->filter->loadBin($handle);
  454 +
  455 + //Sort
  456 + $this->sort->loadBin($handle);
  457 +
  458 + //Intervals
  459 + $res = unpack('L2data',fread($handle,2*4));
  460 + $nbIntervals = $res['data1'];
  461 + $this->lastId = $res['data2'];
  462 + for ($i = 0; $i < $nbIntervals; ++$i)
  463 + {
  464 + $interval = new IntervalCacheObject(-1);
  465 + $interval->loadBin($handle);
  466 + array_push($this->intervals, $interval);
  467 + }
  468 +
  469 + //Indexes
  470 + $res = unpack('Ldata',fread($handle,4));
  471 + $nbIndexes = $res['data'];
  472 + for ($i = 0; $i < $nbIndexes; ++$i)
  473 + {
  474 + $res = unpack('Lindex',fread($handle,4));
  475 + array_push($this->indexes, $res['index']);
  476 + }
  477 +
  478 + return true;
  479 + }
  480 +
  481 + protected function getRandomToken() {
  482 + $letters = 'abcefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
  483 + return substr(str_shuffle($letters), 0, TimeTableCacheObject::$token_len);
  484 + }
  485 +
  486 + public function dump() {
  487 + echo " => TimeTableCacheObject : token = ".$this->token.", nb intervals = ".count($this->intervals).", last id = ".$this->lastId.", nb indexes = ".count($this->indexes).PHP_EOL;
  488 + echo PHP_EOL;
  489 +
  490 + $this->filter->dump();
  491 + echo PHP_EOL;
  492 +
  493 + $this->sort->dump();
  494 + echo PHP_EOL;
  495 +
  496 + foreach ($this->intervals as $interval)
  497 + $interval->dump();
  498 + echo PHP_EOL;
  499 +
  500 + echo " => Indexes list : ";
  501 + foreach ($this->indexes as $index)
  502 + {
  503 + echo $index.", ";
  504 + }
  505 + echo PHP_EOL;
  506 + }
  507 +}
  508 +
  509 +?>
0 510 \ No newline at end of file
... ...
php/classes/TimeTableMgr.php
... ... @@ -22,8 +22,6 @@ function timeFormat($myString) {
22 22  
23 23 class TimeTableMgr extends AmdaObjectMgr {
24 24  
25   -//TODO add catalogs as for requestMgr
26   -
27 25  
28 26 function __construct($user) {
29 27 parent::__construct('Tt.xml');
... ... @@ -82,8 +80,13 @@ class TimeTableMgr extends AmdaObjectMgr {
82 80 //if (!($p->intervals)) return true;
83 81 return false;
84 82 }
  83 +
  84 + /*
  85 + * In case of catalogs
  86 + */
  87 + protected function setParamDescription($param) { }
85 88  
86   -
  89 +
87 90 /*
88 91 * Create Time Table
89 92 */
... ... @@ -95,12 +98,15 @@ class TimeTableMgr extends AmdaObjectMgr {
95 98 $this->id = $this->setId();
96 99 $this->created = date('Y-m-d\TH:i:s');
97 100 if (!$this->id) return array('error' => ID_CREATION_ERROR);
  101 +
98 102 $this->resFileName = USERTTDIR.$this->id.'.xml';
  103 + //TODO catalog root element = 'timetable'
99 104 $rootElement = $this->objectDom->createElement('timetable');
100 105 $rootElement->setAttribute('xml:id',$this->id);
101 106  
102 107 foreach ($p as $key => $value)
103   - if ($key != 'id' && $key != 'leaf' && $key != 'nodeType') {
  108 + if ($key != 'id' && $key != 'leaf' && $key != 'nodeType' &&
  109 + $key != 'objName' && $key != 'objFormat' && $key != 'folderId' && $key != 'cacheToken') {
104 110 if ($key == 'created') {
105 111 $rootElement->appendChild($this->objectDom->createElement($key, $this->created));
106 112 }
... ... @@ -114,8 +120,14 @@ class TimeTableMgr extends AmdaObjectMgr {
114 120 $n_int++;
115 121 }
116 122 }*/
  123 + // it is catalog
  124 + else if ($key == 'parameters') {
  125 + $paramsElement = $this->setParamDescription($value);
  126 + if ($paramsElement) $rootElement->appendChild($paramsElement);
  127 +
  128 + }
117 129 else if ($key != 'intervals')
118   - $rootElement->appendChild($this->objectDom->createElement($key, htmlspecialchars($value)));
  130 + $rootElement->appendChild($this->objectDom->createElement($key, htmlspecialchars($value)));
119 131 }
120 132  
121 133 $this->objectDom->appendChild($rootElement);
... ... @@ -418,12 +430,20 @@ class TimeTableMgr extends AmdaObjectMgr {
418 430 'totalCount' => $intervals->length,
419 431 'intervals' => $result,
420 432 'start' => isset($start) ? $start : 0,
421   - 'limit' => isset($limit) ? $limit : 0,
  433 + 'limit' => isset($limit) ? $limit : 0,
422 434 'success' => true
423 435 );
424 436  
425 437 }
426   -
  438 +
  439 + protected function createIntervalElement($interval) {
  440 +
  441 + $newInterval = $this->objectDom->createElement('intervals');
  442 + $newInterval->appendChild($this->objectDom->createElement('start',$interval->start));
  443 + $newInterval->appendChild($this->objectDom->createElement('stop',$interval->stop));
  444 + return $newInterval;
  445 + }
  446 +
427 447 public function saveIntervals($id,$intervals,$action)
428 448 {
429 449 if (substr($id,0,6) == 'shared') {
... ... @@ -457,11 +477,9 @@ class TimeTableMgr extends AmdaObjectMgr {
457 477  
458 478 //add new intervals
459 479 foreach ($intervals as $interval)
460   - {
461   - $newInterval = $this->objectDom->createElement('intervals');
462   - $newInterval->appendChild($this->objectDom->createElement('start',$interval->start));
463   - $newInterval->appendChild($this->objectDom->createElement('stop',$interval->stop));
464   - $this->objectDom->documentElement->appendChild($newInterval);
  480 + {
  481 + $newInterval = $this-> createIntervalElement($interval);
  482 + $this->objectDom->documentElement->appendChild($newInterval);
465 483 }
466 484  
467 485 //save modifications
... ...