2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
40 class DetailView extends ListView {
42 var $list_row_count = null;
43 var $return_to_list_only=false;
44 var $offset_key_mismatch=false;
45 var $no_record_found=false;
47 function DetailView(){
50 global $theme, $app_strings, $currentModule;
51 $this->local_theme = $theme;
52 $this->local_app_strings =$app_strings;
55 function processSugarBean($html_varName, $seed, &$offset, $isfirstview=0) {
56 global $row_count, $sugar_config;
59 global $previous_offset;
60 global $list_view_row_count;
61 global $current_offset;
62 if (!empty($sugar_config['disable_vcr']) ) {
63 $seed->retrieve($_REQUEST['record']);
68 $nav_history_set=false;
69 $nav_history_array=array();
71 $nav_ids_visited=array();
74 //get the session variable DETAIL_NAV_HISTORY,
75 //the format of the variable stamp,offset, array of IDs visited.
76 $nav_history=$this->getLocalSessionVariable($html_varName, "DETAIL_NAV_HISTORY");
77 if (!empty($nav_history)) {
78 $nav_history_set=true;
79 $nav_history_array=explode(":",$nav_history);
80 $nav_stamp=$nav_history_array[0];
81 $nav_offset=$nav_history_array[1];
82 eval("\$nav_ids_visited= ".$nav_history_array[2].";");
85 //from list offset is there but $bNavHistorySet is false.
86 //from next,previous,start and end buttons offset and $bNavHistorySet is true.
87 //from tracker offset is not there but $bNavHistorySet may or may not exist.
88 if (isset($_REQUEST['offset']) && !empty($_REQUEST['offset'])) {
90 $offset = $_REQUEST['offset'];
94 //if the stamp has changed, ignore the offset and navigate to the record.
95 //use case, search, navigate to detail, copy URL, search again, paste URL.
96 if (!$this->isRequestFromListView($html_varName)) {
97 $result = $seed->retrieve($_REQUEST['record']);
101 if ($nav_history_set) {
102 if (isset($nav_ids_visited[$offset])) {
103 unset($nav_ids_visited[$offset]);
108 if ($nav_history_set) {
109 //try to locate the ID in the nav_history array.
111 $key = array_search($_REQUEST['record'], $nav_ids_visited);
112 if ($key === false) {
113 //do not show the VCR buttons.
115 $result = $seed->retrieve($_REQUEST['record']);
119 $_REQUEST['offset'] = $offset;
120 $_GET['offset'] = $offset;
121 $_POST['offset'] = $offset;
123 $_REQUEST['stamp'] = $nav_stamp;
124 $_GET['stamp'] = $nav_stamp;
125 $_POST['stamp'] = $nav_stamp;
126 if (isset($nav_ids_visited[$offset])) {
127 unset($nav_ids_visited[$offset]);
131 if(!empty($seed->id))return $seed;
133 $result = $seed->retrieve($_REQUEST['record']);
138 //Check if this is the first time we have viewed this record
139 $var = $this->getLocalSessionVariable($html_varName, "IS_FIRST_VIEW");
140 if(!isset($var) || !$var){
144 $isFirstView = false;
146 //indicate that this is not the first time anymore
147 $this->setLocalSessionVariable($html_varName, "IS_FIRST_VIEW", false);
149 // All 3 databases require this because the limit query does a > db_offset comparision.
150 $db_offset=$offset-1;
152 $this->populateQueryWhere($isFirstView, $html_varName);
153 if(ACLController::requireOwner($seed->module_dir, 'view')) {
154 global $current_user;
155 $seed->getOwnerWhere($current_user->id);
156 if(!empty($this->query_where)) {
157 $this->query_where .= ' AND ';
159 $this->query_where .= $seed->getOwnerWhere($current_user->id);
162 $order = $this->getLocalSessionVariable($seed->module_dir.'2_'.$html_varName, "ORDER_BY");
164 if(!empty($order['orderBy']))
165 $orderBy = $order['orderBy'];
166 if(!empty($orderBy) && !empty($order['direction']))
167 $orderBy .= ' ' . $order['direction'];
169 $this->query_orderby = $seed->process_order_by($orderBy,null);
170 $current_offset = $_REQUEST['offset'] -1;
171 $response = $seed->process_detail_query(SugarVCR::retrieve($seed->module_dir), 0, -1, -1, '', $current_offset);
172 //$response = $seed->get_detail(, $this->query_where, $db_offset);
173 $object = $response['bean'];
174 $row_count = $response['row_count'];
175 $next_offset = $response['next_offset'];
176 $previous_offset = $response['previous_offset'];
177 $list_view_row_count = $row_count;
178 $this->setListViewRowCount($row_count);
180 //if the retrieved id is not same as the request ID then hide the VCR buttons.
181 if (empty($object->id)) {
182 $this->no_record_found=true;
184 if (empty($_REQUEST['InDetailNav']) and strcmp($_REQUEST['record'],$object->id)!=0) {
185 $this->offset_key_mismatch=true;
187 if ($this->no_record_found or $this->offset_key_mismatch ) {
188 if ($nav_history_set) {
189 $this->return_to_list_only=true;
191 $result = $seed->retrieve($_REQUEST['record']);
195 //update the request with correct value for the record attribute.
196 //need only when using the VCR buttuoms. This is a workaround need to fix the values
197 //set in the VCR links.
198 $_REQUEST['record'] = $object->id;
199 $_GET['record'] = $object->id;
200 $_POST['record'] = $object->id;
203 if (empty($nav_stamp)) {
204 $nav_stamp=$_GET['stamp'];
206 if (empty($nav_offset)) {
209 //store a maximum of 20 entries in the nav_ids_visited array.
210 //remove the oldest entry when this limit is reached.
211 if (count($nav_ids_visited) >= 20) {
212 reset($nav_ids_visited);
213 unset($nav_ids_visited[key($nav_ids_visited)]);
215 $nav_ids_visited[$offset]=$object->id;
216 $nav_history=sprintf("%s:%s:%s",$nav_stamp,$nav_offset,var_export($nav_ids_visited,true));
217 $this->setLocalSessionVariable($html_varName, "DETAIL_NAV_HISTORY",$nav_history);
222 function populateQueryWhere($isfirstview, $html_varName){
224 $this->query_where = $this->getVariableFromSession($_REQUEST['module'], 'QUERY_WHERE');
226 //this is a fail safe, in case the old ListView is still in use
227 if(empty($this->query_where)){
228 $this->query_where = $this->getLocalSessionVariable($html_varName, "QUERY_WHERE");
230 //SETTING QUERY FOR LATER USE
231 $this->setSessionVariable("QUERY_DETAIL", "where", $this->query_where);
234 $this->query_where = $this->getSessionVariable("QUERY_DETAIL", "where");
238 function processListNavigation( &$xtpl, $html_varName, $current_offset, $display_audit_link = false){
239 global $export_module, $sugar_config, $current_user;
240 //intialize audit_link
243 $row_count = $this->getListViewRowCount();
245 if($display_audit_link && (!isset($sugar_config['disc_client']) || $sugar_config['disc_client'] == false))
248 $popup_request_data = array(
249 'call_back_function' => 'set_return',
250 'form_name' => 'EditView',
251 'field_to_name_array' => array(),
253 $json = getJSONobj();
254 $encoded_popup_request_data = $json->encode($popup_request_data);
255 $audit_link = "<a href='#' onclick='open_popup(\"Audit\", \"600\", \"400\", \"&record=".$_REQUEST['record']."&module_name=".$_REQUEST['module']."\", true, false, $encoded_popup_request_data);'>".$this->local_app_strings['LNK_VIEW_CHANGE_LOG']."</a>";
260 $pre_html_text .= "<tr class='pagination'>\n";
261 $pre_html_text .= "<td COLSPAN=\"20\">\n";
262 $pre_html_text .= "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\"><tr><td style=\"text-align: left\" > ".$audit_link."</td>\n";
266 if ($this->return_to_list_only == true) {
267 if($current_offset != 0 && $this->isRequestFromListView($html_varName))
269 if($current_offset < 0){
272 else if($current_offset > $row_count){
273 $current_offset = $row_count;
276 $this->set_base_URL($html_varName);
277 $list_URL = $this->base_URL.'&action=index&module='.$_REQUEST['module'];
278 $current_page = floor($current_offset / $this->records_per_page) * $this->records_per_page;
280 $list_URL .= '&'.$this->getSessionVariableName($html_varName,"offset").'='.$current_page;
281 //$list_link = "<a href=\"$list_URL\" >".$this->local_app_strings['LNK_LIST_RETURN']." </a>";
282 $list_link = "<button type='button' class='button' title='{$GLOBALS['app_strings']['LNK_LIST_RETURN']}' onClick='location.href=\"$list_URL\";'>".$this->local_app_strings['LNK_LIST_RETURN']."</button>";
284 $html_text .= "<td nowrap align='right' scope='row'>".$list_link;
286 if ($row_count != 0) {
287 $resume_URL = $this->base_URL.$current_offset."&InDetailNav=1";
288 //$resume_link = "<a href=\"$resume_URL\" >".$this->local_app_strings['LNK_RESUME']." </a>";
289 $resume_link = "<button type='button' class='button' title='$this->local_app_strings['LNK_RESUME']' onClick='location.href=\"$resume_URL\";'>".$this->local_app_strings['LNK_RESUME']."</button>";
291 $html_text .= " ".$resume_link;
293 $html_text .= "</td>";
297 if($current_offset != 0 && $this->isRequestFromListView($html_varName))
299 if($current_offset < 0){
302 else if($current_offset > $row_count){
303 $current_offset = $row_count;
306 $next_offset = $current_offset + 1;
307 $previous_offset = $current_offset - 1;
309 $this->set_base_URL($html_varName);
311 $start_URL = $this->base_URL."1"."&InDetailNav=1";
312 $current_URL = $this->base_URL.$current_offset."&InDetailNav=1";
313 $previous_URL = $this->base_URL.$previous_offset."&InDetailNav=1";
314 $next_URL = $this->base_URL.$next_offset."&InDetailNav=1";
315 $end_URL = $this->base_URL.$row_count."&InDetailNav=1";
317 $current_page = floor($current_offset / $this->records_per_page) * $this->records_per_page;
319 if(1 == $current_offset){
320 //$start_link = SugarThemeRegistry::current()->getImage("start_off","alt='".$this->local_app_strings['LNK_LIST_START']."' border='0' align='absmiddle'")." ".$this->local_app_strings['LNK_LIST_START'];
321 //$previous_link = SugarThemeRegistry::current()->getImage("previous_off","alt='".$this->local_app_strings['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'")." ".$this->local_app_strings['LNK_LIST_PREVIOUS']."";
322 $start_link = "<button type='button' title='{$this->local_app_strings['LNK_LIST_START']}' class='button' disabled>".SugarThemeRegistry::current()->getImage("start_off","alt='".$this->local_app_strings['LNK_LIST_START']."' border='0' align='absmiddle'")."</button>";
323 $previous_link = "<button type='button' title='{$this->local_app_strings['LNK_LIST_PREVIOUS']}' class='button' disabled>".SugarThemeRegistry::current()->getImage("previous_off","alt='".$this->local_app_strings['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'")."</button>";
326 //$start_link = "<a href=\"$start_URL\">".SugarThemeRegistry::current()->getImage("start","alt='".$this->local_app_strings['LNK_LIST_START']."' border='0' align='absmiddle'")."</a> <a href=\"$start_URL\">".$this->local_app_strings['LNK_LIST_START']."</a>";
327 $start_link = "<button type='button' class='button' title='{$this->local_app_strings['LNK_LIST_START']}' onClick='location.href=\"$start_URL\";'>".SugarThemeRegistry::current()->getImage("start","alt='".$this->local_app_strings['LNK_LIST_START']."' border='0' align='absmiddle'")."</button>";
329 if(0 != $current_offset){
330 //$previous_link = "<a href=\"$previous_URL\">".SugarThemeRegistry::current()->getImage("previous","alt='".$this->local_app_strings['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'")."</a> <a href=\"$previous_URL\" >".$this->local_app_strings['LNK_LIST_PREVIOUS']."</a>";
331 $previous_link = "<button type='button' class='button' title='{$this->local_app_strings['LNK_LIST_PREVIOUS']}' onClick='location.href=\"$previous_URL\";'>".SugarThemeRegistry::current()->getImage("previous","alt='".$this->local_app_strings['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'")."</button>";
334 //$previous_link = SugarThemeRegistry::current()->getImage("previous_off","alt='".$this->local_app_strings['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'")." ".$this->local_app_strings['LNK_LIST_PREVIOUS'];
335 $previous_link = "<button type='button' title='{$this->local_app_strings['LNK_LIST_PREVIOUS']}' class='button' disabled>".SugarThemeRegistry::current()->getImage("previous_off","alt='".$this->local_app_strings['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'")."</button>";
341 if($row_count <= $current_offset){
342 //$end_link = $this->local_app_strings['LNK_LIST_END']." ".SugarThemeRegistry::current()->getImage("end_off","alt='".$this->local_app_strings['LNK_LIST_END']."' border='0' align='absmiddle'");
343 //$next_link = $this->local_app_strings['LNK_LIST_NEXT']." ".SugarThemeRegistry::current()->getImage("next_off","alt='".$this->local_app_strings['LNK_LIST_NEXT']."' border='0' align='absmiddle'");
344 $end_link = "<button type='button' title='{$this->local_app_strings['LNK_LIST_END']}' class='button' disabled>".SugarThemeRegistry::current()->getImage("end_off","alt='".$this->local_app_strings['LNK_LIST_END']."' border='0' align='absmiddle'")."</button>";
345 $next_link = "<button type='button' title='{$this->local_app_strings['LNK_LIST_NEXT']}' class='button' disabled>".SugarThemeRegistry::current()->getImage("next_off","alt='".$this->local_app_strings['LNK_LIST_NEXT']."' border='0' align='absmiddle'")."</button>";
348 //$end_link = "<a href=\"$end_URL\">".$this->local_app_strings['LNK_LIST_END']."</a> <a href=\"$end_URL\">".SugarThemeRegistry::current()->getImage("end","alt='".$this->local_app_strings['LNK_LIST_END']."' border='0' align='absmiddle'")."</a>";
349 //$next_link = "<a href=\"$next_URL\">".$this->local_app_strings['LNK_LIST_NEXT']."</a> <a href=\"$next_URL\">".SugarThemeRegistry::current()->getImage("next","alt='".$this->local_app_strings['LNK_LIST_NEXT']."' border='0' align='absmiddle'")."</a>";
350 $end_link = "<button type='button' class='button' title='{$this->local_app_strings['LNK_LIST_END']}' onClick='location.href=\"$end_URL\";'>".SugarThemeRegistry::current()->getImage("end","alt='".$this->local_app_strings['LNK_LIST_END']."' border='0' align='absmiddle'")."</button>";
351 $next_link = "<button type='button' class='button' title='{$this->local_app_strings['LNK_LIST_NEXT']}' onClick='location.href=\"$next_URL\";'>".SugarThemeRegistry::current()->getImage("next","alt='".$this->local_app_strings['LNK_LIST_NEXT']."' border='0' align='absmiddle'")."</button>";
355 $html_text .= "<td nowrap align='right' >".$start_link." ".$previous_link." (".$current_offset." ".$this->local_app_strings['LBL_LIST_OF']." ".$row_count.") ".$next_link." ".$end_link."</td>";
359 $post_html_text = "</tr></table>\n";
360 $post_html_text .= "</td>\n";
361 $post_html_text .= "</tr>\n";
362 $showVCRControl = true;
363 if(isset($sugar_config['disable_vcr'])) {
364 $showVCRControl = !$sugar_config['disable_vcr'];
366 if ( $showVCRControl && $html_text != "" )
367 $xtpl->assign("PAGINATION",$pre_html_text.$html_text.$post_html_text);
371 function set_base_URL($html_varName) {
373 if(!isset($this->base_URL)){
375 $this->base_URL = $_SERVER['PHP_SELF'];
376 if(empty($this->base_URL)){
377 $this->base_URL = 'index.php';
380 /*fixes an issue with
381 deletes when doing a search*/
382 foreach($_GET as $name=>$value){
384 if($name != $this->getSessionVariableName($html_varName,"ORDER_BY") && $name != "offset" && substr_count($name, "ORDER_BY")==0 && $name!="isfirstview"){
385 if (is_array($value)) {
386 foreach($value as $valuename=>$valuevalue){
387 $this->base_URL .= "&{$name}[]=".$valuevalue;
390 if(substr_count( $this->base_URL, '?') > 0){
391 $this->base_URL .= "&$name=$value";
393 $this->base_URL .= "?$name=$value";
400 if($_SERVER['REQUEST_METHOD'] == 'POST'){
401 $this->base_URL .= '?';
402 if(isset($_REQUEST['action'])) $this->base_URL .= '&action='.$_REQUEST['action'];
403 if(isset($_REQUEST['record'])) $this->base_URL .= '&record='.$_REQUEST['record'];
404 if(isset($_REQUEST['module'])) $this->base_URL .= '&module='.$_REQUEST['module'];
406 $this->base_URL .= "&offset=";
409 function setListViewRowCount($count)
411 $this->list_row_count = $count;
414 function getListViewRowCount()
416 return $this->list_row_count;
419 /* This method will return in all of these cases: When selecting any of the VCR buttons (start,prev,next or last)
420 * and navigating from list to detail for the first time.
421 * if false in this case: the user changes the list query (which generates a new stamp) and pastes a URL
422 * from a previously navigated item.
424 function isRequestFromListView($html_varName)
426 $varList = $this->getLocalSessionVariable($html_varName, "FROM_LIST_VIEW");
427 if(isset($_GET['stamp']) && isset($varList) && $varList == $_GET['stamp']){
436 * Return a variable from the session. uses the new ListView session data. Hence the '2'
438 * @param unknown_type $name - the name of the variable to set in the session
439 * @param unknown_type $value - the value of the variable to set
441 function getVariableFromSession($name, $value){
442 if(isset($_SESSION[$name."2_".$value])){
443 return $_SESSION[$name."2_".$value];