PageRenderTime 49ms CodeModel.GetById 3ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 0ms

/include/MVC/View/SugarView.php

https://github.com/vincentamari/SuperSweetAdmin
PHP | 1248 lines | 838 code | 161 blank | 249 comment | 192 complexity | 6f087797e1a4bc67abb8c17fcae9aac1 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file