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