]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php
Release 6.4.1
[Github/sugarcrm.git] / modules / ModuleBuilder / parsers / views / GridLayoutMetaDataParser.php
1 <?php
2 if (! defined ( 'sugarEntry' ) || ! sugarEntry)
3     die ( 'Not A Valid Entry Point' ) ;
4 /*********************************************************************************
5  * SugarCRM Community Edition is a customer relationship management program developed by
6  * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
7  * 
8  * This program is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU Affero General Public License version 3 as published by the
10  * Free Software Foundation with the addition of the following permission added
11  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
12  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
13  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14  * 
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
18  * details.
19  * 
20  * You should have received a copy of the GNU Affero General Public License along with
21  * this program; if not, see http://www.gnu.org/licenses or write to the Free
22  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23  * 02110-1301 USA.
24  * 
25  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
26  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27  * 
28  * The interactive user interfaces in modified source and object code versions
29  * of this program must display Appropriate Legal Notices, as required under
30  * Section 5 of the GNU Affero General Public License version 3.
31  * 
32  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
33  * these Appropriate Legal Notices must retain the display of the "Powered by
34  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
35  * technical reasons, the Appropriate Legal Notices must display the words
36  * "Powered by SugarCRM".
37  ********************************************************************************/
38
39
40 require_once 'modules/ModuleBuilder/parsers/views/AbstractMetaDataParser.php' ;
41 require_once 'modules/ModuleBuilder/parsers/views/MetaDataParserInterface.php' ;
42 require_once 'modules/ModuleBuilder/parsers/constants.php' ;
43
44 class GridLayoutMetaDataParser extends AbstractMetaDataParser implements MetaDataParserInterface
45 {
46
47     static $variableMap = array (
48         MB_EDITVIEW => 'EditView' ,
49         MB_DETAILVIEW => 'DetailView' ,
50         MB_QUICKCREATE => 'QuickCreate',
51         ) ;
52
53         protected $FILLER ;
54
55     /*
56      * Constructor
57      * @param string view           The view type, that is, editview, searchview etc
58      * @param string moduleName     The name of the module to which this view belongs
59      * @param string packageName    If not empty, the name of the package to which this view belongs
60      */
61     function __construct ($view , $moduleName , $packageName = '')
62     {
63         $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . "->__construct( {$view} , {$moduleName} , {$packageName} )" ) ;
64
65         $view = strtolower ( $view ) ;
66
67         // BEGIN ASSERTIONS
68         if (! isset ( self::$variableMap [ $view ] ) )
69             sugar_die ( get_class ( $this ) . ": View $view is not supported" ) ;
70         // END ASSERTIONS
71
72                 $this->FILLER = array ( 'name' => MBConstants::$FILLER['name'] , 'label' => translate ( MBConstants::$FILLER['label'] ) ) ;
73
74         $this->_moduleName = $moduleName ;
75         $this->_view = $view ;
76
77         if (empty ( $packageName ))
78         {
79             require_once 'modules/ModuleBuilder/parsers/views/DeployedMetaDataImplementation.php' ;
80             $this->implementation = new DeployedMetaDataImplementation ( $view, $moduleName, self::$variableMap ) ;
81         } else
82         {
83             require_once 'modules/ModuleBuilder/parsers/views/UndeployedMetaDataImplementation.php' ;
84             $this->implementation = new UndeployedMetaDataImplementation ( $view, $moduleName, $packageName ) ;
85         }
86
87         $viewdefs = $this->implementation->getViewdefs () ;
88
89         if (! isset ( $viewdefs [ self::$variableMap [ $view ] ] ))
90             sugar_die ( get_class ( $this ) . ": missing variable " . self::$variableMap [ $view ] . " in layout definition" ) ;
91
92         $viewdefs = $viewdefs [ self::$variableMap [ $view ] ] ;
93         if (! isset ( $viewdefs [ 'templateMeta' ] ))
94             sugar_die ( get_class ( $this ) . ": missing templateMeta section in layout definition (case sensitive)" ) ;
95
96         if (! isset ( $viewdefs [ 'panels' ] ))
97             sugar_die ( get_class ( $this ) . ": missing panels section in layout definition (case sensitive)" ) ;
98
99         $this->_viewdefs = $viewdefs ;
100         if ($this->getMaxColumns () < 1)
101             sugar_die ( get_class ( $this ) . ": maxColumns=" . $this->getMaxColumns () . " - must be greater than 0!" ) ;
102
103         $this->_fielddefs =  $this->implementation->getFielddefs() ;
104         $this->_standardizeFieldLabels( $this->_fielddefs );
105         $this->_viewdefs [ 'panels' ] = $this->_convertFromCanonicalForm ( $this->_viewdefs [ 'panels' ] , $this->_fielddefs ) ; // put into our internal format
106         $this->_originalViewDef = $this->getFieldsFromLayout($this->implementation->getOriginalViewdefs ());
107     }
108
109     /*
110      * Save a draft layout
111      */
112     function writeWorkingFile ($populate = true)
113     {
114         if ($populate)
115             $this->_populateFromRequest ( $this->_fielddefs ) ;
116         
117         $viewdefs = $this->_viewdefs ;
118         $viewdefs [ 'panels' ] = $this->_convertToCanonicalForm ( $this->_viewdefs [ 'panels' ] , $this->_fielddefs ) ;
119         $this->implementation->save ( array ( self::$variableMap [ $this->_view ] => $viewdefs ) ) ;
120     }
121
122     /*
123      * Deploy the layout
124      * @param boolean $populate If true (default), then update the layout first with new layout information from the $_REQUEST array
125      */
126     function handleSave ($populate = true)
127     {
128         $GLOBALS [ 'log' ]->info ( get_class ( $this ) . "->handleSave()" ) ;
129
130         if ($populate)
131             $this->_populateFromRequest ( $this->_fielddefs ) ;
132
133         $viewdefs = $this->_viewdefs ;
134         $viewdefs [ 'panels' ] = $this->_convertToCanonicalForm ( $this->_viewdefs [ 'panels' ] , $this->_fielddefs ) ;
135         $this->implementation->deploy ( array ( self::$variableMap [ $this->_view ] => $viewdefs ) ) ;
136     }
137
138     /*
139      * Return the layout, padded out with (empty) and (filler) fields ready for display
140      */
141     function getLayout ()
142     {
143         $viewdefs = array () ;
144         $fielddefs = $this->_fielddefs;
145         $fielddefs [ $this->FILLER [ 'name' ] ] = $this->FILLER ;
146         $fielddefs [ MBConstants::$EMPTY [ 'name' ] ] = MBConstants::$EMPTY ;
147         
148                 foreach ( $this->_viewdefs [ 'panels' ] as $panelID => $panel )
149         {
150             foreach ( $panel as $rowID => $row )
151             {
152                 foreach ( $row as $colID => $fieldname )
153                 {
154                         if (isset ($this->_fielddefs [ $fieldname ]))
155                                         {
156                                                 $viewdefs [ $panelID ] [ $rowID ] [ $colID ] = self::_trimFieldDefs( $this->_fielddefs [ $fieldname ] ) ;
157                                         } 
158                                         else if (isset($this->_originalViewDef [ $fieldname ]) && is_array($this->_originalViewDef [ $fieldname ]))
159                                         {
160                                                 $viewdefs [ $panelID ] [ $rowID ] [ $colID ] = self::_trimFieldDefs( $this->_originalViewDef [ $fieldname ] ) ;
161                                         } 
162                                         else 
163                                         {
164                                                 $viewdefs [ $panelID ] [ $rowID ] [ $colID ] = array("name" => $fieldname, "label" => $fieldname);
165                                         }
166                 }
167             }
168         }
169         return $viewdefs ;
170     }
171
172     function getMaxColumns ()
173     {
174         if (!empty( $this->_viewdefs) && isset($this->_viewdefs [ 'templateMeta' ] [ 'maxColumns' ]))
175                 {
176                         return $this->_viewdefs [ 'templateMeta' ] [ 'maxColumns' ] ;
177                 }else
178                 {
179                         return 2;
180                 }
181     }
182
183     function getAvailableFields ()
184     {
185
186         // Obtain the full list of valid fields in this module
187         $availableFields = array () ;
188         foreach ( $this->_fielddefs as $key => $def )
189         {
190             if ( GridLayoutMetaDataParser::validField ( $def,  $this->_view ) || isset($this->_originalViewDef[$key]) )
191             {
192                 //If the field original label existing, we should use the original label instead the label in its fielddefs.
193                 if(isset($this->_originalViewDef[$key]) && is_array($this->_originalViewDef[$key]) && isset($this->_originalViewDef[$key]['label'])){
194                     $availableFields [ $key ] = array ( 'name' => $key , 'label' => $this->_originalViewDef[$key]['label']) ; 
195                 }else{
196                     $availableFields [ $key ] = array ( 'name' => $key , 'label' => isset($def [ 'label' ]) ? $def [ 'label' ] : $def['vname'] ) ; // layouts use 'label' not 'vname' for the label entry
197                 }
198
199                 $availableFields[$key]['translatedLabel'] = translate( isset($def [ 'label' ]) ? $def [ 'label' ] : $def['vname'], $this->_moduleName);
200             }
201                         
202         }
203
204                 // Available fields are those that are in the Model and the original layout definition, but not already shown in the View
205         // So, because the formats of the two are different we brute force loop through View and unset the fields we find in a copy of Model
206         if (! empty ( $this->_viewdefs ))
207         {
208             foreach ( $this->_viewdefs [ 'panels' ] as $panel )
209             {
210                 foreach ( $panel as $row )
211                 {
212                     foreach ( $row as $field )
213                     {
214                         unset ( $availableFields [ $field ] ) ;
215                     }
216                 }
217             }
218         }
219         
220         //eggsurplus: Bug 10329 - sort on intuitive display labels
221         //sort by translatedLabel
222         function cmpLabel($a, $b) 
223         {
224             return strcmp($a["translatedLabel"], $b["translatedLabel"]);
225         }
226         usort($availableFields , 'cmpLabel');
227
228         return $availableFields ;
229     }
230
231     function getPanelDependency ( $panelID )
232     {
233         if ( ! isset ( $this->_viewdefs [ 'templateMeta' ][ 'dependency' ] ) && ! isset ( $this->_viewdefs [ 'templateMeta' ][ 'dependency' ] [ $panelID ] ) )
234                 return false;
235
236         return $this->_viewdefs  [ 'templateMeta' ][ 'dependency' ] [ $panelID ] ;
237     }
238
239     /*
240      * Add a new field to the layout
241      * If $panelID is passed in, attempt to add to that panel, otherwise add to the first panel
242      * The field is added in place of the first empty (not filler) slot after the last field in the panel; if that row is full, then a new row will be added to the end of the panel
243      * and the field added to the start of it.
244      * @param array $def Set of properties for the field, in same format as in the viewdefs
245      * @param string $panelID Identifier of the panel to add the field to; empty or false if we should use the first panel
246      */
247     function addField ( $def , $panelID = FALSE)
248     {
249
250         if (count ( $this->_viewdefs [ 'panels' ] ) == 0)
251         {
252             $GLOBALS [ 'log' ]->error ( get_class ( $this ) . "->addField(): _viewdefs empty for module {$this->_moduleName} and view {$this->_view}" ) ;
253         }
254
255         // if a panelID was not provided, use the first available panel in the list
256         if (! $panelID)
257         {
258             $panels = array_keys ( $this->_viewdefs [ 'panels' ] ) ;
259             list ( $dummy, $panelID ) = each ( $panels ) ;
260         }
261
262         if (isset ( $this->_viewdefs [ 'panels' ] [ $panelID ] ))
263         {
264
265             $panel = $this->_viewdefs [ 'panels' ] [ $panelID ] ;
266             $lastrow = count ( $panel ) - 1 ; // index starts at 0
267             $maxColumns = $this->getMaxColumns () ;
268             $lastRowDef = $this->_viewdefs [ 'panels' ] [ $panelID ] [ $lastrow ];
269             for ( $column = 0 ; $column < $maxColumns ; $column ++ )
270             {
271                 if (! isset ( $lastRowDef [ $column ] )
272                         || (is_array( $lastRowDef [ $column ]) && $lastRowDef [ $column ][ 'name' ] == '(empty)')
273                         || (is_string( $lastRowDef [ $column ]) && $lastRowDef [ $column ] == '(empty)')
274                 ){
275                     break ;
276                 }
277             }
278
279             // if we're on the last column of the last row, start a new row
280             if ($column >= $maxColumns)
281             {
282                 $lastrow ++ ;
283                 $this->_viewdefs [ 'panels' ] [ $panelID ] [ $lastrow ] = array ( ) ;
284                 $column = 0 ;
285             }
286
287             $this->_viewdefs [ 'panels' ] [ $panelID ] [ $lastrow ] [ $column ] = $def [ 'name' ] ;
288             // now update the fielddefs
289             if (isset($this->_fielddefs [ $def [ 'name' ] ]))
290             {
291                 $this->_fielddefs [ $def [ 'name' ] ] = array_merge ( $this->_fielddefs [ $def [ 'name' ] ] , $def ) ;
292             } else
293             {
294                 $this->_fielddefs [ $def [ 'name' ] ] = $def;
295             }
296         }
297         return true ;
298     }
299
300     /*
301      * Remove all instances of a field from the layout, and replace by (filler)
302      * Filler because we attempt to preserve the customized layout as much as possible - replacing by (empty) would mean that the positions or sizes of adjacent fields may change
303      * If the last row of a panel only consists of (filler) after removing the fields, then remove the row also. This undoes the standard addField() scenario;
304      * If the fields had been moved around in the layout however then this will not completely undo any addField()
305      * @param string $fieldName Name of the field to remove
306      * @return boolean True if the field was removed; false otherwise
307      */
308     function removeField ($fieldName)
309     {
310         $GLOBALS [ 'log' ]->info ( get_class ( $this ) . "->removeField($fieldName)" ) ;
311
312         $result = false ;
313         reset ( $this->_viewdefs ) ;
314         $firstPanel = each ( $this->_viewdefs [ 'panels' ] ) ;
315         $firstPanelID = $firstPanel [ 'key' ] ;
316
317         foreach ( $this->_viewdefs [ 'panels' ] as $panelID => $panel )
318         {
319             $lastRowTouched = false ;
320             $lastRowID = count ( $this->_viewdefs [ 'panels' ] [ $panelID ] ) - 1 ; // zero offset
321
322             foreach ( $panel as $rowID => $row )
323             {
324
325                 foreach ( $row as $colID => $field )
326                     if ($field == $fieldName)
327                     {
328                         $lastRowTouched = $rowID ;
329                         $this->_viewdefs [ 'panels' ] [ $panelID ] [ $rowID ] [ $colID ] = $this->FILLER [ 'name' ];
330                     }
331
332             }
333
334             // if we removed a field from the last row of this panel, tidy up if the last row now consists only of (empty) or (filler)
335
336             if ( $lastRowTouched ==  $lastRowID )
337             {
338                 $lastRow = $this->_viewdefs [ 'panels' ] [ $panelID ] [ $lastRowID ] ; // can't use 'end' for this as we need the key as well as the value...
339
340                 $empty = true ;
341
342                 foreach ( $lastRow as $colID => $field )
343                     $empty &=  $field == MBConstants::$EMPTY ['name' ] || $field == $this->FILLER [ 'name' ]  ;
344
345                 if ($empty)
346                 {
347                     unset ( $this->_viewdefs [ 'panels' ] [ $panelID ] [ $lastRowID ] ) ;
348                     // if the row was the only one in the panel, and the panel is not the first (default) panel, then remove the panel also
349                                         if ( count ( $this->_viewdefs [ 'panels' ] [ $panelID ] ) == 0 && $panelID != $firstPanelID )
350                                                 unset ( $this->_viewdefs [ 'panels' ] [ $panelID ] ) ;
351                 }
352
353             }
354
355             $result |= ($lastRowTouched !== false ); // explicitly compare to false as row 0 will otherwise evaluate as false
356         }
357
358         return $result ;
359
360     }
361
362     function setPanelDependency ( $panelID , $dependency )
363     {
364         // only accept dependencies for pre-existing panels
365         if ( ! isset ( $this->_viewdefs [ 'panels' ] [ $panelID ] ) )
366                 return false;
367
368         $this->_viewdefs  [ 'templateMeta' ] [ 'dependency' ] [ $panelID ] = $dependency ;
369         return true ;
370     }
371
372     /*
373      * Return an integer value for the next unused panel identifier, such that it and any larger numbers are guaranteed to be unused already in the layout
374      * Necessary when adding new panels to a layout
375      * @return integer First unique panel ID suffix
376      */
377     function getFirstNewPanelId ()
378     {
379         $firstNewPanelId = 0 ;
380         foreach ( $this->_viewdefs [ 'panels' ] as $panelID => $panel )
381         {
382             // strip out all but the numerics from the panelID - can't just use a cast as numbers may not be first in the string
383             for ( $i = 0, $result = '' ; $i < strlen ( $panelID ) ; $i ++ )
384             {
385                 if (is_numeric ( $panelID [ $i ] ))
386                 {
387                     $result .= $panelID [ $i ] ;
388                 }
389             }
390
391             $firstNewPanelId = max ( ( int ) $result, $firstNewPanelId ) ;
392         }
393         return $firstNewPanelId + 1 ;
394     }
395
396     /*
397      * Load the panel layout from the submitted form and update the _viewdefs
398      */
399     protected function _populateFromRequest ( &$fielddefs )
400     {
401         $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . "->populateFromRequest()" ) ;
402         $i = 1 ;
403
404         // set up the map of panel# (as provided in the _REQUEST) to panel ID (as used in $this->_viewdefs['panels'])
405         $i = 1 ;
406         foreach ( $this->_viewdefs [ 'panels' ] as $panelID => $panel )
407         {
408             $panelMap [ $i ++ ] = $panelID ;
409         }
410
411         foreach ( $_REQUEST as $key => $displayLabel )
412         {
413             $components = explode ( '-', $key ) ;
414             if ($components [ 0 ] == 'panel' && $components [ 2 ] == 'label')
415             {
416                 $panelMap [ $components [ '1' ] ] = $displayLabel ;
417             }
418         }
419
420         $this->_viewdefs [ 'panels' ] = array () ; // because the new field properties should replace the old fields, not be merged
421
422         // run through the $_REQUEST twice - first to obtain the fieldnames, the second to update the field properties
423         for ( $pass=1 ; $pass<=2 ; $pass++ )
424         {
425                 foreach ( $_REQUEST as $slot => $value )
426                 {
427                 $slotComponents = explode ( '-', $slot ) ; // [0] = 'slot', [1] = panel #, [2] = slot #, [3] = property name
428
429                 if ($slotComponents [ 0 ] == 'slot')
430                 {
431                         $slotNumber = $slotComponents [ '2' ] ;
432                         $panelID = $panelMap [ $slotComponents [ '1' ] ] ;
433                         $rowID = floor ( $slotNumber / $this->getMaxColumns () ) ;
434                         $colID = $slotNumber - ($rowID * $this->getMaxColumns ()) ;
435                         $property = $slotComponents [ '3' ] ;
436
437                         //If this field has a custom definition, copy that over
438                         if ( $pass == 1 )
439                         {
440                                 if ( $property == 'name' )
441                                 $this->_viewdefs [ 'panels' ] [ $panelID ] [ $rowID ] [ $colID ] = $value ;
442                         } else
443                         {
444                                 // update fielddefs for this property in the provided position
445                                 if ( isset ( $this->_viewdefs [ 'panels' ] [ $panelID ] [ $rowID ] [ $colID ] ) )
446                                 {
447                                         $fieldname = $this->_viewdefs [ 'panels' ] [ $panelID ] [ $rowID ] [ $colID ] ;
448                                                         $fielddefs [ $fieldname ] [ $property ] = $value ;
449                                 }
450                         }
451                 }
452
453                 }
454         }
455         
456         //Set the tabs setting
457         if (isset($_REQUEST['panels_as_tabs']))
458         {
459                 if ($_REQUEST['panels_as_tabs'] == false || $_REQUEST['panels_as_tabs'] == "false")
460                    $this->setUseTabs( false );
461                 else
462                    $this->setUseTabs( true );
463         }
464         
465         //bug: 38232 - Set the sync detail and editview settings
466         if (isset($_REQUEST['sync_detail_and_edit']))
467         {
468                 if ($_REQUEST['sync_detail_and_edit'] === false || $_REQUEST['sync_detail_and_edit'] === "false")
469             {
470                    $this->setSyncDetailEditViews( false );
471             }
472             elseif(!empty($_REQUEST['sync_detail_and_edit']))
473             {
474                    $this->setSyncDetailEditViews( true );
475             }
476         }
477
478         $GLOBALS [ 'log' ]->debug ( print_r ( $this->_viewdefs [ 'panels' ], true ) ) ;
479
480     }
481
482     /*  Convert our internal format back to the standard Canonical MetaData layout
483      *  First non-(empty) field goes in at column 0; all other (empty)'s removed
484      *  Studio required fields are also added to the layout.
485      *  Do this AFTER reading in all the $_REQUEST parameters as can't guarantee the order of those, and we need to operate on complete rows
486      */
487     protected function _convertToCanonicalForm ( $panels , $fielddefs )
488     {
489         $previousViewDef = $this->getFieldsFromLayout($this->implementation->getViewdefs ());
490         $oldDefs = $this->implementation->getViewdefs ();
491         $currentFields = $this->getFieldsFromLayout($this->_viewdefs);
492         foreach($fielddefs as $field => $def)
493         {
494                 if (self::fieldIsRequired($def) && !isset($currentFields[$field]))
495                 {
496                 //Use the previous viewdef if this field was on it.
497                 if (isset($previousViewDef[$field]))
498                 {
499                     $def = $previousViewDef[$field];
500                 }
501                 //next see if the field was on the original layout.
502                 else if (isset ($this->_originalViewDef [ $field ]))
503                 {
504                     $def = $this->_originalViewDef [ $field ] ;   
505                 }
506                 //Otherwise make up a viewdef for it from field_defs
507                 else
508                 {
509                     $def =  self::_trimFieldDefs( $def ) ;
510                 }
511                 $this->addField($def);
512                 }
513         }
514         
515         foreach ( $panels as $panelID => $panel )
516         {
517             // remove all (empty)s
518             foreach ( $panel as $rowID => $row )
519             {
520                 $startOfRow = true ;
521                 $offset = 0 ;
522                 foreach ( $row as $colID => $fieldname )
523                 {
524                     if ($fieldname == MBConstants::$EMPTY[ 'name' ])
525                     {
526                         // if a leading (empty) then remove (by noting that remaining fields need to be shuffled along)
527                         if ($startOfRow)
528                         {
529                             $offset ++ ;
530                         }
531                         unset ( $row [ $colID ] ) ;
532                     } else
533                     {
534                         $startOfRow = false ;
535                     }
536                 }
537
538                 // reindex to remove leading (empty)s and replace fieldnames by full definition from fielddefs
539                 $newRow = array ( ) ;
540                 foreach ( $row as $colID => $fieldname )
541                 {
542                         if ($fieldname == null)
543                            continue;
544                     
545                     //Backwards compatibility and a safeguard against multiple calls to _convertToCanonicalForm
546                            if(is_array($fieldname))
547                     {
548                         $newRow [ $colID - $offset ] = $fieldname;
549                         continue;
550                     }
551                         
552                         //Replace (filler) with the empty string
553                         if ($fieldname == $this->FILLER[ 'name' ]) {
554                         $newRow [ $colID - $offset ] = '' ;
555                     }
556                     //Use the previous viewdef if this field was on it.
557                                         else if (isset($previousViewDef[$fieldname]))
558                         {
559                                  $newRow [ $colID - $offset ] = $previousViewDef[$fieldname];
560                         //We should copy over the tabindex if it is set.
561                         if (isset ($fielddefs [ $fieldname ]) && !empty($fielddefs [ $fieldname ]['tabindex']))
562                             $newRow [ $colID - $offset ]['tabindex'] = $fielddefs [ $fieldname ]['tabindex'];
563                         }
564                     //next see if the field was on the original layout.
565                     else if (isset ($this->_originalViewDef [ $fieldname ]))
566                     {
567                         $newRow [ $colID - $offset ] = $this->_originalViewDef [ $fieldname ] ;  
568                         //We should copy over the tabindex if it is set.
569                         if (isset ($fielddefs [ $fieldname ]) && !empty($fielddefs [ $fieldname ]['tabindex']))
570                             $newRow [ $colID - $offset ]['tabindex'] = $fielddefs [ $fieldname ]['tabindex']; 
571                     }
572                         //Otherwise make up a viewdef for it from field_defs
573                         else if (isset ($fielddefs [ $fieldname ]))
574                         {
575                                 $newRow [ $colID - $offset ] =  self::_trimFieldDefs( $fielddefs [ $fieldname ] ) ;
576                                 
577                         }
578                         //No additional info on this field can be found, jsut use the name;
579                         else 
580                         {
581                         $newRow [ $colID - $offset ] = $fieldname;
582                         }
583                 }
584                 $panels [ $panelID ] [ $rowID ] = $newRow ;
585             }
586         }
587         
588         return $panels ;
589     }
590
591     /*
592      * Convert from the standard MetaData format to our internal format
593      * Replace NULL with (filler) and missing entries with (empty)
594      */
595     protected function _convertFromCanonicalForm ( $panels , $fielddefs )
596     {
597         if (empty ( $panels ))
598             return ;
599
600         // Fix for a flexibility in the format of the panel sections - if only one panel, then we don't have a panel level defined,
601                 // it goes straight into rows
602         // See EditView2 for similar treatment
603         if (! empty ( $panels ) && count ( $panels ) > 0)
604         {
605             $keys = array_keys ( $panels ) ;
606             if (is_numeric ( $keys [ 0 ] ))
607             {
608                 $defaultPanel = $panels ;
609                 unset ( $panels ) ; //blow away current value
610                 $panels [ 'default' ] = $defaultPanel ;
611             }
612         }
613
614         $newPanels = array ( ) ;
615
616         // replace '' with (filler)
617         foreach ( $panels as $panelID => $panel )
618         {
619             foreach ( $panel as $rowID => $row )
620             {
621                 $cols = 0;
622                 foreach ( $row as $colID => $col )
623                 {
624                     if ( ! empty ( $col ) )
625                     {
626                         if ( is_string ( $col ))
627                         {
628                             $fieldname = $col ;
629                         } else if (! empty ( $col [ 'name' ] ))
630                         {
631                             $fieldname = $col [ 'name' ] ;
632                         }
633                     } else
634                     {
635                         $fieldname = $this->FILLER['name'] ;
636                     }
637
638                     $newPanels [ $panelID ] [ $rowID ] [ $cols ] = $fieldname ;
639                     $cols++;
640                 }
641             }
642         }
643
644         // replace missing fields with (empty)
645         foreach ( $newPanels as $panelID => $panel )
646         {
647             $column = 0 ;
648             foreach ( $panel as $rowID => $row )
649             {
650                 // pad between fields on a row
651                 foreach ( $row as $colID => $col )
652                 {
653                     for ( $i = $column + 1 ; $i < $colID ; $i ++ )
654                     {
655                         $row [ $i ] = MBConstants::$EMPTY ['name'];
656                     }
657                     $column = $colID ;
658                 }
659                 // now pad out to the end of the row
660                 if (($column + 1) < $this->getMaxColumns ())
661                 { // last column is maxColumns-1
662                     for ( $i = $column + 1 ; $i < $this->getMaxColumns () ; $i ++ )
663                     {
664                         $row [ $i ] = MBConstants::$EMPTY ['name'] ;
665                     }
666                 }
667                 ksort ( $row ) ;
668                 $newPanels [ $panelID ] [ $rowID ] = $row ;
669             }
670         }
671
672         return $newPanels ;
673     }
674     
675     protected function getFieldsFromLayout($viewdef) {
676         if (isset($viewdef['panels']))
677         {
678                 $panels = $viewdef['panels']; 
679         } else {
680         $panels = $viewdef[self::$variableMap [ $this->_view ] ]['panels']; 
681         }
682         
683         $ret = array();
684         if (is_array($panels)) 
685         {       
686                 foreach ( $panels as $rows) {
687                     foreach ($rows as $fields) {
688                         //wireless layouts have one less level of depth
689                         if (is_array($fields) && isset($fields['name'])) {
690                                 $ret[$fields['name']] = $fields;  
691                                 continue;
692                         }
693                         if (!is_array($fields)) {
694                                 $ret[$fields] = $fields;
695                                 continue;
696                         }
697                         foreach ($fields as $field) {
698                             if (is_array($field) && !empty($field['name']))
699                             {
700                                 $ret[$field['name']] = $field;  
701                             }
702                             else if(!is_array($field)){
703                             $ret[$field] = $field;
704                         }                           
705                         }
706                     }
707                 }
708         }
709         return $ret;
710     }
711     
712     protected function fieldIsRequired($def)
713     {
714         if (isset($def['studio']))
715         { 
716                 if (is_array($def['studio']))
717                 {
718                         if (!empty($def['studio'][$this->_view]) && $def['studio'][$this->_view] == "required")
719                         {
720                                 return true;
721     }
722                         else if (!empty($def['studio']['required']) && $def['studio']['required'] == true)
723                         {
724                                 return true;
725                         }
726                 }
727                 else if ($def['studio'] == "required" ){
728                   return true;
729                 }
730     }
731         return false;
732     }
733
734     static function _trimFieldDefs ( $def )
735         {
736                 $ret = array_intersect_key ( $def , 
737             array ( 'studio' => true , 'name' => true , 'label' => true , 'displayParams' => true , 'comment' => true , 
738                     'customCode' => true , 'customLabel' => true , 'tabindex' => true , 'hideLabel' => true) ) ;
739         if (!empty($def['vname']) && empty($def['label']))
740             $ret['label'] = $def['vname'];
741                 return $ret;
742         }
743         
744         public function getUseTabs(){
745         if (isset($this->_viewdefs  [ 'templateMeta' ]['useTabs']))
746            return $this->_viewdefs  [ 'templateMeta' ]['useTabs'];
747            
748         return false;
749     }
750     
751     public function setUseTabs($useTabs){
752         $this->_viewdefs  [ 'templateMeta' ]['useTabs'] = $useTabs;
753     }
754     
755     /**
756      * Return whether the Detail & EditView should be in sync.
757      */
758         public function getSyncDetailEditViews(){
759         if (isset($this->_viewdefs  [ 'templateMeta' ]['syncDetailEditViews']))
760            return $this->_viewdefs  [ 'templateMeta' ]['syncDetailEditViews'];
761            
762         return false;
763     }
764     
765     /**
766      * Sync DetailView & EditView. This should only be set on the EditView
767      * @param bool $syncViews
768      */
769     public function setSyncDetailEditViews($syncDetailEditViews){
770         $this->_viewdefs  [ 'templateMeta' ]['syncDetailEditViews'] = $syncDetailEditViews;
771     }
772
773     /**
774      * Getter function to get the implementation method which is a private variable
775      * @return DeployedMetaDataImplementation
776      */
777     public function getImplementation(){
778         return $this->implementation;
779     }
780
781     /**
782      * Public access to _convertFromCanonicalForm
783      * @param  $panels
784      * @param  $fielddefs
785      * @return array
786      */
787     public function convertFromCanonicalForm ( $panels , $fielddefs )
788     {
789         return $this->_convertFromCanonicalForm ( $panels , $fielddefs );
790     }
791
792      /**
793      * Public access to _convertToCanonicalForm
794      * @param  $panels
795      * @param  $fielddefs
796      * @return array
797      */
798     public function convertToCanonicalForm ( $panels , $fielddefs )
799     {
800         return $this->_convertToCanonicalForm ( $panels , $fielddefs );
801     }
802
803     
804     /**
805      * @return Array list of fields in this module that have the calculated property
806      */
807     public function getCalculatedFields() {
808         $ret = array();
809         foreach ($this->_fielddefs as $field => $def)
810         {
811             if(!empty($def['calculated']) && !empty($def['formula']))
812             {
813                 $ret[] = $field;
814             }
815         }
816         
817         return $ret;
818     }
819
820     /**
821      * @return Array fields in the given panel
822      */
823     public function getFieldsInPanel($targetPanel) {
824         return iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator($this->_viewdefs['panels'][$targetPanel])));
825     }
826 }
827
828 ?>