home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 April / CMCD0404.ISO / Software / Freeware / Programare / dotproject / classes / ui.class.php < prev   
PHP Script  |  2004-01-17  |  26KB  |  865 lines

  1. <?php /* CLASSES $Id: ui.class.php,v 1.32 2004/01/17 14:59:45 gregorerhardt Exp $ */
  2. /**
  3. * @package dotproject
  4. * @subpackage core
  5. * @license http://opensource.org/licenses/bsd-license.php BSD License
  6. */
  7.  
  8. // Message No Constants
  9. define( 'UI_MSG_OK', 1 );
  10. define( 'UI_MSG_ALERT', 2 );
  11. define( 'UI_MSG_WARNING', 3 );
  12. define( 'UI_MSG_ERROR', 4 );
  13.  
  14. // global variable holding the translation array
  15. $GLOBALS['translate'] = array();
  16.  
  17. define( "UI_CASE_UPPER", 1 );
  18. define( "UI_CASE_LOWER", 2 );
  19. define( "UI_CASE_UPPERFIRST", 3 );
  20.  
  21. /**
  22. * The Application User Interface Class.
  23. *
  24. * @author Andrew Eddie <eddieajau@users.sourceforge.net>
  25. * @version $Revision: 1.32 $
  26. */
  27. class CAppUI {
  28. /** @var array generic array for holding the state of anything */
  29.     var $state=null;
  30. /** @var int */
  31.     var $user_id=null;
  32. /** @var string */
  33.     var $user_first_name=null;
  34. /** @var string */
  35.     var $user_last_name=null;
  36. /** @var string */
  37.     var $user_company=null;
  38. /** @var int */
  39.     var $user_department=null;
  40. /** @var string */
  41.     var $user_email=null;
  42. /** @var int */
  43.     var $user_type=null;
  44. /** @var array */
  45.     var $user_prefs=null;
  46. /** @var int Unix time stamp */
  47.     var $day_selected=null;
  48.  
  49. // localisation
  50. /** @var string */
  51.     var $user_locale=null;
  52. /** @var string */
  53.     var $base_locale = 'en'; // do not change - the base 'keys' will always be in english
  54.  
  55. /** @var string Message string*/
  56.     var $msg = '';
  57. /** @var string */
  58.     var $msgNo = '';
  59. /** @var string Default page for a redirect call*/
  60.     var $defaultRedirect = '';
  61.  
  62. /** @var array Configuration variable array*/
  63.     var $cfg=null;
  64.  
  65. /** @var integer Version major */
  66.     var $version_major = null;
  67.  
  68. /** @var integer Version minor */
  69.     var $version_minor = null;
  70.  
  71. /** @var integer Version patch level */
  72.     var $version_patch = null;
  73.  
  74. /** @var string Version string */
  75.     var $version_string = null;
  76.  
  77. /**
  78. * CAppUI Constructor
  79. */
  80.     function CAppUI() {
  81.         $this->state = array();
  82.  
  83.         $this->user_id = -1;
  84.         $this->user_first_name = '';
  85.         $this->user_last_name = '';
  86.         $this->user_company = 0;
  87.         $this->user_department = 0;
  88.         $this->user_type = 0;
  89.  
  90.         $this->project_id = 0;
  91.  
  92.         $this->defaultRedirect = "";
  93. // set up the default preferences
  94.         $this->user_locale = $this->base_locale;
  95.         $this->user_prefs = array();
  96.     }
  97. /**
  98. * Used to load a php class file from the system classes directory
  99. * @param string $name The class root file name (excluding .class.php)
  100. * @return string The path to the include file
  101.  */
  102.     function getSystemClass( $name=null ) {
  103.         if ($name) {
  104.             if ($root = $this->getConfig( 'root_dir' )) {
  105.                 return "$root/classes/$name.class.php";
  106.             }
  107.         }
  108.     }
  109.  
  110. /**
  111. * Used to load a php class file from the lib directory
  112. *
  113. * @param string $name The class root file name (excluding .class.php)
  114. * @return string The path to the include file
  115. */
  116.     function getLibraryClass( $name=null ) {
  117.         if ($name) {
  118.             if ($root = $this->getConfig( 'root_dir' )) {
  119.                 return "$root/lib/$name.php";
  120.             }
  121.         }
  122.     }
  123.  
  124. /**
  125. * Used to load a php class file from the module directory
  126. * @param string $name The class root file name (excluding .class.php)
  127. * @return string The path to the include file
  128.  */
  129.     function getModuleClass( $name=null ) {
  130.         if ($name) {
  131.             if ($root = $this->getConfig( 'root_dir' )) {
  132.                 return "$root/modules/$name/$name.class.php";
  133.             }
  134.         }
  135.     }
  136.  
  137. /**
  138. * Sets the internal confuration settings array.
  139. * @param array A named array of configuration variables (usually from config.php)
  140. */
  141.     function setConfig( &$cfg ) {
  142.         $this->cfg = $cfg;
  143.     }
  144.  
  145. /**
  146. * Retrieves a configuration setting.
  147. * @param string The name of a configuration setting
  148. * @return The value of the setting, otherwise null if the key is not found in the configuration array
  149. */
  150.     function getConfig( $key ) {
  151.         if (array_key_exists( $key, $this->cfg )) {
  152.             return $this->cfg[$key];
  153.         } else {
  154.             return null;
  155.         }
  156.     }
  157.  
  158. /**
  159. * Determines the version.
  160. * @return String value indicating the current dotproject version
  161. */
  162.     function getVersion() {
  163.         if ( ! isset($this->version_major)) {
  164.             include_once $this->cfg['root_dir'] . '/includes/version.php';
  165.             $this->version_major = $dp_version_major;
  166.             $this->version_minor = $dp_version_minor;
  167.             $this->version_patch = $dp_version_patch;
  168.             $this->version_string = $this->version_major . "." . $this->version_minor;
  169.             if (isset($this->version_patch))
  170.               $this->version_string .= "." . $this->version_patch;
  171.             if (isset($dp_version_prepatch))
  172.               $this->version_string .= "-" . $dp_version_prepatch;
  173.         }
  174.         return $this->version_string;
  175.     }
  176.  
  177. /**
  178. * Checks that the current user preferred style is valid/exists.
  179. */
  180.     function checkStyle() {
  181.         // check if default user's uistyle is installed
  182.         $uistyle = $this->getPref("UISTYLE");
  183.  
  184.         if ($uistyle && !is_dir("{$this->cfg['root_dir']}/style/$uistyle")) {
  185.             // fall back to host_style if user style is not installed
  186.             $this->setPref( 'UISTYLE', $this->cfg['host_style'] );
  187.         }
  188.     }
  189.  
  190. /**
  191. * Utility function to read the 'directories' under 'path'
  192. *
  193. * This function is used to read the modules or locales installed on the file system.
  194. * @param string The path to read.
  195. * @return array A named array of the directories (the key and value are identical).
  196. */
  197.     function readDirs( $path ) {
  198.         $dirs = array();
  199.         $d = dir( "{$this->cfg['root_dir']}/$path" );
  200.         while (false !== ($name = $d->read())) {
  201.             if(is_dir( "{$this->cfg['root_dir']}/$path/$name" ) && $name != "." && $name != ".." && $name != "CVS") {
  202.                 $dirs[$name] = $name;
  203.             }
  204.         }
  205.         $d->close();
  206.         return $dirs;
  207.     }
  208.  
  209. /**
  210. * Utility function to read the 'files' under 'path'
  211. * @param string The path to read.
  212. * @param string A regular expression to filter by.
  213. * @return array A named array of the files (the key and value are identical).
  214. */
  215.     function readFiles( $path, $filter='.' ) {
  216.         $files = array();
  217.  
  218.         if ($handle = opendir( $path )) {
  219.             while (false !== ($file = readdir( $handle ))) { 
  220.                 if ($file != "." && $file != ".." && preg_match( "/$filter/", $file )) { 
  221.                     $files[$file] = $file; 
  222.                 } 
  223.             }
  224.             closedir($handle); 
  225.         }
  226.         return $files;
  227.     }
  228.  
  229.  
  230. /**
  231. * Utility function to check whether a file name is 'safe'
  232. *
  233. * Prevents from access to relative directories (eg ../../dealyfile.php);
  234. * @param string The file name.
  235. * @return array A named array of the files (the key and value are identical).
  236. */
  237.     function checkFileName( $file ) {
  238.         global $AppUI;
  239.  
  240.         // define bad characters and their replacement
  241.         $bad_chars = ";/\\";
  242.         $bad_replace = "...."; // Needs the same number of chars as $bad_chars
  243.  
  244.         // check whether the filename contained bad characters
  245.         if ( strpos( strtr( $file, $bad_chars, $bad_replace), '.') !== false ) {
  246.             $AppUI->redirect( "m=public&a=access_denied" );
  247.         }
  248.         else {
  249.             return $file;
  250.         }
  251.  
  252.     }
  253.  
  254.  
  255.  
  256. /**
  257. * Utility function to make a file name 'safe'
  258. *
  259. * Strips out mallicious insertion of relative directories (eg ../../dealyfile.php);
  260. * @param string The file name.
  261. * @return array A named array of the files (the key and value are identical).
  262. */
  263.     function makeFileNameSafe( $file ) {
  264.         $file = str_replace( '../', '', $file );
  265.         $file = str_replace( '..\\', '', $file );
  266.         return $file;
  267.     }
  268.  
  269. /**
  270. * Sets the user locale.
  271. *
  272. * Looks in the user preferences first.  If this value has not been set by the user it uses the system default set in config.php.
  273. * @param string Locale abbreviation corresponding to the sub-directory name in the locales directory (usually the abbreviated language code).
  274. */
  275.     function setUserLocale( $loc='' ) {
  276.         if ($loc) {
  277.             $this->user_locale = $loc;
  278.         } else {
  279.             $this->user_locale = @$this->user_prefs['LOCALE'] ? $this->user_prefs['LOCALE'] : $this->cfg['host_locale'];
  280.         }
  281.     }
  282. /**
  283. * Translate string to the local language [same form as the gettext abbreviation]
  284. *
  285. * This is the order of precedence:
  286. * <ul>
  287. * <li>If the key exists in the lang array, return the value of the key
  288. * <li>If no key exists and the base lang is the same as the local lang, just return the string
  289. * <li>If this is not the base lang, then return string with a red star appended to show
  290. * that a translation is required.
  291. * </ul>
  292. * @param string The string to translate
  293. * @param int Option to change the case of the string
  294. * @return string
  295. */
  296.     function _( $str, $case=0 ) {
  297.         $str = trim($str);
  298.         if (empty( $str )) {
  299.             return '';
  300.         }
  301.         $x = @$GLOBALS['translate'][$str];
  302.         if ($x) {
  303.             $str = $x;
  304.         } else if (@$this->cfg['locale_warn']) {
  305.             if ($this->base_locale != $this->user_locale ||
  306.                 ($this->base_locale == $this->user_locale && !in_array( $str, @$GLOBALS['translate'] )) ) {
  307.                 $str .= @$this->cfg['locale_alert'];
  308.             }
  309.         }
  310.         switch ($case) {
  311.             case UI_CASE_UPPER:
  312.                 $str = strtoupper( $str );
  313.                 break;
  314.             case UI_CASE_LOWER:
  315.                 $str = strtolower( $str );
  316.                 break;
  317.             case UI_CASE_UPPERFIRST:
  318.                 break;
  319.         }
  320.         /* stripslashes added to fix #811242 on 2004 Jan 10
  321.          * if no problems occur, delete this comment. (gregor) */
  322.         return stripslashes($str);
  323.     }
  324. /**
  325. * Set the display of warning for untranslated strings
  326. * @param string
  327. */
  328.     function setWarning( $state=true ) {
  329.         $temp = @$this->cfg['locale_warn'];
  330.         $this->cfg['locale_warn'] = $state;
  331.         return $temp;
  332.     }
  333. /**
  334. * Save the url query string
  335. *
  336. * Also saves one level of history.  This is useful for returning from a delete
  337. * operation where the record more not now exist.  Returning to a view page
  338. * would be a nonsense in this case.
  339. * @param string If not set then the current url query string is used
  340. */
  341.     function savePlace( $query='' ) {
  342.         if (!$query) {
  343.             $query = @$_SERVER['QUERY_STRING'];
  344.         }
  345.         if ($query != @$this->state['SAVEDPLACE']) {
  346.             $this->state['SAVEDPLACE-1'] = @$this->state['SAVEDPLACE'];
  347.             $this->state['SAVEDPLACE'] = $query;
  348.         }
  349.     }
  350. /**
  351. * Resets the internal variable
  352. */
  353.     function resetPlace() {
  354.         $this->state['SAVEDPLACE'] = '';
  355.     }
  356. /**
  357. * Get the saved place (usually one that could contain an edit button)
  358. * @return string
  359. */
  360.     function getPlace() {
  361.         return @$this->state['SAVEDPLACE'];
  362.     }
  363. /**
  364. * Redirects the browser to a new page.
  365. *
  366. * Mostly used in conjunction with the savePlace method. It is generally used
  367. * to prevent nasties from doing a browser refresh after a db update.  The
  368. * method deliberately does not use javascript to effect the redirect.
  369. *
  370. * @param string The URL query string to append to the URL
  371. * @param string A marker for a historic 'place, only -1 or an empty string is valid.
  372. */
  373.     function redirect( $params='', $hist='' ) {
  374.         $session_id = SID;
  375.  
  376.         session_write_close();
  377.     // are the params empty
  378.         if (!$params) {
  379.         // has a place been saved
  380.             $params = !empty($this->state["SAVEDPLACE$hist"]) ? $this->state["SAVEDPLACE$hist"] : $this->defaultRedirect;
  381.         }
  382.         // Fix to handle cookieless sessions
  383.         if ($session_id != "") {
  384.           if (!$params)
  385.             $params = $session_id;
  386.           else
  387.             $params .= "&" . $session_id;
  388.         }
  389.         header( "Location: index.php?$params" );
  390.         exit();    // stop the PHP execution
  391.     }
  392. /**
  393. * Set the page message.
  394. *
  395. * The page message is displayed above the title block and then again
  396. * at the end of the page.
  397. *
  398. * IMPORTANT: Please note that append should not be used, since for some
  399. * languagues atomic-wise translation doesn't work. Append should be
  400. * deprecated.
  401. *
  402. * @param string The (translated) message
  403. * @param int The type of message
  404. * @param boolean If true, $msg is appended to the current string otherwise
  405. * the existing message is overwritten with $msg.
  406. */
  407.     function setMsg( $msg, $msgNo=0, $append=false ) {
  408.         $msg = $this->_( $msg );
  409.         $this->msg = $append ? $this->msg.' '.$msg : $msg;
  410.         $this->msgNo = $msgNo;
  411.     }
  412. /**
  413. * Display the formatted message and icon
  414. * @param boolean If true the current message state is cleared.
  415. */
  416.     function getMsg( $reset=true ) {
  417.         $img = '';
  418.         $class = '';
  419.         $msg = $this->msg;
  420.  
  421.         switch( $this->msgNo ) {
  422.         case UI_MSG_OK:
  423.             $img = dPshowImage( dPfindImage( 'stock_ok-16.png' ), 16, 16, '' );
  424.             $class = "message";
  425.             break;
  426.         case UI_MSG_ALERT:
  427.             $img = dPshowImage( dPfindImage( 'rc-gui-status-downgr.png' ), 16, 16, '' );
  428.             $class = "message";
  429.             break;
  430.         case UI_MSG_WARNING:
  431.             $img = dPshowImage( dPfindImage( 'rc-gui-status-downgr.png' ), 16, 16, '' );
  432.             $class = "warning";
  433.             break;
  434.         case UI_MSG_ERROR:
  435.             $img = dPshowImage( dPfindImage( 'stock_cancel-16.png' ), 16, 16, '' );
  436.             $class = "error";
  437.             break;
  438.         default:
  439.             $class = "message";
  440.             break;
  441.         }
  442.         if ($reset) {
  443.             $this->msg = '';
  444.             $this->msgNo = 0;
  445.         }
  446.         return $msg ? '<table cellspacing="0" cellpadding="1" border="0"><tr>'
  447.             . "<td>$img</td>"
  448.             . "<td class=\"$class\">$msg</td>"
  449.             . '</tr></table>'
  450.             : '';
  451.     }
  452. /**
  453. * Set the value of a temporary state variable.
  454. *
  455. * The state is only held for the duration of a session.  It is not stored in the database.
  456. * @param string The label or key of the state variable
  457. * @param mixed Value to assign to the label/key
  458. */
  459.     function setState( $label, $value ) {
  460.         $this->state[$label] = $value;
  461.     }
  462. /**
  463. * Get the value of a temporary state variable.
  464. * @return mixed
  465. */
  466.     function getState( $label ) {
  467.         return array_key_exists( $label, $this->state) ? $this->state[$label] : NULL;
  468.     }
  469. /**
  470. * Login function
  471. *
  472. * A number of things are done in this method to prevent illegal entry:
  473. * <ul>
  474. * <li>The username and password are trimmed and escaped to prevent malicious
  475. *     SQL being executed
  476. * <li>The username and encrypted password are selected from the database but
  477. *     the comparision is not made by the database, for example
  478. *     <code>...WHERE user_username = '$username' AND password=MD5('$password')...</code>
  479. *     to further prevent the injection of malicious SQL
  480. * </ul>
  481. * The schema previously used the MySQL PASSWORD function for encryption.  This
  482. * is not the recommended technique so a procedure was introduced to first check
  483. * for a match using the PASSWORD function.  If this is successful, then the
  484. * is upgraded to the MD5 encyption format.  This check can be controlled by the
  485. * <code>check_legacy_password</code> configuration variable in </code>config.php</code>
  486. *
  487. * Upon a successful username and password match, several fields from the user
  488. * table are loaded in this object for convenient reference.  The style, localces
  489. * and preferences are also loaded at this time.
  490. *
  491. * @param string The user login name
  492. * @param string The user password
  493. * @return boolean True if successful, false if not
  494. */
  495.     function login( $username, $password ) {
  496.         $username = trim( db_escape( $username ) );
  497.         $password = trim( db_escape( $password ) );
  498.  
  499.         $sql = "
  500.         SELECT user_id, user_password AS pwd, password('$password') AS pwdpwd, md5('$password') AS pwdmd5
  501.         FROM users, permissions
  502.         WHERE user_username = '$username'
  503.             AND users.user_id = permissions.permission_user
  504.             AND permission_value <> 0
  505.         ";
  506.  
  507.         $row = null;
  508.         if (!db_loadObject( $sql, $row )) {
  509.             return false;
  510.         }
  511.  
  512.         if (strcmp( $row->pwd, $row->pwdmd5 )) {
  513.             if ($this->cfg['check_legacy_password']) {
  514.             /* next check the legacy password */
  515.                 if (strcmp( $row->pwd, $row->pwdpwd )) {
  516.                     /* no match - failed login */
  517.                     return false;
  518.                 } else {
  519.                     /* valid legacy login - update the md5 password */
  520.                     $sql = "UPDATE users SET user_password=MD5('$password') WHERE user_id=$row->user_id";
  521.                     db_exec( $sql ) or die( "Password update failed." );
  522.                     $this->setMsg( 'Password updated', UI_MSG_ALERT );
  523.                 }
  524.             } else {
  525.                 return false;
  526.             }
  527.         }
  528.  
  529.         $sql = "
  530.         SELECT user_id, user_first_name, user_last_name, user_company, user_department, user_email, user_type
  531.         FROM users
  532.         WHERE user_id = $row->user_id AND user_username = '$username'
  533.         ";
  534.  
  535.         writeDebug( $sql, 'Login SQL', __FILE__, __LINE__ );
  536.  
  537.         if( !db_loadObject( $sql, $this ) ) {
  538.             return false;
  539.         }
  540.  
  541. // load the user preferences
  542.         $this->loadPrefs( $this->user_id );
  543.         $this->setUserLocale();
  544.         $this->checkStyle();
  545.         return true;
  546.     }
  547. /**
  548. * @deprecated
  549. */
  550.     function logout() {
  551.     }
  552. /**
  553. * Checks whether there is any user logged in.
  554. */
  555.     function doLogin() {
  556.         return ($this->user_id < 0) ? true : false;
  557.     }
  558. /**
  559. * Gets the value of the specified user preference
  560. * @param string Name of the preference
  561. */
  562.     function getPref( $name ) {
  563.         return @$this->user_prefs[$name];
  564.     }
  565. /**
  566. * Sets the value of a user preference specified by name
  567. * @param string Name of the preference
  568. * @param mixed The value of the preference
  569. */
  570.     function setPref( $name, $val ) {
  571.         $this->user_prefs[$name] = $val;
  572.     }
  573. /**
  574. * Loads the stored user preferences from the database into the internal
  575. * preferences variable.
  576. * @param int User id number
  577. */
  578.     function loadPrefs( $uid=0 ) {
  579.         $sql = "SELECT pref_name, pref_value FROM user_preferences WHERE pref_user = $uid";
  580.         //writeDebug( $sql, "Preferences for user $uid, SQL", __FILE__, __LINE__ );
  581.         $prefs = db_loadHashList( $sql );
  582.         $this->user_prefs = array_merge( $this->user_prefs, db_loadHashList( $sql ) );
  583.     }
  584.  
  585. // --- Module connectors
  586.  
  587. /**
  588. * Gets a list of the installed modules
  589. * @return array Named array list in the form 'module directory'=>'module name'
  590. */
  591.     function getInstalledModules() {
  592.         $sql = "
  593.         SELECT mod_directory, mod_ui_name
  594.         FROM modules
  595.         ORDER BY mod_directory
  596.         ";
  597.         return (db_loadHashList( $sql ));
  598.     }
  599. /**
  600. * Gets a list of the active modules
  601. * @return array Named array list in the form 'module directory'=>'module name'
  602. */
  603.     function getActiveModules() {
  604.         $sql = "
  605.         SELECT mod_directory, mod_ui_name
  606.         FROM modules
  607.         WHERE mod_active > 0
  608.         ORDER BY mod_directory
  609.         ";
  610.         return (db_loadHashList( $sql ));
  611.     }
  612. /**
  613. * Gets a list of the modules that should appear in the menu
  614. * @return array Named array list in the form
  615. * ['module directory', 'module name', 'module_icon']
  616. */
  617.     function getMenuModules() {
  618.         $sql = "
  619.         SELECT mod_directory, mod_ui_name, mod_ui_icon
  620.         FROM modules
  621.         WHERE mod_active > 0 AND mod_ui_active > 0
  622.         ORDER BY mod_ui_order
  623.         ";
  624.         return (db_loadList( $sql ));
  625.     }
  626. }
  627.  
  628. /**
  629. * Tabbed box abstract class
  630. */
  631. class CTabBox_core {
  632. /** @var array */
  633.     var $tabs=NULL;
  634. /** @var int The active tab */
  635.     var $active=NULL;
  636. /** @var string The base URL query string to prefix tab links */
  637.     var $baseHRef=NULL;
  638. /** @var string The base path to prefix the include file */
  639.     var $baseInc;
  640.  
  641. /**
  642. * Constructor
  643. * @param string The base URL query string to prefix tab links
  644. * @param string The base path to prefix the include file
  645. * @param int The active tab
  646. */
  647.     function CTabBox( $baseHRef='', $baseInc='', $active=0 ) {
  648.         $this->tabs = array();
  649.         $this->active = $active;
  650.         $this->baseHRef = ($baseHRef ? "$baseHRef&" : "?");
  651.         $this->baseInc = $baseInc;
  652.     }
  653. /**
  654. * Gets the name of a tab
  655. * @return string
  656. */
  657.     function getTabName( $idx ) {
  658.         return $this->tabs[$idx][1];
  659.     }
  660. /**
  661. * Adds a tab to the object
  662. * @param string File to include
  663. * @param The display title/name of the tab
  664. */
  665.     function add( $file, $title ) {
  666.         $this->tabs[] = array( $file, $title );
  667.     }
  668. /**
  669. * Displays the tabbed box
  670. *
  671. * This function may be overridden
  672. *
  673. * @param string Can't remember whether this was useful
  674. */
  675.     function show( $extra='' ) {
  676.         GLOBAL $AppUI;
  677.         reset( $this->tabs );
  678.         $s = '';
  679.     // tabbed / flat view options
  680.         if (@$AppUI->getPref( 'TABVIEW' ) == 0) {
  681.             $s .= '<table border="0" cellpadding="2" cellspacing="0" width="100%"><tr><td nowrap="nowrap">';
  682.             $s .= '<a href="'.$this->baseHRef.'tab=0">'.$AppUI->_('tabbed').'</a> : ';
  683.             $s .= '<a href="'.$this->baseHRef.'tab=-1">'.$AppUI->_('flat').'</a>';
  684.             $s .= '</td>'.$extra.'</tr></table>';
  685.             echo $s;
  686.         } else {
  687.             if ($extra) {
  688.                 echo '<table border="0" cellpadding="2" cellspacing="0" width="100%"><tr>'.$extra.'</tr></table>';
  689.             } else {
  690.                 echo '<img src="./images/shim.gif" height="10" width="1" />';
  691.             }
  692.         }
  693.  
  694.         if ($this->active < 0 || @$AppUI->getPref( 'TABVIEW' ) == 2 ) {
  695.         // flat view, active = -1
  696.             echo '<table border="0" cellpadding="2" cellspacing="0" width="100%">';
  697.             foreach ($this->tabs as $v) {
  698.                 echo '<tr><td><strong>'.$AppUI->_($v[1]).'</strong></td></tr>';
  699.                 echo '<tr><td>';
  700.                 include $this->baseInc.$v[0].".php";
  701.                 echo '</td></tr>';
  702.             }
  703.             echo '</table>';
  704.         } else {
  705.         // tabbed view
  706.             $s = "<table width=\"100%\" border=\"0\" cellpadding=\"3\" cellspacing=\"0\">\n<tr>";
  707.             if ( count($this->tabs)-1 < $this->active ) {
  708.                 //Last selected tab is not available in this view. eg. Child tasks
  709.                 $this->active = 0;
  710.             }
  711.             foreach( $this->tabs as $k => $v ) {
  712.                 $class = ($k == $this->active) ? 'tabon' : 'taboff';
  713.                 $s .= "\n\t<td width=\"1%\" nowrap=\"nowrap\" class=\"tabsp\">";
  714.                 $s .= "\n\t\t<img src=\"./images/shim.gif\" height=\"1\" width=\"1\" alt=\"\" />";
  715.                 $s .= "\n\t</td>";
  716.                 $s .= "\n\t<td width=\"1%\" nowrap=\"nowrap\" class=\"$class\">";
  717.                 $s .= "\n\t\t<a href=\"{$this->baseHRef}tab=$k\">".$AppUI->_($v[1])."</a>";
  718.                 $s .= "\n\t</td>";
  719.             }
  720.             $s .= "\n\t<td nowrap=\"nowrap\" class=\"tabsp\"> </td>";
  721.             $s .= "\n</tr>";
  722.             $s .= "\n<tr>";
  723.             $s .= '<td width="100%" colspan="'.(count($this->tabs)*2 + 1).'" class="tabox">';
  724.             echo $s;
  725.             //Will be null if the previous selection tab is not available in the new window eg. Children tasks
  726.             if ( $this->baseInc.$this->tabs[$this->active][0] != "" )
  727.                 require $this->baseInc.$this->tabs[$this->active][0].'.php';
  728.             echo "\n</td>\n</tr>\n</table>";
  729.         }
  730.     }
  731. }
  732.  
  733. /**
  734. * Title box abstract class
  735. */
  736. class CTitleBlock_core {
  737. /** @var string The main title of the page */
  738.     var $title='';
  739. /** @var string The name of the icon used to the left of the title */
  740.     var $icon='';
  741. /** @var string The name of the module that this title block is displaying in */
  742.     var $module='';
  743. /** @var array An array of the table 'cells' to the right of the title block and for bread-crumbs */
  744.     var $cells=null;
  745. /** @var string The reference for the context help system */
  746.     var $helpref='';
  747. /**
  748. * The constructor
  749. *
  750. * Assigns the title, icon, module and help reference.  If the user does not
  751. * have permission to view the help module, then the context help icon is
  752. * not displayed.
  753. */
  754.     function CTitleBlock_core( $title, $icon='', $module='', $helpref='' ) {
  755.         $this->title = $title;
  756.         $this->icon = $icon;
  757.         $this->module = $module;
  758.         $this->helpref = $helpref;
  759.         $this->cells1 = array();
  760.         $this->cells2 = array();
  761.         $this->crumbs = array();
  762.         $this->showhelp = !getDenyRead( 'help' );
  763.     }
  764. /**
  765. * Adds a table 'cell' beside the Title string
  766. *
  767. * Cells are added from left to right.
  768. */
  769.     function addCell( $data='', $attribs='', $prefix='', $suffix='' ) {
  770.         $this->cells1[] = array( $attribs, $data, $prefix, $suffix );
  771.     }
  772. /**
  773. * Adds a table 'cell' to left-aligned bread-crumbs
  774. *
  775. * Cells are added from left to right.
  776. */
  777.     function addCrumb( $link, $label, $icon='' ) {
  778.         $this->crumbs[$link] = array( $label, $icon );
  779.     }
  780. /**
  781. * Adds a table 'cell' to the right-aligned bread-crumbs
  782. *
  783. * Cells are added from left to right.
  784. */
  785.     function addCrumbRight( $data='', $attribs='', $prefix='', $suffix='' ) {
  786.         $this->cells2[] = array( $attribs, $data, $prefix, $suffix );
  787.     }
  788. /**
  789. * Creates a standarised, right-aligned delete bread-crumb and icon.
  790. */
  791.     function addCrumbDelete( $title, $canDelete='', $msg='' ) {
  792.         global $AppUI;
  793.         $this->addCrumbRight(
  794.             '<table cellspacing="0" cellpadding="0" border="0"?<tr><td>'
  795.             . '<a href="javascript:delIt()" title="'.($canDelete?'':$msg).'">'
  796.             . dPshowImage( './images/icons/'.($canDelete?'stock_delete-16.png':'stock_trash_full-16.png'), '16', '16',  '' )
  797.             . '</a>'
  798.             . '</td><td> '
  799.             . '<a href="javascript:delIt()" title="'.($canDelete?'':$msg).'">' . $AppUI->_( $title ) . '</a>'
  800.             . '</td></tr></table>'
  801.         );
  802.     }
  803. /**
  804. * The drawing function
  805. */
  806.     function show() {
  807.         global $AppUI;
  808.         $CR = "\n";
  809.         $CT = "\n\t";
  810.         $s = $CR . '<table width="100%" border="0" cellpadding="1" cellspacing="1">';
  811.         $s .= $CR . '<tr>';
  812.         if ($this->icon) {
  813.             $s .= $CR . '<td width="42">';
  814.             $s .= dPshowImage( dPFindImage( $this->icon, $this->module ), '42', '42' );
  815.             $s .= '</td>';
  816.         }
  817.         $s .= $CR . '<td align="left" width="100%" nowrap="nowrap"><h1>' . $AppUI->_($this->title) . '</h1></td>';
  818.         foreach ($this->cells1 as $c) {
  819.             $s .= $c[2] ? $CR . $c[2] : '';
  820.             $s .= $CR . '<td align="right" nowrap="nowrap"' . ($c[0] ? " $c[0]" : '') . '>';
  821.             $s .= $c[1] ? $CT . $c[1] : ' ';
  822.             $s .= $CR . '</td>';
  823.             $s .= $c[3] ? $CR . $c[3] : '';
  824.         }
  825.         if ($this->showhelp) {
  826.             $s .= '<td nowrap="nowrap" width="20" align="right">';
  827.             //$s .= $CT . contextHelp( '<img src="./images/obj/help.gif" width="14" height="16" border="0" alt="'.$AppUI->_( 'Help' ).'" />', $this->helpref );
  828.  
  829.             $s .= "\n\t<a href=\"#$this->helpref\" onClick=\"javascript:window.open('?m=help&dialog=1&hid=$this->helpref', 'contexthelp', 'width=400, height=400, left=50, top=50, scrollbars=yes, resizable=yes')\" title=\"".$AppUI->_( 'Help' )."\">";
  830.             $s .= "\n\t\t" . dPshowImage( './images/icons/stock_help-16.png', '16', '16', $AppUI->_( 'Help' ) );
  831.             $s .= "\n\t</a>";
  832.             $s .= "\n</td>";
  833.         }
  834.         $s .= "\n</tr>";
  835.         $s .= "\n</table>";
  836.  
  837.         if (count( $this->crumbs ) || count( $this->cells2 )) {
  838.             $crumbs = array();
  839.             foreach ($this->crumbs as $k => $v) {
  840.                 $t = $v[1] ? '<img src="' . dPfindImage( $v[1], $this->module ) . '" border="" alt="" /> ' : '';
  841.                 $t .= $AppUI->_( $v[0] );
  842.                 $crumbs[] = "<a href=\"$k\">$t</a>";
  843.             }
  844.             $s .= "\n<table border=\"0\" cellpadding=\"4\" cellspacing=\"0\" width=\"100%\">";
  845.             $s .= "\n<tr>";
  846.             $s .= "\n\t<td nowrap=\"nowrap\">";
  847.             $s .= "\n\t\t" . implode( ' <strong>:</strong> ', $crumbs );
  848.             $s .= "\n\t</td>";
  849.  
  850.             foreach ($this->cells2 as $c) {
  851.                 $s .= $c[2] ? "\n$c[2]" : '';
  852.                 $s .= "\n\t<td align=\"right\" nowrap=\"nowrap\"" . ($c[0] ? " $c[0]" : '') . '>';
  853.                 $s .= $c[1] ? "\n\t$c[1]" : ' ';
  854.                 $s .= "\n\t</td>";
  855.                 $s .= $c[3] ? "\n\t$c[3]" : '';
  856.             }
  857.  
  858.             $s .= "\n</tr>\n</table>";
  859.         }
  860.         echo "$s";
  861.     }
  862. }
  863. // !! Ensure there is no white space after this close php tag.
  864. ?>
  865.