]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/MVC/View/SugarView.php
Release 6.3.1
[Github/sugarcrm.git] / include / MVC / View / SugarView.php
1 <?php
2 /*********************************************************************************
3  * SugarCRM Community Edition is a customer relationship management program developed by
4  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
5  * 
6  * This program is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Affero General Public License version 3 as published by the
8  * Free Software Foundation with the addition of the following permission added
9  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12  * 
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
16  * details.
17  * 
18  * You should have received a copy of the GNU Affero General Public License along with
19  * this program; if not, see http://www.gnu.org/licenses or write to the Free
20  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  * 02110-1301 USA.
22  * 
23  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
25  * 
26  * The interactive user interfaces in modified source and object code versions
27  * of this program must display Appropriate Legal Notices, as required under
28  * Section 5 of the GNU Affero General Public License version 3.
29  * 
30  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31  * these Appropriate Legal Notices must retain the display of the "Powered by
32  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33  * technical reasons, the Appropriate Legal Notices must display the words
34  * "Powered by SugarCRM".
35  ********************************************************************************/
36
37 class SugarView
38 {
39     /**
40      * This array is meant to hold an objects/data that we would like to pass between
41      * the controller and the view.  The bean will automatically be set for us, but this
42      * is meant to hold anything else.
43      */
44     var $view_object_map = array();
45     /**
46      * The name of the current module.
47      */
48     var $module = '';
49     /**
50      * The name of the current action.
51      */
52     var $action = '';
53     /**
54      */
55     var $bean = null;
56     /**
57      * Sugar_Smarty. This is useful if you have a view and a subview you can
58      * share the same smarty object.
59      */
60     var $ss = null;
61     /**
62      * Any errors that occured this can either be set by the view or the controller or the model
63      */
64     var $errors = array();
65     /**
66      * Set to true if you do not want to display errors from SugarView::displayErrors(); instead they will be returned
67      */
68     var $suppressDisplayErrors = false;
69
70     /**
71      * Options for what UI elements to hide/show/
72      */
73     var $options = array('show_header' => true, 'show_title' => true, 'show_subpanels' => false, 'show_search' => true, 'show_footer' => true, 'show_javascript' => true, 'view_print' => false,);
74     var $type = null;
75     var $responseTime;
76     var $fileResources;
77
78     /**
79      * Constructor which will peform the setup.
80      */
81     public function SugarView(
82         $bean = null,
83         $view_object_map = array()
84         )
85     {
86     }
87
88     public function init(
89         $bean = null,
90         $view_object_map = array()
91         )
92     {
93         $this->bean = $bean;
94         $this->view_object_map = $view_object_map;
95         $this->action = $GLOBALS['action'];
96         $this->module = $GLOBALS['module'];
97         $this->_initSmarty();
98     }
99
100     protected function _initSmarty()
101     {
102         $this->ss = new Sugar_Smarty();
103         $this->ss->assign('MOD', $GLOBALS['mod_strings']);
104         $this->ss->assign('APP', $GLOBALS['app_strings']);
105     }
106
107     /**
108      * This method will be called from the controller and is not meant to be overridden.
109      */
110     public function process()
111     {
112         LogicHook::initialize();
113         $this->_checkModule();
114
115         //trackView has to be here in order to track for breadcrumbs
116         $this->_trackView();
117
118         //For the ajaxUI, we need to use output buffering to return the page in an ajax friendly format
119         if ($this->_getOption('json_output')){
120                         ob_start();
121                         if(!empty($_REQUEST['ajax_load']) && !empty($_REQUEST['loadLanguageJS'])){
122                                 echo $this->_getModLanguageJS();
123                         }
124                 }
125
126         if ($this->_getOption('show_header')) {
127             $this->displayHeader();
128         } else {
129             $this->renderJavascript();
130         }
131
132         $this->_buildModuleList();
133         $this->preDisplay();
134         $this->displayErrors();
135         $this->display();
136         if ( !empty($this->module) ) {
137             $GLOBALS['logic_hook']->call_custom_logic($this->module, 'after_ui_frame');
138         } else {
139             $GLOBALS['logic_hook']->call_custom_logic('', 'after_ui_frame');
140         }
141
142         if ($this->_getOption('show_subpanels') && !empty($_REQUEST['record'])) $this->_displaySubPanels();
143
144         if ($this->action === 'Login') {
145             //this is needed for a faster loading login page ie won't render unless the tables are closed
146             ob_flush();
147         }
148         if ($this->_getOption('show_footer')) $this->displayFooter();
149         $GLOBALS['logic_hook']->call_custom_logic('', 'after_ui_footer');
150         if ($this->_getOption('json_output'))
151         {
152             $content = ob_get_clean();
153             $module = $this->module;
154             $ajax_ret = array(
155                 'content' => mb_detect_encoding($content) == "UTF-8" ? $content : utf8_encode($content),
156                  'menu' => array(
157                      'module' => $module,
158                      'label' => translate($module),
159                      $this->getMenu($module),
160                  ),
161                 'moduleList' => $this->displayHeader(true),
162                 'title' => $this->getBrowserTitle(),
163                 'action' => isset($_REQUEST['action']) ? $_REQUEST['action'] : "",
164                 'record' => isset($_REQUEST['record']) ? $_REQUEST['record'] : "",
165             );
166             if(empty($this->responseTime)) $this->_calculateFooterMetrics();
167             $ajax_ret['responseTime'] = $this->responseTime;
168             $json = getJSONobj();
169             echo $json->encode($ajax_ret);
170             $GLOBALS['app']->headerDisplayed = false;
171             ob_flush();
172         }
173         //Do not track if there is no module or if module is not a String
174         $this->_track();
175     }
176
177     /**
178      * This method will display the errors on the page.
179      */
180     public function displayErrors()
181     {
182         $errors = '';
183
184         foreach($this->errors as $error) {
185             $errors .= '<span class="error">' . $error . '</span><br>';
186         }
187
188         if ( !$this->suppressDisplayErrors ) {
189             echo $errors;
190         }
191         else {
192             return $errors;
193         }
194     }
195
196     /**
197      * [OVERRIDE] - This method is meant to overidden in a subclass. The purpose of this method is
198      * to allow a view to do some preprocessing before the display method is called. This becomes
199      * useful when you have a view defined at the application level and then within a module
200      * have a sub-view that extends from this application level view.  The application level
201      * view can do the setup in preDisplay() that is common to itself and any subviews
202      * and then the subview can just override display(). If it so desires, can also override
203      * preDisplay().
204      */
205     public function preDisplay()
206     {
207     }
208
209     /**
210      * [OVERRIDE] - This method is meant to overidden in a subclass. This method
211      * will handle the actual display logic of the view.
212      */
213     public function display()
214     {
215     }
216
217
218     /**
219      * trackView
220      */
221     protected function _trackView()
222     {
223         $action = strtolower($this->action);
224         //Skip save, tracked in SugarBean instead
225         if($action == 'save') {
226         return;
227         }
228
229
230         $trackerManager = TrackerManager::getInstance();
231         $timeStamp = TimeDate::getInstance()->nowDb();
232         if($monitor = $trackerManager->getMonitor('tracker')){
233             $monitor->setValue('action', $action);
234             $monitor->setValue('user_id', $GLOBALS['current_user']->id);
235             $monitor->setValue('module_name', $this->module);
236             $monitor->setValue('date_modified', $timeStamp);
237             $monitor->setValue('visible', (($monitor->action == 'detailview') || ($monitor->action == 'editview')
238                                             ) ? 1 : 0);
239
240             if (!empty($this->bean->id)) {
241                 $monitor->setValue('item_id', $this->bean->id);
242                 $monitor->setValue('item_summary', $this->bean->get_summary_text());
243             }
244
245             //If visible is true, but there is no bean, do not track (invalid/unauthorized reference)
246             //Also, do not track save actions where there is no bean id
247             if($monitor->visible && empty($this->bean->id)) {
248             $trackerManager->unsetMonitor($monitor);
249             return;
250             }
251             $trackerManager->saveMonitor($monitor, true, true);
252         }
253     }
254
255
256     /**
257      * Displays the header on section of the page; basically everything before the content
258      */
259     public function displayHeader($retModTabs=false)
260     {
261         global $theme;
262         global $max_tabs;
263         global $app_strings;
264         global $current_user;
265         global $sugar_config;
266         global $app_list_strings;
267         global $mod_strings;
268         global $current_language;
269
270         $GLOBALS['app']->headerDisplayed = true;
271
272         $themeObject = SugarThemeRegistry::current();
273         $theme = $themeObject->__toString();
274
275         $ss = new Sugar_Smarty();
276         $ss->assign("APP", $app_strings);
277         $ss->assign("THEME", $theme);
278         $ss->assign("THEME_IE6COMPAT", $themeObject->ie6compat ? 'true':'false');
279         $ss->assign("MODULE_NAME", $this->module);
280
281         // get browser title
282         $ss->assign("SYSTEM_NAME", $this->getBrowserTitle());
283
284         // get css
285         $css = $themeObject->getCSS();
286         if ($this->_getOption('view_print')) {
287             $css .= '<link rel="stylesheet" type="text/css" href="'.$themeObject->getCSSURL('print.css').'" media="all" />';
288         }
289         $ss->assign("SUGAR_CSS",$css);
290
291         // get javascript
292         ob_start();
293         $this->renderJavascript();
294
295         $ss->assign("SUGAR_JS",ob_get_contents().$themeObject->getJS());
296         ob_end_clean();
297
298         // get favicon
299         if(isset($GLOBALS['sugar_config']['default_module_favicon']))
300             $module_favicon = $GLOBALS['sugar_config']['default_module_favicon'];
301         else
302             $module_favicon = false;
303
304         $favicon = '';
305         if ( $module_favicon )
306             $favicon = $themeObject->getImageURL($this->module.'.gif',false);
307         if ( !sugar_is_file($favicon) || !$module_favicon )
308             $favicon = $themeObject->getImageURL('sugar_icon.ico',false);
309         $ss->assign('FAVICON_URL',getJSPath($favicon));
310
311         // build the shortcut menu
312         $shortcut_menu = array();
313         foreach ( $this->getMenu() as $key => $menu_item )
314             $shortcut_menu[$key] = array(
315                 "URL"         => $menu_item[0],
316                 "LABEL"       => $menu_item[1],
317                 "MODULE_NAME" => $menu_item[2],
318                 "IMAGE"       => $themeObject
319                     ->getImage($menu_item[2],"alt='".$menu_item[1]."'  border='0' align='absmiddle'"),
320                 );
321         $ss->assign("SHORTCUT_MENU",$shortcut_menu);
322
323         // handle rtl text direction
324         if(isset($_REQUEST['RTL']) && $_REQUEST['RTL'] == 'RTL'){
325             $_SESSION['RTL'] = true;
326         }
327         if(isset($_REQUEST['LTR']) && $_REQUEST['LTR'] == 'LTR'){
328             unset($_SESSION['RTL']);
329         }
330         if(isset($_SESSION['RTL']) && $_SESSION['RTL']){
331             $ss->assign("DIR", 'dir="RTL"');
332         }
333
334         // handle resizing of the company logo correctly on the fly
335         $companyLogoURL = $themeObject->getImageURL('company_logo.png');
336         $companyLogoURL_arr = explode('?', $companyLogoURL);
337         $companyLogoURL = $companyLogoURL_arr[0];
338
339         $company_logo_attributes = sugar_cache_retrieve('company_logo_attributes');
340         if(!empty($company_logo_attributes)) {
341             $ss->assign("COMPANY_LOGO_MD5", $company_logo_attributes[0]);
342             $ss->assign("COMPANY_LOGO_WIDTH", $company_logo_attributes[1]);
343             $ss->assign("COMPANY_LOGO_HEIGHT", $company_logo_attributes[2]);
344         }
345         else {
346             // Always need to md5 the file
347             $ss->assign("COMPANY_LOGO_MD5", md5_file($companyLogoURL));
348
349             list($width,$height) = getimagesize($companyLogoURL);
350             if ( $width > 212 || $height > 40 ) {
351                 $resizePctWidth  = ($width - 212)/212;
352                 $resizePctHeight = ($height - 40)/40;
353                 if ( $resizePctWidth > $resizePctHeight )
354                     $resizeAmount = $width / 212;
355                 else
356                     $resizeAmount = $height / 40;
357                 $ss->assign("COMPANY_LOGO_WIDTH", round($width * (1/$resizeAmount)));
358                 $ss->assign("COMPANY_LOGO_HEIGHT", round($height * (1/$resizeAmount)));
359             }
360             else {
361                 $ss->assign("COMPANY_LOGO_WIDTH", $width);
362                 $ss->assign("COMPANY_LOGO_HEIGHT", $height);
363             }
364
365             // Let's cache the results
366             sugar_cache_put('company_logo_attributes',
367                             array(
368                                 $ss->get_template_vars("COMPANY_LOGO_MD5"),
369                                 $ss->get_template_vars("COMPANY_LOGO_WIDTH"),
370                                 $ss->get_template_vars("COMPANY_LOGO_HEIGHT")
371                                 )
372             );
373         }
374         $ss->assign("COMPANY_LOGO_URL",getJSPath($companyLogoURL)."&logo_md5=".$ss->get_template_vars("COMPANY_LOGO_MD5"));
375
376         // get the global links
377         $gcls = array();
378         $global_control_links = array();
379         require("include/globalControlLinks.php");
380
381         foreach($global_control_links as $key => $value) {
382             if ($key == 'users')  {   //represents logout link.
383                 $ss->assign("LOGOUT_LINK", $value['linkinfo'][key($value['linkinfo'])]);
384                 $ss->assign("LOGOUT_LABEL", key($value['linkinfo']));//key value for first element.
385                 continue;
386             }
387
388             foreach ($value as $linkattribute => $attributevalue) {
389                 // get the main link info
390                 if ( $linkattribute == 'linkinfo' ) {
391                     $gcls[$key] = array(
392                         "LABEL" => key($attributevalue),
393                         "URL"   => current($attributevalue),
394                         "SUBMENU" => array(),
395                         );
396                    if(substr($gcls[$key]["URL"], 0, 11) == "javascript:") {
397                        $gcls[$key]["ONCLICK"] = substr($gcls[$key]["URL"],11);
398                        $gcls[$key]["URL"] = "javascript:void(0)";
399                    }
400                 }
401                 // and now the sublinks
402                 if ( $linkattribute == 'submenu' && is_array($attributevalue) ) {
403                     foreach ($attributevalue as $submenulinkkey => $submenulinkinfo)
404                         $gcls[$key]['SUBMENU'][$submenulinkkey] = array(
405                             "LABEL" => key($submenulinkinfo),
406                             "URL"   => current($submenulinkinfo),
407                         );
408                        if(substr($gcls[$key]['SUBMENU'][$submenulinkkey]["URL"], 0, 11) == "javascript:") {
409                            $gcls[$key]['SUBMENU'][$submenulinkkey]["ONCLICK"] = substr($gcls[$key]['SUBMENU'][$submenulinkkey]["URL"],11);
410                            $gcls[$key]['SUBMENU'][$submenulinkkey]["URL"] = "javascript:void(0)";
411                        }
412                 }
413             }
414         }
415         $ss->assign("GCLS",$gcls);
416
417         $ss->assign("SEARCH", isset($_REQUEST['query_string']) ? $_REQUEST['query_string'] : '');
418
419         if ($this->action == "EditView" || $this->action == "Login")
420             $ss->assign("ONLOAD", 'onload="set_focus()"');
421
422         $ss->assign("AUTHENTICATED",isset($_SESSION["authenticated_user_id"]));
423
424         // get other things needed for page style popup
425         if (isset($_SESSION["authenticated_user_id"])) {
426             // get the current user name and id
427             $ss->assign("CURRENT_USER", $current_user->full_name == '' || !showFullName()
428                 ? $current_user->user_name : $current_user->full_name );
429             $ss->assign("CURRENT_USER_ID", $current_user->id);
430
431             // get the last viewed records
432             $tracker = new Tracker();
433             $history = $tracker->get_recently_viewed($current_user->id);
434             foreach ( $history as $key => $row ) {
435                 $history[$key]['item_summary_short'] = getTrackerSubstring($row['item_summary']);
436                 $history[$key]['image'] = SugarThemeRegistry::current()
437                     ->getImage($row['module_name'],'border="0" align="absmiddle" alt="'.$row['item_summary'].'"');
438             }
439             $ss->assign("recentRecords",$history);
440         }
441
442         $bakModStrings = $mod_strings;
443         if (isset($_SESSION["authenticated_user_id"]) ) {
444             // get the module list
445             $moduleTopMenu = array();
446
447             $max_tabs = $current_user->getPreference('max_tabs');
448             // Attempt to correct if max tabs count is waaay too high.
449             if ( !isset($max_tabs) || $max_tabs <= 0 || $max_tabs > 10 ) {
450                 $max_tabs = $GLOBALS['sugar_config']['default_max_tabs'];
451                 $current_user->setPreference('max_tabs', $max_tabs, 0, 'global');
452             }
453
454             $moduleTab = $this->_getModuleTab();
455             $ss->assign('MODULE_TAB',$moduleTab);
456
457
458             // See if they are using grouped tabs or not (removed in 6.0, returned in 6.1)
459             $user_navigation_paradigm = $current_user->getPreference('navigation_paradigm');
460             if ( !isset($user_navigation_paradigm) ) {
461                 $user_navigation_paradigm = $GLOBALS['sugar_config']['default_navigation_paradigm'];
462             }
463
464
465             // Get the full module list for later use
466             foreach ( query_module_access_list($current_user) as $module ) {
467                 // Bug 25948 - Check for the module being in the moduleList
468                 if ( isset($app_list_strings['moduleList'][$module]) ) {
469                     $fullModuleList[$module] = $app_list_strings['moduleList'][$module];
470                 }
471             }
472
473
474             if(!should_hide_iframes()) {
475                 $iFrame = new iFrame();
476                 $frames = $iFrame->lookup_frames('tab');
477                 foreach($frames as $key => $values){
478                         $fullModuleList[$key] = $values;
479                 }
480             }
481             elseif (isset($fullModuleList['iFrames'])) {
482                 unset($fullModuleList['iFrames']);
483             }
484
485             if ( $user_navigation_paradigm == 'gm' && isset($themeObject->group_tabs) && $themeObject->group_tabs) {
486                 // We are using grouped tabs
487                 require_once('include/GroupedTabs/GroupedTabStructure.php');
488                 $groupedTabsClass = new GroupedTabStructure();
489                 $modules = query_module_access_list($current_user);
490                 //handle with submoremodules
491                 $max_tabs = $current_user->getPreference('max_tabs');
492                 // If the max_tabs isn't set incorrectly, set it within the range, to the default max sub tabs size
493                 if ( !isset($max_tabs) || $max_tabs <= 0 || $max_tabs > 10){
494                     // We have a default value. Use it
495                     if(isset($GLOBALS['sugar_config']['default_max_tabs'])){
496                         $max_tabs = $GLOBALS['sugar_config']['default_max_tabs'];
497                     }
498                     else{
499                         $max_tabs = 8;
500                     }
501                 }
502
503                 $subMoreModules = false;
504                 $groupTabs = $groupedTabsClass->get_tab_structure(get_val_array($modules));
505                 // We need to put this here, so the "All" group is valid for the user's preference.
506                 $groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules'] = $fullModuleList;
507
508
509                 // Setup the default group tab.
510                 $allGroup = $app_strings['LBL_TABGROUP_ALL'];
511                 $ss->assign('currentGroupTab',$allGroup);
512                 $currentGroupTab = $allGroup;
513                 $usersGroup = $current_user->getPreference('theme_current_group');
514                 // Figure out which tab they currently have selected (stored as a user preference)
515                 if ( !empty($usersGroup) && isset($groupTabs[$usersGroup]) ) {
516                     $currentGroupTab = $usersGroup;
517                 } else {
518                     $current_user->setPreference('theme_current_group',$currentGroupTab);
519                 }
520
521                 $ss->assign('currentGroupTab',$currentGroupTab);
522                 $usingGroupTabs = true;
523
524             } else {
525                 // Setup the default group tab.
526                 $ss->assign('currentGroupTab',$app_strings['LBL_TABGROUP_ALL']);
527
528                 $usingGroupTabs = false;
529
530                 $groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules'] = $fullModuleList;
531
532             }
533
534
535             $topTabList = array();
536
537             // Now time to go through each of the tab sets and fix them up.
538             foreach ( $groupTabs as $tabIdx => $tabData ) {
539                 $topTabs = $tabData['modules'];
540                 if ( ! is_array($topTabs) ) {
541                     $topTabs = array();
542                 }
543                 $extraTabs = array();
544
545                 // Split it in to the tabs that go across the top, and the ones that are on the extra menu.
546                 if ( count($topTabs) > $max_tabs ) {
547                     $extraTabs = array_splice($topTabs,$max_tabs);
548                 }
549                 // Make sure the current module is accessable through one of the top tabs
550                 if ( !isset($topTabs[$moduleTab]) ) {
551                     // Nope, we need to add it.
552                     // First, take it out of the extra menu, if it's there
553                     if ( isset($extraTabs[$moduleTab]) ) {
554                         unset($extraTabs[$moduleTab]);
555                     }
556                     if ( count($topTabs) >= $max_tabs - 1 ) {
557                         // We already have the maximum number of tabs, so we need to shuffle the last one
558                         // from the top to the first one of the extras
559                         $lastElem = array_splice($topTabs,$max_tabs-1);
560                         $extraTabs = $lastElem + $extraTabs;
561                     }
562                     if ( !empty($moduleTab) ) {
563                         $topTabs[$moduleTab] = $app_list_strings['moduleList'][$moduleTab];
564                     }
565                 }
566
567
568                 /*
569                 // This was removed, but I like the idea, so I left the code in here in case we decide to turn it back on
570                 // If we are using group tabs, add all the "hidden" tabs to the end of the extra menu
571                 if ( $usingGroupTabs ) {
572                     foreach($fullModuleList as $moduleKey => $module ) {
573                         if ( !isset($topTabs[$moduleKey]) && !isset($extraTabs[$moduleKey]) ) {
574                             $extraTabs[$moduleKey] = $module;
575                         }
576                     }
577                 }
578                 */
579
580                 // Get a unique list of the top tabs so we can build the popup menus for them
581                 foreach ( $topTabs as $moduleKey => $module ) {
582                     $topTabList[$moduleKey] = $module;
583                 }
584
585                 $groupTabs[$tabIdx]['modules'] = $topTabs;
586                 $groupTabs[$tabIdx]['extra'] = $extraTabs;
587             }
588         }
589
590         if ( isset($topTabList) && is_array($topTabList) ) {
591             // Adding shortcuts array to menu array for displaying shortcuts associated with each module
592             $shortcutTopMenu = array();
593             foreach($topTabList as $module_key => $label) {
594                 global $mod_strings;
595                 $mod_strings = return_module_language($current_language, $module_key);
596                 foreach ( $this->getMenu($module_key) as $key => $menu_item ) {
597                     $shortcutTopMenu[$module_key][$key] = array(
598                         "URL"         => $menu_item[0],
599                         "LABEL"       => $menu_item[1],
600                         "MODULE_NAME" => $menu_item[2],
601                         "IMAGE"       => $themeObject
602                         ->getImage($menu_item[2],"alt='".$menu_item[1]."'  border='0' align='absmiddle'"),
603                         );
604                 }
605             }
606             $ss->assign("groupTabs",$groupTabs);
607             $ss->assign("shortcutTopMenu",$shortcutTopMenu);
608             $ss->assign('USE_GROUP_TABS',$usingGroupTabs);
609
610             // This is here for backwards compatibility, someday, somewhere, it will be able to be removed
611             $ss->assign("moduleTopMenu",$groupTabs[$app_strings['LBL_TABGROUP_ALL']]['modules']);
612             $ss->assign("moduleExtraMenu",$groupTabs[$app_strings['LBL_TABGROUP_ALL']]['extra']);
613
614         }
615
616         global $mod_strings;
617         $mod_strings = $bakModStrings;
618         $headerTpl = $themeObject->getTemplate('header.tpl');
619         if ( isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'] )
620             $ss->clear_compiled_tpl($headerTpl);
621
622         if ($retModTabs)
623         {
624             return $ss->fetch($themeObject->getTemplate('_headerModuleList.tpl'));
625         } else {
626             $ss->display($headerTpl);
627
628             $this->includeClassicFile('modules/Administration/DisplayWarnings.php');
629
630             $errorMessages = SugarApplication::getErrorMessages();
631             if ( !empty($errorMessages)) {
632                 foreach ( $errorMessages as $error_message ) {
633                     echo('<p class="error">' . $error_message.'</p>');
634                 }
635             }
636         }
637
638     }
639
640     function getModuleMenuHTML()
641     {
642
643     }
644
645     /**
646      * If the view is classic then this method will include the file and
647      * setup any global variables.
648      *
649      * @param string $file
650      */
651     public function includeClassicFile(
652         $file
653         )
654     {
655         global $sugar_config, $theme, $current_user, $sugar_version, $sugar_flavor, $mod_strings, $app_strings, $app_list_strings, $action;
656         global $gridline, $request_string, $modListHeader, $dashletData, $authController, $locale, $currentModule, $import_bean_map, $image_path, $license;
657         global $user_unique_key, $server_unique_key, $barChartColors, $modules_exempt_from_availability_check, $dictionary, $current_language, $beanList, $beanFiles, $sugar_build, $sugar_codename;
658         global $timedate, $login_error; // cn: bug 13855 - timedate not available to classic views.
659         if (!empty($this->module))
660             $currentModule = $this->module;
661         require_once ($file);
662     }
663
664     protected function _displayLoginJS()
665     {
666         global $sugar_config, $timedate;
667
668         if(isset($this->bean->module_dir)){
669             echo "<script>var module_sugar_grp1 = '{$this->bean->module_dir}';</script>";
670         }
671         if(isset($_REQUEST['action'])){
672             echo "<script>var action_sugar_grp1 = '{$_REQUEST['action']}';</script>";
673         }
674         echo '<script>jscal_today = 1000*' . $timedate->asUserTs($timedate->getNow()) . '; if(typeof app_strings == "undefined") app_strings = new Array();</script>';
675         if (!is_file("include/javascript/sugar_grp1.js")) {
676             $_REQUEST['root_directory'] = ".";
677             require_once("jssource/minify_utils.php");
678             ConcatenateFiles(".");
679         }
680         echo '<script type="text/javascript" src="' . getJSPath('include/javascript/sugar_grp1_yui.js') . '"></script>';
681         echo '<script type="text/javascript" src="' . getJSPath('include/javascript/sugar_grp1.js') . '"></script>';
682         echo '<script type="text/javascript" src="' . getJSPath('include/javascript/calendar.js') . '"></script>';
683         echo <<<EOQ
684         <script>
685             if ( typeof(SUGAR) == 'undefined' ) {SUGAR = {}};
686             if ( typeof(SUGAR.themes) == 'undefined' ) SUGAR.themes = {};
687         </script>
688 EOQ;
689         if(isset( $sugar_config['disc_client']) && $sugar_config['disc_client'])
690             echo '<script type="text/javascript" src="' . getJSPath('modules/Sync/headersync.js') . '"></script>';
691     }
692
693     /**
694      * Get JS validation code for views
695      */
696     public static function getJavascriptValidation()
697     {
698         global $timedate;
699         $cal_date_format = $timedate->get_cal_date_format();
700         $timereg = $timedate->get_regular_expression($timedate->get_time_format());
701         $datereg = $timedate->get_regular_expression($timedate->get_date_format());
702         $date_pos = '';
703         foreach ($datereg['positions'] as $type => $pos) {
704             if (empty($date_pos)) {
705                 $date_pos .= "'$type': $pos";
706             } else {
707                 $date_pos .= ",'$type': $pos";
708             }
709         }
710
711         $time_separator = $timedate->timeSeparator();
712         $hour_offset = $timedate->getUserUTCOffset() * 60;
713
714         // Add in the number formatting styles here as well, we have been handling this with individual modules.
715         require_once ('modules/Currencies/Currency.php');
716         list ($num_grp_sep, $dec_sep) = get_number_seperators();
717
718         $the_script = "<script type=\"text/javascript\">\n" . "\tvar time_reg_format = '" .
719              $timereg['format'] . "';\n" . "\tvar date_reg_format = '" .
720              $datereg['format'] . "';\n" . "\tvar date_reg_positions = { $date_pos };\n" .
721              "\tvar time_separator = '$time_separator';\n" .
722              "\tvar cal_date_format = '$cal_date_format';\n" .
723              "\tvar time_offset = $hour_offset;\n" . "\tvar num_grp_sep = '$num_grp_sep';\n" .
724              "\tvar dec_sep = '$dec_sep';\n" . "</script>";
725
726         return $the_script;
727     }
728
729     /**
730      * Called from process(). This method will display the correct javascript.
731      */
732     protected function _displayJavascript()
733     {
734         global $locale, $sugar_config, $timedate;
735
736
737         if ($this->_getOption('show_javascript')) {
738             if (!$this->_getOption('show_header'))
739                 echo <<<EOHTML
740 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
741 <html>
742 <head>
743 EOHTML;
744
745             echo "<script>var sugar_cache_dir = '{$GLOBALS['sugar_config']['cache_dir']}';</script>";
746             echo "<script>var sugar_upload_dir = '{$GLOBALS['sugar_config']['upload_dir']}';</script>";
747
748             if(isset($this->bean->module_dir)){
749                 echo "<script>var module_sugar_grp1 = '{$this->bean->module_dir}';</script>";
750             }
751             if(isset($_REQUEST['action'])){
752                 echo "<script>var action_sugar_grp1 = '{$_REQUEST['action']}';</script>";
753             }
754             echo '<script>jscal_today = 1000*' . $timedate->asUserTs($timedate->getNow()) . '; if(typeof app_strings == "undefined") app_strings = new Array();</script>';
755             if (!is_file("include/javascript/sugar_grp1.js") || !is_file("include/javascript/sugar_grp1_yui.js")) {
756                 $_REQUEST['root_directory'] = ".";
757                 require_once("jssource/minify_utils.php");
758                 ConcatenateFiles(".");
759             }
760             echo '<script type="text/javascript" src="' . getJSPath('include/javascript/sugar_grp1_yui.js') . '"></script>';
761             echo '<script type="text/javascript" src="' . getJSPath('include/javascript/sugar_grp1.js') . '"></script>';
762             echo '<script type="text/javascript" src="' . getJSPath('include/javascript/calendar.js') . '"></script>';
763
764             // output necessary config js in the top of the page
765             $config_js = $this->getSugarConfigJS();
766             if(!empty($config_js)){
767                 echo "<script>\n".implode("\n", $config_js)."</script>\n";
768             }
769             if ( isset($sugar_config['email_sugarclient_listviewmaxselect']) ) {
770                 echo "<script>SUGAR.config.email_sugarclient_listviewmaxselect = {$GLOBALS['sugar_config']['email_sugarclient_listviewmaxselect']};</script>";
771             }
772             
773             $image_server = (defined('TEMPLATE_URL'))?TEMPLATE_URL . '/':'';
774             echo '<script type="text/javascript">SUGAR.themes.image_server="' . $image_server . '";</script>'; // cn: bug 12274 - create session-stored key to defend against CSRF
775             echo '<script type="text/javascript">var name_format = "' . $locale->getLocaleFormatMacro() . '";</script>';
776             echo self::getJavascriptValidation();
777             if (!is_file($GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $GLOBALS['current_language'] . '.js')) {
778                 require_once ('include/language/jsLanguage.php');
779                 jsLanguage::createAppStringsCache($GLOBALS['current_language']);
780             }
781             echo '<script type="text/javascript" src="' . $GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $GLOBALS['current_language'] . '.js?s=' . $GLOBALS['js_version_key'] . '&c=' . $GLOBALS['sugar_config']['js_custom_version'] . '&j=' . $GLOBALS['sugar_config']['js_lang_version'] . '"></script>';
782
783                         echo $this->_getModLanguageJS();
784
785             if(isset( $sugar_config['disc_client']) && $sugar_config['disc_client'])
786                 echo '<script type="text/javascript" src="' . getJSPath('modules/Sync/headersync.js') . '"></script>';
787
788         }
789     }
790
791         protected function _getModLanguageJS(){
792                 if (!is_file($GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $this->module . '/' . $GLOBALS['current_language'] . '.js')) {
793                         require_once ('include/language/jsLanguage.php');
794                         jsLanguage::createModuleStringsCache($this->module, $GLOBALS['current_language']);
795                 }
796                 return '<script type="text/javascript" src="' . $GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $this->module . '/' . $GLOBALS['current_language'] . '.js?s=' . $GLOBALS['js_version_key'] . '&c=' . $GLOBALS['sugar_config']['js_custom_version'] . '&j=' . $GLOBALS['sugar_config']['js_lang_version'] . '"></script>';
797         }
798
799     /**
800      * Called from process(). This method will display the footer on the page.
801      */
802     public function displayFooter()
803     {
804         if (empty($this->responseTime)) {
805             $this->_calculateFooterMetrics();
806         }
807         global $sugar_config;
808         global $app_strings;
809
810         //decide whether or not to show themepicker, default is to show
811         $showThemePicker = true;
812         if (isset($sugar_config['showThemePicker'])) {
813             $showThemePicker = $sugar_config['showThemePicker'];
814         }
815
816         echo "<!-- crmprint -->";
817         $jsalerts = new jsAlerts();
818         if ( !isset($_SESSION['isMobile']) )
819             echo $jsalerts->getScript();
820
821         $ss = new Sugar_Smarty();
822         $ss->assign("AUTHENTICATED",isset($_SESSION["authenticated_user_id"]));
823         $ss->assign('MOD',return_module_language($GLOBALS['current_language'], 'Users'));
824
825                 $bottomLinkList = array();
826                  if (isset($this->action) && $this->action != "EditView") {
827                          $bottomLinkList['print'] = array($app_strings['LNK_PRINT'] => getPrintLink());
828                 }
829                 $bottomLinkList['backtotop'] = array($app_strings['LNK_BACKTOTOP'] => 'javascript:SUGAR.util.top();');
830
831                 $bottomLinksStr = "";
832                 foreach($bottomLinkList as $key => $value) {
833                         foreach($value as $text => $link) {
834                                    $href = $link;
835                                    if(substr($link, 0, 11) == "javascript:") {
836                        $onclick = " onclick=\"".substr($link,11)."\"";
837                        $href = "javascript:void(0)";
838                    } else {
839                                 $onclick = "";
840                         }
841                 $imageURL = SugarThemeRegistry::current()->getImageURL($key.'.gif');
842                                 $bottomLinksStr .= "<a href=\"{$href}\"";
843                                 $bottomLinksStr .= (isset($onclick)) ? $onclick : "";
844                                 $bottomLinksStr .= "><img src='{$imageURL}' alt='{$text}'></a>";
845                                 $bottomLinksStr .= " <a href=\"{$href}\" class=\"bottomLink\"";
846                                 $bottomLinksStr .= (isset($onclick)) ? $onclick : "";
847                                 $bottomLinksStr .= ">".$text."</a>";
848                         }
849                 }
850                 $ss->assign("BOTTOMLINKS",$bottomLinksStr);
851         if (SugarConfig::getInstance()->get('calculate_response_time', false))
852             $ss->assign('STATISTICS',$this->_getStatistics());
853
854         // Under the License referenced above, you are required to leave in all copyright statements in both
855         // the code and end-user application.
856
857
858         $copyright = '&copy; 2004-2011 SugarCRM Inc. The Program is provided AS IS, without warranty.  Licensed under <a href="LICENSE.txt" target="_blank" class="copyRightLink">AGPLv3</a>.<br>This program is free software; you can redistribute it and/or modify it under the terms of the <br><a href="LICENSE.txt" target="_blank" class="copyRightLink"> GNU Affero General Public License version 3</a> as published by the Free Software Foundation, including the additional permission set forth in the source code header.<br>';
859
860
861
862
863
864
865
866
867
868
869
870         // The interactive user interfaces in modified source and object code
871         // versions of this program must display Appropriate Legal Notices, as
872         // required under Section 5 of the GNU General Public License version
873         // 3. In accordance with Section 7(b) of the GNU General Public License
874         // version 3, these Appropriate Legal Notices must retain the display
875         // of the "Powered by SugarCRM" logo. If the display of the logo is
876         // not reasonably feasible for technical reasons, the Appropriate
877         // Legal Notices must display the words "Powered by SugarCRM".
878         $attribLinkImg = "<img style='margin-top: 2px' border='0' width='106' height='23' src='include/images/poweredby_sugarcrm.png' alt='Powered By SugarCRM'>\n";
879
880
881
882         // Bug 38594 - Add in Trademark wording
883         $copyright .= 'SugarCRM is a trademark of SugarCRM, Inc. All other company and product names may be trademarks of the respective companies with which they are associated.<br />';
884
885         //rrs bug: 20923 - if this image does not exist as per the license, then the proper image will be displaye regardless, so no need
886         //to display an empty image here.
887         if(file_exists('include/images/poweredby_sugarcrm.png')){
888             $copyright .= $attribLinkImg;
889         }
890         // End Required Image
891         $ss->assign('COPYRIGHT',$copyright);
892         $ss->display(SugarThemeRegistry::current()->getTemplate('footer.tpl'));
893     }
894
895     /**
896      * Called from process(). This method will display subpanels.
897      */
898     protected function _displaySubPanels()
899     {
900         if (isset($this->bean) && !empty($this->bean->id) && (file_exists('modules/' . $this->module . '/metadata/subpaneldefs.php') || file_exists('custom/modules/' . $this->module . '/metadata/subpaneldefs.php') || file_exists('custom/modules/' . $this->module . '/Ext/Layoutdefs/layoutdefs.ext.php'))) {
901             $GLOBALS['focus'] = $this->bean;
902             require_once ('include/SubPanel/SubPanelTiles.php');
903             $subpanel = new SubPanelTiles($this->bean, $this->module);
904             echo $subpanel->display();
905         }
906     }
907
908     protected function _buildModuleList()
909     {
910         if (!empty($GLOBALS['current_user']) && empty($GLOBALS['modListHeader']))
911             $GLOBALS['modListHeader'] = query_module_access_list($GLOBALS['current_user']);
912     }
913
914     /**
915      * private method used in process() to determine the value of a passed in option
916      *
917      * @param string option - the option that we want to know the valye of
918      * @param bool default - what the default value should be if we do not find the option
919      *
920      * @return bool - the value of the option
921      */
922     protected function _getOption(
923         $option,
924         $default = false
925         )
926     {
927         if (!empty($this->options) && isset($this->options['show_all'])) {
928             return $this->options['show_all'];
929         } elseif (!empty($this->options) && isset($this->options[$option])) {
930             return $this->options[$option];
931         } else return $default;
932     }
933
934     /**
935      * track
936      * Private function to track information about the view request
937      */
938     private function _track()
939     {
940         if (empty($this->responseTime)) {
941             $this->_calculateFooterMetrics();
942         }
943         if (empty($GLOBALS['current_user']->id)) {
944             return;
945         }
946
947
948         $trackerManager = TrackerManager::getInstance();
949             $trackerManager->save();
950
951     }
952
953     /**
954      * Checks to see if the module name passed is valid; dies if it is not
955      */
956     protected function _checkModule()
957     {
958         if(!empty($this->module) && !file_exists('modules/'.$this->module)){
959             $error = str_replace("[module]", "$this->module", $GLOBALS['app_strings']['ERR_CANNOT_FIND_MODULE']);
960             $GLOBALS['log']->fatal($error);
961             echo $error;
962             die();
963         }
964     }
965
966     public function renderJavascript()
967     {
968         if ($this->action !== 'Login')
969             $this->_displayJavascript();
970         else
971             $this->_displayLoginJS();
972     }
973
974     private function _calculateFooterMetrics()
975     {
976         $endTime = microtime(true);
977         $deltaTime = $endTime - $GLOBALS['startTime'];
978         $this->responseTime = number_format(round($deltaTime, 2), 2);
979         // Print out the resources used in constructing the page.
980         $this->fileResources = count(get_included_files());
981     }
982
983     private function _getStatistics()
984     {
985         $endTime = microtime(true);
986         $deltaTime = $endTime - $GLOBALS['startTime'];
987         $response_time_string = $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME'] . ' <span id="responseTime">' . number_format(round($deltaTime, 2), 2) . '</span> ' . $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME_SECONDS'];
988         $return = $response_time_string;
989         $return .= '<br />';
990         if (!empty($GLOBALS['sugar_config']['show_page_resources'])) {
991             // Print out the resources used in constructing the page.
992             $included_files = get_included_files();
993
994             // take all of the included files and make a list that does not allow for duplicates based on case
995             // I believe the full get_include_files result set appears to have one entry for each file in real
996             // case, and one entry in all lower case.
997             $list_of_files_case_insensitive = array();
998             foreach($included_files as $key => $name) {
999                 // preserve the first capitalization encountered.
1000                 $list_of_files_case_insensitive[mb_strtolower($name) ] = $name;
1001             }
1002             $return .= $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_RESOURCES'] . '(' . DBManager::getQueryCount() . ',' . sizeof($list_of_files_case_insensitive) . ')<br>';
1003             // Display performance of the internal and external caches....
1004             $cacheStats = SugarCache::instance()->getCacheStats();
1005             $return .= "External cache (hits/total=ratio) local ({$cacheStats['localHits']}/{$cacheStats['requests']}=" . round($cacheStats['localHits']*100/$cacheStats['requests'], 0) . "%)";
1006             $return .= " external ({$cacheStats['externalHits']}/{$cacheStats['requests']}=" . round($cacheStats['externalHits']*100/$cacheStats['requests'], 0) . "%)<br />";
1007             $return .= " misses ({$cacheStats['misses']}/{$cacheStats['requests']}=" . round($cacheStats['misses']*100/$cacheStats['requests'], 0) . "%)<br />";
1008         }
1009
1010         return $return;
1011     }
1012
1013     /**
1014      * Loads the module shortcuts menu
1015      *
1016      * @param  $module string optional, can specify module to retrieve menu for if not the current one
1017      * @return array module menu
1018      */
1019     public function getMenu(
1020         $module = null
1021         )
1022     {
1023         global $current_language, $current_user, $mod_strings, $app_strings, $module_menu;
1024
1025         if ( empty($module) )
1026             $module = $this->module;
1027
1028         //Need to make sure the mod_strings match the requested module or Menus may fail
1029         $curr_mod_strings = $mod_strings;
1030         $mod_strings = return_module_language ( $current_language, $module ) ;
1031
1032         $module_menu = array();
1033
1034         if (file_exists('modules/' . $module . '/Menu.php')) {
1035             require('modules/' . $module . '/Menu.php');
1036         }
1037         if (file_exists('custom/modules/' . $module . '/Ext/Menus/menu.ext.php')) {
1038             require('custom/modules/' . $module . '/Ext/Menus/menu.ext.php');
1039         }
1040         if (!file_exists('modules/' . $module . '/Menu.php')
1041                 && !file_exists('custom/modules/' . $module . '/Ext/Menus/menu.ext.php')
1042                 && !empty($GLOBALS['mod_strings']['LNK_NEW_RECORD'])) {
1043             $module_menu[] = array("index.php?module=$module&action=EditView&return_module=$module&return_action=DetailView",
1044                 $GLOBALS['mod_strings']['LNK_NEW_RECORD'],"{$GLOBALS['app_strings']['LBL_CREATE_BUTTON_LABEL']}$module" ,$module );
1045             $module_menu[] = array("index.php?module=$module&action=index", $GLOBALS['mod_strings']['LNK_LIST'],
1046                 $module, $module);
1047             if ( ($this->bean instanceOf SugarBean) && !empty($this->bean->importable) )
1048                 if ( !empty($mod_strings['LNK_IMPORT_'.strtoupper($module)]) )
1049                     $module_menu[] = array("index.php?module=Import&action=Step1&import_module=$module&return_module=$module&return_action=index",
1050                         $mod_strings['LNK_IMPORT_'.strtoupper($module)], "Import", $module);
1051                 else
1052                     $module_menu[] = array("index.php?module=Import&action=Step1&import_module=$module&return_module=$module&return_action=index",
1053                         $app_strings['LBL_IMPORT'], "Import", $module);
1054         }
1055         if (file_exists('custom/application/Ext/Menus/menu.ext.php')) {
1056             require('custom/application/Ext/Menus/menu.ext.php');
1057         }
1058
1059         $mod_strings = $curr_mod_strings;
1060         $builtModuleMenu = $module_menu;
1061         unset($module_menu);
1062
1063         return $builtModuleMenu;
1064     }
1065
1066     /**
1067     * Returns the module name which should be highlighted in the module menu
1068      */
1069     protected function _getModuleTab()
1070     {
1071         global $app_list_strings, $moduleTabMap;
1072
1073         // Need to figure out what tab this module belongs to, most modules have their own tabs, but there are exceptions.
1074         if ( !empty($_REQUEST['module_tab']) )
1075             return $_REQUEST['module_tab'];
1076         elseif ( isset($moduleTabMap[$this->module]) )
1077             return $moduleTabMap[$this->module];
1078         // Special cases
1079         elseif ( $this->module == 'MergeRecords' )
1080             return !empty($_REQUEST['merge_module']) ? $_REQUEST['merge_module'] : $_REQUEST['return_module'];
1081         elseif ( $this->module == 'Users' && $this->action == 'SetTimezone' )
1082             return 'Home';
1083         // Default anonymous pages to be under Home
1084         elseif ( !isset($app_list_strings['moduleList'][$this->module]) )
1085             return 'Home';
1086         else
1087             return $this->module;
1088     }
1089
1090    /**
1091     * Return the "breadcrumbs" to display at the top of the page
1092     *
1093     * @param  bool $show_help optional, true if we show the help links
1094     * @return HTML string containing breadcrumb title
1095     */
1096     public function getModuleTitle(
1097         $show_help = true
1098         )
1099     {
1100         global $sugar_version, $sugar_flavor, $server_unique_key, $current_language, $action;
1101
1102         $theTitle = "<div class='moduleTitle'>\n<h2>";
1103
1104         $module = preg_replace("/ /","",$this->module);
1105
1106         $params = $this->_getModuleTitleParams();
1107         $count = count($params);
1108         $index = 0;
1109
1110                 if(SugarThemeRegistry::current()->directionality == "rtl") {
1111                         $params = array_reverse($params);
1112                 }
1113
1114         foreach($params as $parm){
1115             $index++;
1116             $theTitle .= $parm;
1117             if($index < $count){
1118                 $theTitle .= $this->getBreadCrumbSymbol();
1119             }
1120         }
1121         $theTitle .= "</h2>\n";
1122         if ($show_help) {
1123             $theTitle .= "<span class='utils'>";
1124
1125             $createImageURL = SugarThemeRegistry::current()->getImageURL('create-record.gif');
1126             $url = ajaxLink("index.php?module=$module&action=EditView&return_module=$module&return_action=DetailView");
1127             $theTitle .= <<<EOHTML
1128 &nbsp;
1129 <a id="create_image" href="{$url}" class="utilsLink">
1130 <img src='{$createImageURL}' alt='{$GLOBALS['app_strings']['LNK_CREATE']}'></a>
1131 <a id="create_link" href="{$url}" class="utilsLink">
1132 {$GLOBALS['app_strings']['LNK_CREATE']}
1133 </a>
1134 EOHTML;
1135         }
1136
1137         $theTitle .= "</span></div>\n";
1138         return $theTitle;
1139     }
1140
1141     /**
1142      * Return the metadata file that will be used by this view.
1143      *
1144      * @return string File location of the metadata file.
1145      */
1146     public function getMetaDataFile()
1147     {
1148         $metadataFile = null;
1149         $foundViewDefs = false;
1150         $viewDef = strtolower($this->type) . 'viewdefs';
1151         $coreMetaPath = 'modules/'.$this->module.'/metadata/' . $viewDef . '.php';
1152         if(file_exists('custom/' .$coreMetaPath )){
1153             $metadataFile = 'custom/' . $coreMetaPath;
1154             $foundViewDefs = true;
1155         }else{
1156             if(file_exists('custom/modules/'.$this->module.'/metadata/metafiles.php')){
1157                 require_once('custom/modules/'.$this->module.'/metadata/metafiles.php');
1158                 if(!empty($metafiles[$this->module][$viewDef])){
1159                     $metadataFile = $metafiles[$this->module][$viewDef];
1160                     $foundViewDefs = true;
1161                 }
1162             }elseif(file_exists('modules/'.$this->module.'/metadata/metafiles.php')){
1163                 require_once('modules/'.$this->module.'/metadata/metafiles.php');
1164                 if(!empty($metafiles[$this->module][$viewDef])){
1165                     $metadataFile = $metafiles[$this->module][$viewDef];
1166                     $foundViewDefs = true;
1167                 }
1168             }
1169         }
1170
1171         if(!$foundViewDefs && file_exists($coreMetaPath)){
1172                 $metadataFile = $coreMetaPath;
1173         }
1174         $GLOBALS['log']->debug("metadatafile=". $metadataFile);
1175
1176         return $metadataFile;
1177     }
1178
1179
1180     /**
1181      * Returns an array composing of the breadcrumbs to use for the module title
1182      *
1183      * @param bool $browserTitle true if the returned string is being used for the browser title, meaning
1184      *                           there should be no HTML in the string
1185      * @return array
1186      */
1187     protected function _getModuleTitleParams($browserTitle = false)
1188     {
1189         $params = array($this->_getModuleTitleListParam($browserTitle));
1190
1191         if (isset($this->action)){
1192             switch ($this->action) {
1193             case 'EditView':
1194                 if(!empty($this->bean->id)) {
1195                     $params[] = "<a href='index.php?module={$this->module}&action=DetailView&record={$this->bean->id}'>".$this->bean->get_summary_text()."</a>";
1196                     $params[] = $GLOBALS['app_strings']['LBL_EDIT_BUTTON_LABEL'];
1197                 }
1198                 else
1199                     $params[] = $GLOBALS['app_strings']['LBL_CREATE_BUTTON_LABEL'];
1200                 break;
1201             case 'DetailView':
1202                 $beanName = $this->bean->get_summary_text();
1203                 $params[] = $beanName;
1204                 break;
1205             }
1206         }
1207
1208         return $params;
1209     }
1210
1211     /**
1212      * Returns the portion of the array that will represent the listview in the breadcrumb
1213      *
1214      * @param bool $browserTitle true if the returned string is being used for the browser title, meaning
1215      *                           there should be no HTML in the string
1216      * @return string
1217      */
1218     protected function _getModuleTitleListParam( $browserTitle = false )
1219     {
1220         global $current_user;
1221         global $app_strings;
1222
1223         if(!empty($GLOBALS['app_list_strings']['moduleList'][$this->module]))
1224                 $firstParam = $GLOBALS['app_list_strings']['moduleList'][$this->module];
1225         else
1226                 $firstParam = $this->module;
1227
1228         $iconPath = $this->getModuleTitleIconPath($this->module);
1229         if($this->action == "ListView" || $this->action == "index") {
1230             if (!empty($iconPath) && !$browserTitle) {
1231                 if (SugarThemeRegistry::current()->directionality == "ltr") {
1232                                         return "<a href='index.php?module={$this->module}&action=index'>"
1233                                              . "<img src='{$iconPath}' alt='".$firstParam."' title='".$firstParam."' align='absmiddle'></a>"
1234                                              . $this->getBreadCrumbSymbol().$app_strings['LBL_SEARCH'];
1235                 } else {
1236                         return $app_strings['LBL_SEARCH'].$this->getBreadCrumbSymbol()
1237                                  . "<a href='index.php?module={$this->module}&action=index'>"
1238                                              . "<img src='{$iconPath}' alt='".$firstParam."' title='".$firstParam."' align='absmiddle'></a>";
1239                 }
1240                         } else {
1241                                 return $firstParam;
1242                         }
1243         }
1244         else {
1245                     if (!empty($iconPath) && !$browserTitle) {
1246                                 return "<a href='index.php?module={$this->module}&action=index'>"
1247                                      . "<img src='{$iconPath}' alt='".$this->module."' title='".$this->module."' align='absmiddle'></a>";
1248                         } else {
1249                                 return "{$firstParam}";
1250                         }
1251         }
1252     }
1253
1254     protected function getModuleTitleIconPath($module)
1255     {
1256         $iconPath = "";
1257         if(is_file(SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png',false))) {
1258                 $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png');
1259         }
1260         else if (is_file(SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png',false))) {
1261                 $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png');
1262         }
1263         return $iconPath;
1264     }
1265
1266     /**
1267      * Returns the string which will be shown in the browser's title; defaults to using the same breadcrumb
1268      * as in the module title
1269      *
1270      * @return string
1271      */
1272     public function getBrowserTitle()
1273     {
1274         global $app_strings;
1275
1276         $browserTitle = $app_strings['LBL_BROWSER_TITLE'];
1277         if ( $this->module == 'Users' && ($this->action == 'SetTimezone' || $this->action == 'Login') )
1278             return $browserTitle;
1279         $params = $this->_getModuleTitleParams(true);
1280         foreach ($params as $value )
1281             $browserTitle = strip_tags($value) . ' &raquo; ' . $browserTitle;
1282
1283         return $browserTitle;
1284     }
1285
1286     /**
1287      * Returns the correct breadcrumb symbol according to theme's directionality setting
1288      *
1289      * @return string
1290      */
1291     public function getBreadCrumbSymbol()
1292     {
1293         if(SugarThemeRegistry::current()->directionality == "ltr") {
1294                 return "<span class='pointer'>&raquo;</span>";
1295         }
1296         else {
1297                 return "<span class='pointer'>&laquo;</span>";
1298         }
1299     }
1300
1301     protected function getSugarConfigJS(){
1302         global $sugar_config;
1303
1304         // Set all the config parameters in the JS config as necessary
1305         $config_js = array();
1306         // AjaxUI stock banned modules
1307         $config_js[] = "SUGAR.config.stockAjaxBannedModules = ".json_encode(ajaxBannedModules()).";";
1308         if ( isset($sugar_config['quicksearch_querydelay']) ) {
1309             $config_js[] = "SUGAR.config.quicksearch_querydelay = {$GLOBALS['sugar_config']['quicksearch_querydelay']};";
1310         }
1311         if ( empty($sugar_config['disableAjaxUI']) ) {
1312             $config_js[] = "SUGAR.config.disableAjaxUI = false;";
1313         }
1314         else{
1315             $config_js[] = "SUGAR.config.disableAjaxUI = true;";
1316         }
1317         if ( !empty($sugar_config['addAjaxBannedModules']) ){
1318             $config_js[] = "SUGAR.config.addAjaxBannedModules = ".json_encode($sugar_config['addAjaxBannedModules']).";";
1319         }
1320         if ( !empty($sugar_config['overrideAjaxBannedModules']) ){
1321             $config_js[] = "SUGAR.config.overrideAjaxBannedModules = ".json_encode($sugar_config['overrideAjaxBannedModules']).";";
1322         }
1323
1324         return $config_js;
1325     }
1326 }