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