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.
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.
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
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
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.
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.
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 ********************************************************************************/
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' ;
44 class GridLayoutMetaDataParser extends AbstractMetaDataParser implements MetaDataParserInterface
47 static $variableMap = array (
48 MB_EDITVIEW => 'EditView' ,
49 MB_DETAILVIEW => 'DetailView' ,
50 MB_QUICKCREATE => 'QuickCreate',
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
61 function __construct ($view , $moduleName , $packageName = '')
63 $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . "->__construct( {$view} , {$moduleName} , {$packageName} )" ) ;
65 $view = strtolower ( $view ) ;
67 $this->FILLER = array ( 'name' => MBConstants::$FILLER['name'] , 'label' => translate ( MBConstants::$FILLER['label'] ) ) ;
69 $this->_moduleName = $moduleName ;
70 $this->_view = $view ;
72 if (empty ( $packageName ))
74 require_once 'modules/ModuleBuilder/parsers/views/DeployedMetaDataImplementation.php' ;
75 $this->implementation = new DeployedMetaDataImplementation ( $view, $moduleName, self::$variableMap ) ;
78 require_once 'modules/ModuleBuilder/parsers/views/UndeployedMetaDataImplementation.php' ;
79 $this->implementation = new UndeployedMetaDataImplementation ( $view, $moduleName, $packageName ) ;
82 $viewdefs = $this->implementation->getViewdefs () ;
83 if (!isset(self::$variableMap [ $view ]))
84 self::$variableMap [ $view ] = $view;
86 if (!isset($viewdefs [ self::$variableMap [ $view ]])){
87 sugar_die ( get_class ( $this ) . ": incorrect view variable for $view" ) ;
90 $viewdefs = $viewdefs [ self::$variableMap [ $view ] ] ;
91 if (! isset ( $viewdefs [ 'templateMeta' ] ))
92 sugar_die ( get_class ( $this ) . ": missing templateMeta section in layout definition (case sensitive)" ) ;
94 if (! isset ( $viewdefs [ 'panels' ] ))
95 sugar_die ( get_class ( $this ) . ": missing panels section in layout definition (case sensitive)" ) ;
97 $this->_viewdefs = $viewdefs ;
98 if ($this->getMaxColumns () < 1)
99 sugar_die ( get_class ( $this ) . ": maxColumns=" . $this->getMaxColumns () . " - must be greater than 0!" ) ;
101 $this->_fielddefs = $this->implementation->getFielddefs() ;
102 $this->_standardizeFieldLabels( $this->_fielddefs );
103 $this->_viewdefs [ 'panels' ] = $this->_convertFromCanonicalForm ( $this->_viewdefs [ 'panels' ] , $this->_fielddefs ) ; // put into our internal format
104 $this->_originalViewDef = $this->getFieldsFromLayout($this->implementation->getOriginalViewdefs ());
108 * Save a draft layout
110 function writeWorkingFile ($populate = true)
113 $this->_populateFromRequest ( $this->_fielddefs ) ;
115 $viewdefs = $this->_viewdefs ;
116 $viewdefs [ 'panels' ] = $this->_convertToCanonicalForm ( $this->_viewdefs [ 'panels' ] , $this->_fielddefs ) ;
117 $this->implementation->save ( array ( self::$variableMap [ $this->_view ] => $viewdefs ) ) ;
122 * @param boolean $populate If true (default), then update the layout first with new layout information from the $_REQUEST array
124 function handleSave ($populate = true)
126 $GLOBALS [ 'log' ]->info ( get_class ( $this ) . "->handleSave()" ) ;
129 $this->_populateFromRequest ( $this->_fielddefs ) ;
131 $viewdefs = $this->_viewdefs ;
132 $viewdefs [ 'panels' ] = $this->_convertToCanonicalForm ( $this->_viewdefs [ 'panels' ] , $this->_fielddefs ) ;
133 $this->implementation->deploy ( array ( self::$variableMap [ $this->_view ] => $viewdefs ) ) ;
137 * Return the layout, padded out with (empty) and (filler) fields ready for display
139 function getLayout ()
141 $viewdefs = array () ;
142 $fielddefs = $this->_fielddefs;
143 $fielddefs [ $this->FILLER [ 'name' ] ] = $this->FILLER ;
144 $fielddefs [ MBConstants::$EMPTY [ 'name' ] ] = MBConstants::$EMPTY ;
146 foreach ( $this->_viewdefs [ 'panels' ] as $panelID => $panel )
148 foreach ( $panel as $rowID => $row )
150 foreach ( $row as $colID => $fieldname )
152 if (isset ($this->_fielddefs [ $fieldname ]))
154 $viewdefs [ $panelID ] [ $rowID ] [ $colID ] = self::_trimFieldDefs( $this->_fielddefs [ $fieldname ] ) ;
156 else if (isset($this->_originalViewDef [ $fieldname ]) && is_array($this->_originalViewDef [ $fieldname ]))
158 $viewdefs [ $panelID ] [ $rowID ] [ $colID ] = self::_trimFieldDefs( $this->_originalViewDef [ $fieldname ] ) ;
162 $viewdefs [ $panelID ] [ $rowID ] [ $colID ] = array("name" => $fieldname, "label" => $fieldname);
171 * Return the tab definitions for tab/panel combo
173 function getTabDefs ()
176 $this->setUseTabs( false );
177 foreach ( $this->_viewdefs [ 'panels' ] as $panelID => $panel )
180 $tabDefs [ strtoupper($panelID) ] = array();
182 // panel or tab setting
183 if ( isset($this->_viewdefs [ 'templateMeta' ] [ 'tabDefs' ] [ strtoupper($panelID) ] [ 'newTab' ])
184 && is_bool($this->_viewdefs [ 'templateMeta' ] [ 'tabDefs' ] [ strtoupper($panelID) ] [ 'newTab' ]))
186 $tabDefs [ strtoupper($panelID) ] [ 'newTab' ] = $this->_viewdefs [ 'templateMeta' ] [ 'tabDefs' ] [ strtoupper($panelID) ] [ 'newTab' ];
187 if ($tabDefs [ strtoupper($panelID) ] [ 'newTab' ] == true)
188 $this->setUseTabs( true );
192 $tabDefs [ strtoupper($panelID) ] [ 'newTab' ] = false;
196 if ( isset($this->_viewdefs [ 'templateMeta' ] [ 'tabDefs' ] [ strtoupper($panelID) ] [ 'panelDefault' ])
197 && $this->_viewdefs [ 'templateMeta' ] [ 'tabDefs' ] [ strtoupper($panelID) ] [ 'panelDefault' ] == 'collapsed' )
199 $tabDefs [ strtoupper($panelID) ] [ 'panelDefault' ] = 'collapsed';
203 $tabDefs [ strtoupper($panelID) ] [ 'panelDefault' ] = 'expanded';
210 * Set tab definitions
212 function setTabDefs($tabDefs) {
213 $this->_viewdefs [ 'templateMeta' ] [ 'tabDefs' ] = $tabDefs;
216 function getMaxColumns ()
218 if (!empty( $this->_viewdefs) && isset($this->_viewdefs [ 'templateMeta' ] [ 'maxColumns' ]))
220 return $this->_viewdefs [ 'templateMeta' ] [ 'maxColumns' ] ;
227 function getAvailableFields ()
230 // Obtain the full list of valid fields in this module
231 $availableFields = array () ;
232 foreach ( $this->_fielddefs as $key => $def )
234 if ( GridLayoutMetaDataParser::validField ( $def, $this->_view ) || isset($this->_originalViewDef[$key]) )
236 //If the field original label existing, we should use the original label instead the label in its fielddefs.
237 if(isset($this->_originalViewDef[$key]) && is_array($this->_originalViewDef[$key]) && isset($this->_originalViewDef[$key]['label'])){
238 $availableFields [ $key ] = array ( 'name' => $key , 'label' => $this->_originalViewDef[$key]['label']) ;
240 $availableFields [ $key ] = array ( 'name' => $key , 'label' => isset($def [ 'label' ]) ? $def [ 'label' ] : $def['vname'] ) ; // layouts use 'label' not 'vname' for the label entry
243 $availableFields[$key]['translatedLabel'] = translate( isset($def [ 'label' ]) ? $def [ 'label' ] : $def['vname'], $this->_moduleName);
248 // Available fields are those that are in the Model and the original layout definition, but not already shown in the View
249 // 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
250 if (! empty ( $this->_viewdefs ))
252 foreach ( $this->_viewdefs [ 'panels' ] as $panel )
254 foreach ( $panel as $row )
256 foreach ( $row as $field )
258 unset ( $availableFields [ $field ] ) ;
264 //eggsurplus: Bug 10329 - sort on intuitive display labels
265 //sort by translatedLabel
266 function cmpLabel($a, $b)
268 return strcmp($a["translatedLabel"], $b["translatedLabel"]);
270 usort($availableFields , 'cmpLabel');
272 return $availableFields ;
275 function getPanelDependency ( $panelID )
277 if ( ! isset ( $this->_viewdefs [ 'templateMeta' ][ 'dependency' ] ) && ! isset ( $this->_viewdefs [ 'templateMeta' ][ 'dependency' ] [ $panelID ] ) )
280 return $this->_viewdefs [ 'templateMeta' ][ 'dependency' ] [ $panelID ] ;
284 * Add a new field to the layout
285 * If $panelID is passed in, attempt to add to that panel, otherwise add to the first panel
286 * 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
287 * and the field added to the start of it.
288 * @param array $def Set of properties for the field, in same format as in the viewdefs
289 * @param string $panelID Identifier of the panel to add the field to; empty or false if we should use the first panel
291 function addField ( $def , $panelID = FALSE)
294 if (count ( $this->_viewdefs [ 'panels' ] ) == 0)
296 $GLOBALS [ 'log' ]->error ( get_class ( $this ) . "->addField(): _viewdefs empty for module {$this->_moduleName} and view {$this->_view}" ) ;
299 // if a panelID was not provided, use the first available panel in the list
302 $panels = array_keys ( $this->_viewdefs [ 'panels' ] ) ;
303 list ( $dummy, $panelID ) = each ( $panels ) ;
306 if (isset ( $this->_viewdefs [ 'panels' ] [ $panelID ] ))
309 $panel = $this->_viewdefs [ 'panels' ] [ $panelID ] ;
310 $lastrow = count ( $panel ) - 1 ; // index starts at 0
311 $maxColumns = $this->getMaxColumns () ;
312 $lastRowDef = $this->_viewdefs [ 'panels' ] [ $panelID ] [ $lastrow ];
313 for ( $column = 0 ; $column < $maxColumns ; $column ++ )
315 if (! isset ( $lastRowDef [ $column ] )
316 || (is_array( $lastRowDef [ $column ]) && $lastRowDef [ $column ][ 'name' ] == '(empty)')
317 || (is_string( $lastRowDef [ $column ]) && $lastRowDef [ $column ] == '(empty)')
323 // if we're on the last column of the last row, start a new row
324 if ($column >= $maxColumns)
327 $this->_viewdefs [ 'panels' ] [ $panelID ] [ $lastrow ] = array ( ) ;
331 $this->_viewdefs [ 'panels' ] [ $panelID ] [ $lastrow ] [ $column ] = $def [ 'name' ] ;
332 // now update the fielddefs
333 if (isset($this->_fielddefs [ $def [ 'name' ] ]))
335 $this->_fielddefs [ $def [ 'name' ] ] = array_merge ( $this->_fielddefs [ $def [ 'name' ] ] , $def ) ;
338 $this->_fielddefs [ $def [ 'name' ] ] = $def;
345 * Remove all instances of a field from the layout, and replace by (filler)
346 * 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
347 * 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;
348 * If the fields had been moved around in the layout however then this will not completely undo any addField()
349 * @param string $fieldName Name of the field to remove
350 * @return boolean True if the field was removed; false otherwise
352 function removeField ($fieldName)
354 $GLOBALS [ 'log' ]->info ( get_class ( $this ) . "->removeField($fieldName)" ) ;
357 reset ( $this->_viewdefs ) ;
358 $firstPanel = each ( $this->_viewdefs [ 'panels' ] ) ;
359 $firstPanelID = $firstPanel [ 'key' ] ;
361 foreach ( $this->_viewdefs [ 'panels' ] as $panelID => $panel )
363 $lastRowTouched = false ;
364 $lastRowID = count ( $this->_viewdefs [ 'panels' ] [ $panelID ] ) - 1 ; // zero offset
366 foreach ( $panel as $rowID => $row )
369 foreach ( $row as $colID => $field )
370 if ($field == $fieldName)
372 $lastRowTouched = $rowID ;
373 $this->_viewdefs [ 'panels' ] [ $panelID ] [ $rowID ] [ $colID ] = $this->FILLER [ 'name' ];
378 // 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)
380 if ( $lastRowTouched == $lastRowID )
382 $lastRow = $this->_viewdefs [ 'panels' ] [ $panelID ] [ $lastRowID ] ; // can't use 'end' for this as we need the key as well as the value...
386 foreach ( $lastRow as $colID => $field )
387 $empty &= $field == MBConstants::$EMPTY ['name' ] || $field == $this->FILLER [ 'name' ] ;
391 unset ( $this->_viewdefs [ 'panels' ] [ $panelID ] [ $lastRowID ] ) ;
392 // if the row was the only one in the panel, and the panel is not the first (default) panel, then remove the panel also
393 if ( count ( $this->_viewdefs [ 'panels' ] [ $panelID ] ) == 0 && $panelID != $firstPanelID )
394 unset ( $this->_viewdefs [ 'panels' ] [ $panelID ] ) ;
399 $result |= ($lastRowTouched !== false ); // explicitly compare to false as row 0 will otherwise evaluate as false
406 function setPanelDependency ( $panelID , $dependency )
408 // only accept dependencies for pre-existing panels
409 if ( ! isset ( $this->_viewdefs [ 'panels' ] [ $panelID ] ) )
412 $this->_viewdefs [ 'templateMeta' ] [ 'dependency' ] [ $panelID ] = $dependency ;
417 * 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
418 * Necessary when adding new panels to a layout
419 * @return integer First unique panel ID suffix
421 function getFirstNewPanelId ()
423 $firstNewPanelId = 0 ;
424 foreach ( $this->_viewdefs [ 'panels' ] as $panelID => $panel )
426 // strip out all but the numerics from the panelID - can't just use a cast as numbers may not be first in the string
427 for ( $i = 0, $result = '' ; $i < strlen ( $panelID ) ; $i ++ )
429 if (is_numeric ( $panelID [ $i ] ))
431 $result .= $panelID [ $i ] ;
435 $firstNewPanelId = max ( ( int ) $result, $firstNewPanelId ) ;
437 return $firstNewPanelId + 1 ;
441 * Load the panel layout from the submitted form and update the _viewdefs
443 protected function _populateFromRequest ( &$fielddefs )
445 $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . "->populateFromRequest()" ) ;
448 // set up the map of panel# (as provided in the _REQUEST) to panel ID (as used in $this->_viewdefs['panels'])
450 foreach ( $this->_viewdefs [ 'panels' ] as $panelID => $panel )
452 $panelMap [ $i ++ ] = $panelID ;
455 foreach ( $_REQUEST as $key => $displayLabel )
457 $components = explode ( '-', $key ) ;
458 if ($components [ 0 ] == 'panel' && $components [ 2 ] == 'label')
460 $panelMap [ $components [ '1' ] ] = $displayLabel ;
464 $this->_viewdefs [ 'panels' ] = array () ; // because the new field properties should replace the old fields, not be merged
466 // run through the $_REQUEST twice - first to obtain the fieldnames, the second to update the field properties
467 for ( $pass=1 ; $pass<=2 ; $pass++ )
469 foreach ( $_REQUEST as $slot => $value )
471 $slotComponents = explode ( '-', $slot ) ; // [0] = 'slot', [1] = panel #, [2] = slot #, [3] = property name
473 if ($slotComponents [ 0 ] == 'slot')
475 $slotNumber = $slotComponents [ '2' ] ;
476 $panelID = $panelMap [ $slotComponents [ '1' ] ] ;
477 $rowID = floor ( $slotNumber / $this->getMaxColumns () ) ;
478 $colID = $slotNumber - ($rowID * $this->getMaxColumns ()) ;
479 $property = $slotComponents [ '3' ] ;
481 //If this field has a custom definition, copy that over
484 if ( $property == 'name' )
485 $this->_viewdefs [ 'panels' ] [ $panelID ] [ $rowID ] [ $colID ] = $value ;
488 // update fielddefs for this property in the provided position
489 if ( isset ( $this->_viewdefs [ 'panels' ] [ $panelID ] [ $rowID ] [ $colID ] ) )
491 $fieldname = $this->_viewdefs [ 'panels' ] [ $panelID ] [ $rowID ] [ $colID ] ;
492 $fielddefs [ $fieldname ] [ $property ] = $value ;
501 //Set the tabs setting
502 if (isset($_REQUEST['panels_as_tabs']))
504 if ($_REQUEST['panels_as_tabs'] == false || $_REQUEST['panels_as_tabs'] == "false")
505 $this->setUseTabs( false );
507 $this->setUseTabs( true );
511 //Set the tab definitions
513 $this->setUseTabs( false );
514 foreach ( $this->_viewdefs [ 'panels' ] as $panelID => $panel )
516 // panel or tab setting
517 $tabDefs [ strtoupper($panelID) ] = array();
518 if ( isset($_REQUEST['tabDefs_'.$panelID.'_newTab']) )
520 $tabDefs [ strtoupper($panelID) ] [ 'newTab' ] = ( $_REQUEST['tabDefs_'.$panelID.'_newTab'] == '1' ) ? true : false;
521 if ($tabDefs [ strtoupper($panelID) ] [ 'newTab' ] == true)
522 $this->setUseTabs( true );
526 $tabDefs [ strtoupper($panelID) ] [ 'newTab' ] = false;
530 if ( isset($_REQUEST['tabDefs_'.$panelID.'_panelDefault']) )
532 $tabDefs [ strtoupper($panelID) ] [ 'panelDefault' ] = ( $_REQUEST['tabDefs_'.$panelID.'_panelDefault'] == 'collapsed' ) ? 'collapsed' : 'expanded';
536 $tabDefs [ strtoupper($panelID) ] [ 'panelDefault' ] = 'expanded';
540 $this->setTabDefs($tabDefs);
542 //bug: 38232 - Set the sync detail and editview settings
543 if (isset($_REQUEST['sync_detail_and_edit']))
545 if ($_REQUEST['sync_detail_and_edit'] === false || $_REQUEST['sync_detail_and_edit'] === "false")
547 $this->setSyncDetailEditViews( false );
549 elseif(!empty($_REQUEST['sync_detail_and_edit']))
551 $this->setSyncDetailEditViews( true );
555 $GLOBALS [ 'log' ]->debug ( print_r ( $this->_viewdefs [ 'panels' ], true ) ) ;
559 /* Convert our internal format back to the standard Canonical MetaData layout
560 * First non-(empty) field goes in at column 0; all other (empty)'s removed
561 * Studio required fields are also added to the layout.
562 * 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
564 protected function _convertToCanonicalForm ( $panels , $fielddefs )
566 $previousViewDef = $this->getFieldsFromLayout($this->implementation->getViewdefs ());
567 $oldDefs = $this->implementation->getViewdefs ();
568 $currentFields = $this->getFieldsFromLayout($this->_viewdefs);
569 foreach($fielddefs as $field => $def)
571 if (self::fieldIsRequired($def) && !isset($currentFields[$field]))
573 //Use the previous viewdef if this field was on it.
574 if (isset($previousViewDef[$field]))
576 $def = $previousViewDef[$field];
578 //next see if the field was on the original layout.
579 else if (isset ($this->_originalViewDef [ $field ]))
581 $def = $this->_originalViewDef [ $field ] ;
583 //Otherwise make up a viewdef for it from field_defs
586 $def = self::_trimFieldDefs( $def ) ;
588 $this->addField($def);
592 foreach ( $panels as $panelID => $panel )
594 // remove all (empty)s
595 foreach ( $panel as $rowID => $row )
599 foreach ( $row as $colID => $fieldname )
601 if ($fieldname == MBConstants::$EMPTY[ 'name' ])
603 // if a leading (empty) then remove (by noting that remaining fields need to be shuffled along)
608 unset ( $row [ $colID ] ) ;
611 $startOfRow = false ;
615 // reindex to remove leading (empty)s and replace fieldnames by full definition from fielddefs
616 $newRow = array ( ) ;
617 foreach ( $row as $colID => $fieldname )
619 if ($fieldname == null )
621 //Backwards compatibility and a safeguard against multiple calls to _convertToCanonicalForm
622 if(is_array($fieldname))
625 $newRow [ $colID - $offset ] = $fieldname;
627 }else if(!isset($fielddefs[$fieldname])){
631 //Replace (filler) with the empty string
632 if ($fieldname == $this->FILLER[ 'name' ]) {
633 $newRow [ $colID - $offset ] = '' ;
635 //Use the previous viewdef if this field was on it.
636 else if (isset($previousViewDef[$fieldname]))
638 $newRow[$colID - $offset] = $this->getNewRowItem($previousViewDef[$fieldname], $fielddefs[$fieldname]);
640 //next see if the field was on the original layout.
641 else if (isset ($this->_originalViewDef [ $fieldname ]))
643 $newRow[$colID - $offset] = $this->getNewRowItem($this->_originalViewDef[$fieldname], $fielddefs[$fieldname]);
645 //Otherwise make up a viewdef for it from field_defs
646 else if (isset ($fielddefs [ $fieldname ]))
648 $newRow [ $colID - $offset ] = self::_trimFieldDefs( $fielddefs [ $fieldname ] ) ;
651 //No additional info on this field can be found, jsut use the name;
654 $newRow [ $colID - $offset ] = $fieldname;
657 $panels [ $panelID ] [ $rowID ] = $newRow ;
665 * fixing bug #44428: Studio | Tab Order causes layout errors
666 * @param string|array $source it can be a string which contain just a name of field
667 * or an array with field attributes including name
668 * @param array $fielddef stores field defs from request
669 * @return string|array definition of new row item
671 function getNewRowItem($source, $fielddef)
673 //We should copy over the tabindex if it is set.
675 if (isset ($fielddef) && !empty($fielddef['tabindex']))
677 if (is_array($source))
683 $newRow['name'] = $source;
685 $newRow['tabindex'] = $fielddef['tabindex'];
695 * Convert from the standard MetaData format to our internal format
696 * Replace NULL with (filler) and missing entries with (empty)
698 protected function _convertFromCanonicalForm ( $panels , $fielddefs )
700 if (empty ( $panels ))
703 // Fix for a flexibility in the format of the panel sections - if only one panel, then we don't have a panel level defined,
704 // it goes straight into rows
705 // See EditView2 for similar treatment
706 if (! empty ( $panels ) && count ( $panels ) > 0)
708 $keys = array_keys ( $panels ) ;
709 if (is_numeric ( $keys [ 0 ] ))
711 $defaultPanel = $panels ;
712 unset ( $panels ) ; //blow away current value
713 $panels [ 'default' ] = $defaultPanel ;
717 $newPanels = array ( ) ;
719 // replace '' with (filler)
720 foreach ( $panels as $panelID => $panel )
722 foreach ( $panel as $rowID => $row )
725 foreach ( $row as $colID => $col )
727 if ( ! empty ( $col ) )
729 if ( is_string ( $col ))
732 } else if (! empty ( $col [ 'name' ] ))
734 $fieldname = $col [ 'name' ] ;
738 $fieldname = $this->FILLER['name'] ;
741 $newPanels [ $panelID ] [ $rowID ] [ $cols ] = $fieldname ;
747 // replace missing fields with (empty)
748 foreach ( $newPanels as $panelID => $panel )
751 foreach ( $panel as $rowID => $row )
753 // pad between fields on a row
754 foreach ( $row as $colID => $col )
756 for ( $i = $column + 1 ; $i < $colID ; $i ++ )
758 $row [ $i ] = MBConstants::$EMPTY ['name'];
762 // now pad out to the end of the row
763 if (($column + 1) < $this->getMaxColumns ())
764 { // last column is maxColumns-1
765 for ( $i = $column + 1 ; $i < $this->getMaxColumns () ; $i ++ )
767 $row [ $i ] = MBConstants::$EMPTY ['name'] ;
771 $newPanels [ $panelID ] [ $rowID ] = $row ;
778 protected function getFieldsFromLayout($viewdef) {
779 if (isset($viewdef['panels']))
781 $panels = $viewdef['panels'];
783 $panels = $viewdef[self::$variableMap [ $this->_view ] ]['panels'];
787 if (is_array($panels))
789 foreach ( $panels as $rows) {
790 foreach ($rows as $fields) {
791 if (!is_array($fields)) {
792 $ret[$fields] = $fields;
795 foreach ($fields as $field) {
796 if (is_array($field) && !empty($field['name']))
798 $ret[$field['name']] = $field;
800 else if(!is_array($field)){
801 $ret[$field] = $field;
810 protected function fieldIsRequired($def)
812 if (isset($def['studio']))
814 if (is_array($def['studio']))
816 if (!empty($def['studio'][$this->_view]) && $def['studio'][$this->_view] == "required")
820 else if (!empty($def['studio']['required']) && $def['studio']['required'] == true)
825 else if ($def['studio'] == "required" ){
832 static function _trimFieldDefs ( $def )
834 $ret = array_intersect_key ( $def ,
835 array ( 'studio' => true , 'name' => true , 'label' => true , 'displayParams' => true , 'comment' => true ,
836 'customCode' => true , 'customLabel' => true , 'tabindex' => true , 'hideLabel' => true) ) ;
837 if (!empty($def['vname']) && empty($def['label']))
838 $ret['label'] = $def['vname'];
842 public function getUseTabs(){
843 if (isset($this->_viewdefs [ 'templateMeta' ]['useTabs']))
844 return $this->_viewdefs [ 'templateMeta' ]['useTabs'];
849 public function setUseTabs($useTabs){
850 $this->_viewdefs [ 'templateMeta' ]['useTabs'] = $useTabs;
854 * Return whether the Detail & EditView should be in sync.
856 public function getSyncDetailEditViews(){
857 if (isset($this->_viewdefs [ 'templateMeta' ]['syncDetailEditViews']))
858 return $this->_viewdefs [ 'templateMeta' ]['syncDetailEditViews'];
864 * Sync DetailView & EditView. This should only be set on the EditView
865 * @param bool $syncViews
867 public function setSyncDetailEditViews($syncDetailEditViews){
868 $this->_viewdefs [ 'templateMeta' ]['syncDetailEditViews'] = $syncDetailEditViews;
872 * Getter function to get the implementation method which is a private variable
873 * @return DeployedMetaDataImplementation
875 public function getImplementation(){
876 return $this->implementation;
880 * Public access to _convertFromCanonicalForm
885 public function convertFromCanonicalForm ( $panels , $fielddefs )
887 return $this->_convertFromCanonicalForm ( $panels , $fielddefs );
891 * Public access to _convertToCanonicalForm
896 public function convertToCanonicalForm ( $panels , $fielddefs )
898 return $this->_convertToCanonicalForm ( $panels , $fielddefs );
903 * @return Array list of fields in this module that have the calculated property
905 public function getCalculatedFields() {
907 foreach ($this->_fielddefs as $field => $def)
909 if(!empty($def['calculated']) && !empty($def['formula']))
919 * @return Array fields in the given panel
921 public function getFieldsInPanel($targetPanel) {
922 return iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator($this->_viewdefs['panels'][$targetPanel])));