/**
  * Updates the object form POSTED arguments, and writes it into the DB (applies a stimuli if requested)
  * @param DBObject $oObj The object to update
  * $param array $aAttList If set, this will limit the list of updated attributes	 
  * @return void
  */
 public function DoUpdateObjectFromPostedForm(DBObject $oObj, $aAttList = null)
 {
     $sTransactionId = utils::ReadPostedParam('transaction_id', '');
     if (!utils::IsTransactionValid($sTransactionId)) {
         throw new TransactionException();
     }
     $sClass = get_class($oObj);
     $sStimulus = trim(utils::ReadPostedParam('apply_stimulus', ''));
     $sTargetState = '';
     if (!empty($sStimulus)) {
         // Compute the target state
         $aTransitions = $oObj->EnumTransitions();
         if (!isset($aTransitions[$sStimulus])) {
             throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
         }
         $sTargetState = $aTransitions[$sStimulus]['target_state'];
     }
     $oObj->UpdateObjectFromPostedForm('', $aAttList, $sTargetState);
     // Optional: apply a stimulus
     //
     if (!empty($sStimulus)) {
         if (!$oObj->ApplyStimulus($sStimulus)) {
             throw new Exception("Cannot apply stimulus '{$sStimulus}' to {$oObj->GetName()}");
         }
     }
     if ($oObj->IsModified()) {
         // Record the change
         //
         $oObj->DBUpdate();
         // Trigger ?
         //
         $aClasses = MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL);
         $sClassList = implode(", ", CMDBSource::Quote($aClasses));
         $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnPortalUpdate AS t WHERE t.target_class IN ({$sClassList})"));
         while ($oTrigger = $oSet->Fetch()) {
             $oTrigger->DoActivate($oObj->ToArgs('this'));
         }
         $this->p("<h1>" . Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName()) . "</h1>\n");
     }
     $bLockEnabled = MetaModel::GetConfig()->Get('concurrent_lock_enabled');
     if ($bLockEnabled) {
         // Release the concurrent lock, if any
         $sOwnershipToken = utils::ReadPostedParam('ownership_token', null, false, 'raw_data');
         if ($sOwnershipToken !== null) {
             // We're done, let's release the lock
             iTopOwnershipLock::ReleaseLock(get_class($oObj), $oObj->GetKey(), $sOwnershipToken);
         }
     }
 }
    public function DisplayStimulusForm(WebPage $oPage, $sStimulus)
    {
        $sClass = get_class($this);
        $iKey = $this->GetKey();
        $aTransitions = $this->EnumTransitions();
        $aStimuli = MetaModel::EnumStimuli($sClass);
        if (!isset($aTransitions[$sStimulus])) {
            // Invalid stimulus
            throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $this->GetName(), $this->GetStateLabel()));
        }
        // Check for concurrent access lock
        $LockEnabled = MetaModel::GetConfig()->Get('concurrent_lock_enabled');
        $sOwnershipToken = null;
        if ($LockEnabled) {
            $sOwnershipToken = utils::ReadPostedParam('ownership_token', null, false, 'raw_data');
            $aLockInfo = iTopOwnershipLock::AcquireLock($sClass, $iKey);
            if ($aLockInfo['success']) {
                $sOwnershipToken = $aLockInfo['token'];
                $sOwnershipDate = $aLockInfo['acquired'];
            } else {
                $oOwner = $aLockInfo['lock']->GetOwner();
                // If the object is locked by the current user, it's worth trying again, since
                // the lock may be released by 'onunload' which is called AFTER loading the current page.
                //$bTryAgain = $oOwner->GetKey() == UserRights::GetUserId();
                self::ReloadAndDisplay($oPage, $this, array('operation' => 'stimulus', 'stimulus' => $sStimulus));
                return;
            }
        }
        $sActionLabel = $aStimuli[$sStimulus]->GetLabel();
        $sActionDetails = $aStimuli[$sStimulus]->GetDescription();
        $aTransition = $aTransitions[$sStimulus];
        $sTargetState = $aTransition['target_state'];
        $aTargetStates = MetaModel::EnumStates($sClass);
        $oPage->add("<div class=\"page_header\">\n");
        $oPage->add("<h1>{$sActionLabel} - <span class=\"hilite\">{$this->GetName()}</span></h1>\n");
        $oPage->set_title($sActionLabel);
        $oPage->add("</div>\n");
        $aTargetState = $aTargetStates[$sTargetState];
        $aExpectedAttributes = $aTargetState['attribute_list'];
        $oPage->add("<h1>{$sActionDetails}</h1>\n");
        $sButtonsPosition = MetaModel::GetConfig()->Get('buttons_position');
        if ($sButtonsPosition == 'bottom') {
            // bottom: Displays the ticket details BEFORE the actions
            $oPage->add('<div class="ui-widget-content">');
            $this->DisplayBareProperties($oPage);
            $oPage->add('</div>');
        }
        $oPage->add("<div class=\"wizContainer\">\n");
        $oPage->add("<form id=\"apply_stimulus\" method=\"post\" onSubmit=\"return OnSubmit('apply_stimulus');\">\n");
        $aDetails = array();
        $iFieldIndex = 0;
        $aFieldsMap = array();
        // The list of candidate fields is made of the ordered list of "details" attributes + other attributes
        $aAttributes = array();
        foreach ($this->FlattenZList(MetaModel::GetZListItems($sClass, 'details')) as $sAttCode) {
            $aAttributes[$sAttCode] = true;
        }
        foreach (MetaModel::GetAttributesList($sClass) as $sAttCode) {
            if (!array_key_exists($sAttCode, $aAttributes)) {
                $aAttributes[$sAttCode] = true;
            }
        }
        // Order the fields based on their dependencies, set the fields for which there is only one possible value
        // and perform this in the order of dependencies to avoid dead-ends
        $aDeps = array();
        foreach ($aAttributes as $sAttCode => $trash) {
            $aDeps[$sAttCode] = MetaModel::GetPrerequisiteAttributes($sClass, $sAttCode);
        }
        $aList = $this->OrderDependentFields($aDeps);
        foreach ($aList as $sAttCode) {
            // Consider only the "expected" fields for the target state
            if (array_key_exists($sAttCode, $aExpectedAttributes)) {
                $iExpectCode = $aExpectedAttributes[$sAttCode];
                // Prompt for an attribute if
                // - the attribute must be changed or must be displayed to the user for confirmation
                // - or the field is mandatory and currently empty
                if ($iExpectCode & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT) || $iExpectCode & OPT_ATT_MANDATORY && $this->Get($sAttCode) == '') {
                    $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
                    $aArgs = array('this' => $this);
                    // If the field is mandatory, set it to the only possible value
                    if (!$oAttDef->IsNullAllowed() || $iExpectCode & OPT_ATT_MANDATORY) {
                        if ($oAttDef->IsExternalKey()) {
                            $oAllowedValues = MetaModel::GetAllowedValuesAsObjectSet($sClass, $sAttCode, $aArgs);
                            if ($oAllowedValues->Count() == 1) {
                                $oRemoteObj = $oAllowedValues->Fetch();
                                $this->Set($sAttCode, $oRemoteObj->GetKey());
                            }
                        } else {
                            $aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, $aArgs);
                            if (count($aAllowedValues) == 1) {
                                $aValues = array_keys($aAllowedValues);
                                $this->Set($sAttCode, $aValues[0]);
                            }
                        }
                    }
                    $sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $this->Get($sAttCode), $this->GetEditValue($sAttCode), 'att_' . $iFieldIndex, '', $iExpectCode, $aArgs);
                    $aDetails[] = array('label' => '<span>' . $oAttDef->GetLabel() . '</span>', 'value' => "<span id=\"field_att_{$iFieldIndex}\">{$sHTMLValue}</span>");
                    $aFieldsMap[$sAttCode] = 'att_' . $iFieldIndex;
                    $iFieldIndex++;
                }
            }
        }
        $oPage->add('<table><tr><td>');
        $oPage->details($aDetails);
        $oPage->add('</td></tr></table>');
        $oPage->add("<input type=\"hidden\" name=\"id\" value=\"" . $this->GetKey() . "\" id=\"id\">\n");
        $aFieldsMap['id'] = 'id';
        $oPage->add("<input type=\"hidden\" name=\"class\" value=\"{$sClass}\">\n");
        $oPage->add("<input type=\"hidden\" name=\"operation\" value=\"apply_stimulus\">\n");
        $oPage->add("<input type=\"hidden\" name=\"stimulus\" value=\"{$sStimulus}\">\n");
        $iTransactionId = utils::GetNewTransactionId();
        $oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"" . $iTransactionId . "\">\n");
        if ($sOwnershipToken !== null) {
            $oPage->add("<input type=\"hidden\" name=\"ownership_token\" value=\"" . htmlentities($sOwnershipToken, ENT_QUOTES, 'UTF-8') . "\">\n");
        }
        $oAppContext = new ApplicationContext();
        $oPage->add($oAppContext->GetForForm());
        $oPage->add("<button type=\"button\" class=\"action cancel\" onClick=\"BackToDetails('{$sClass}', " . $this->GetKey() . ", '', '{$sOwnershipToken}')\"><span>" . Dict::S('UI:Button:Cancel') . "</span></button>&nbsp;&nbsp;&nbsp;&nbsp;\n");
        $oPage->add("<button type=\"submit\" class=\"action\"><span>{$sActionLabel}</span></button>\n");
        $oPage->add("</form>\n");
        $oPage->add("</div>\n");
        if ($sButtonsPosition != 'top') {
            // bottom or both: Displays the ticket details AFTER the actions
            $oPage->add('<div class="ui-widget-content">');
            $this->DisplayBareProperties($oPage);
            $oPage->add('</div>');
        }
        $iFieldsCount = count($aFieldsMap);
        $sJsonFieldsMap = json_encode($aFieldsMap);
        $oPage->add_script(<<<EOF
\t\t// Initializes the object once at the beginning of the page...
\t\tvar oWizardHelper = new WizardHelper('{$sClass}', '', '{$sTargetState}');
\t\toWizardHelper.SetFieldsMap({$sJsonFieldsMap});
\t\toWizardHelper.SetFieldsCount({$iFieldsCount});
EOF
);
        $sJSToken = json_encode($sOwnershipToken);
        $oPage->add_ready_script(<<<EOF
\t\t// Starts the validation when the page is ready
\t\tCheckFields('apply_stimulus', false);
\t\t\$(window).unload(function() { return OnUnload('{$iTransactionId}', '{$sClass}', {$iKey}, {$sJSToken}) } );
EOF
);
        if ($sOwnershipToken !== null) {
            $this->GetOwnershipJSHandler($oPage, $sOwnershipToken);
        }
    }
 /**
  * Renders the "Actions" popup menu for the given set of objects
  * 
  * Note that the menu links containing (or ending) with a hash (#) will have their fragment
  * part (whatever is after the hash) dynamically replaced (by javascript) when the menu is
  * displayed, to correspond to the current hash/fragment in the page. This allows modifying
  * an object in with the same tab active by default as the tab that was active when selecting
  * the "Modify..." action.
  */
 public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
 {
     if ($this->m_sStyle == 'popup') {
         $this->m_sStyle = 'list';
     }
     $sHtml = '';
     $oAppContext = new ApplicationContext();
     $sContext = $oAppContext->GetForLink();
     if (!empty($sContext)) {
         $sContext = '&' . $sContext;
     }
     $sClass = $this->m_oFilter->GetClass();
     $oReflectionClass = new ReflectionClass($sClass);
     $oSet = new CMDBObjectSet($this->m_oFilter);
     $sFilter = $this->m_oFilter->serialize();
     $sFilterDesc = $this->m_oFilter->ToOql(true);
     $aActions = array();
     $sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass);
     $sRootUrl = utils::GetAbsoluteUrlAppRoot();
     // 1:n links, populate the target object as a default value when creating a new linked object
     if (isset($aExtraParams['target_attr'])) {
         $aExtraParams['default'][$aExtraParams['target_attr']] = $aExtraParams['object_id'];
     }
     $sDefault = '';
     if (!empty($aExtraParams['default'])) {
         foreach ($aExtraParams['default'] as $sKey => $sValue) {
             $sDefault .= "&default[{$sKey}]={$sValue}";
         }
     }
     $bIsCreationAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_CREATE) == UR_ALLOWED_YES && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
     switch ($oSet->Count()) {
         case 0:
             // No object in the set, the only possible action is "new"
             if ($bIsCreationAllowed) {
                 $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}");
             }
             break;
         case 1:
             $oObj = $oSet->Fetch();
             $id = $oObj->GetKey();
             $bLocked = false;
             if (MetaModel::GetConfig()->Get('concurrent_lock_enabled')) {
                 $aLockInfo = iTopOwnershipLock::IsLocked(get_class($oObj), $id);
                 if ($aLockInfo['locked']) {
                     $bLocked = true;
                     //$this->AddMenuSeparator($aActions);
                     //$aActions['concurrent_lock_unlock'] = array ('label' => Dict::S('UI:Menu:ReleaseConcurrentLock'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=kill_lock&class=$sClass&id=$id{$sContext}");
                 }
             }
             $bRawModifiedAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
             $bIsModifyAllowed = !$bLocked && $bRawModifiedAllowed;
             $bIsDeleteAllowed = !$bLocked && UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet);
             // Just one object in the set, possible actions are "new / clone / modify and delete"
             if (!isset($aExtraParams['link_attr'])) {
                 if ($bIsModifyAllowed) {
                     $aActions['UI:Menu:Modify'] = array('label' => Dict::S('UI:Menu:Modify'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify&class={$sClass}&id={$id}{$sContext}#");
                 }
                 if ($bIsCreationAllowed) {
                     $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}");
                 }
                 if ($bIsDeleteAllowed) {
                     $aActions['UI:Menu:Delete'] = array('label' => Dict::S('UI:Menu:Delete'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=delete&class={$sClass}&id={$id}{$sContext}");
                 }
                 // Transitions / Stimuli
                 if (!$bLocked) {
                     $aTransitions = $oObj->EnumTransitions();
                     if (count($aTransitions)) {
                         $this->AddMenuSeparator($aActions);
                         $aStimuli = Metamodel::EnumStimuli(get_class($oObj));
                         foreach ($aTransitions as $sStimulusCode => $aTransitionDef) {
                             $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet) : UR_ALLOWED_NO;
                             switch ($iActionAllowed) {
                                 case UR_ALLOWED_YES:
                                     $aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=stimulus&stimulus={$sStimulusCode}&class={$sClass}&id={$id}{$sContext}");
                                     break;
                                 default:
                                     // Do nothing
                             }
                         }
                     }
                 }
                 // Relations...
                 $aRelations = MetaModel::EnumRelationsEx($sClass);
                 if (count($aRelations)) {
                     $this->AddMenuSeparator($aActions);
                     foreach ($aRelations as $sRelationCode => $aRelationInfo) {
                         if (array_key_exists('down', $aRelationInfo)) {
                             $aActions[$sRelationCode . '_down'] = array('label' => $aRelationInfo['down'], 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=swf_navigator&relation={$sRelationCode}&direction=down&class={$sClass}&id={$id}{$sContext}");
                         }
                         if (array_key_exists('up', $aRelationInfo)) {
                             $aActions[$sRelationCode . '_up'] = array('label' => $aRelationInfo['up'], 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=swf_navigator&relation={$sRelationCode}&direction=up&class={$sClass}&id={$id}{$sContext}");
                         }
                     }
                 }
                 if ($bLocked && $bRawModifiedAllowed) {
                     // Add a special menu to kill the lock, but only to allowed users who can also modify this object
                     $aAllowedProfiles = MetaModel::GetConfig()->Get('concurrent_lock_override_profiles');
                     $bCanKill = false;
                     $oUser = UserRights::GetUserObject();
                     $aUserProfiles = array();
                     if (!is_null($oUser)) {
                         $oProfileSet = $oUser->Get('profile_list');
                         while ($oProfile = $oProfileSet->Fetch()) {
                             $aUserProfiles[$oProfile->Get('profile')] = true;
                         }
                     }
                     foreach ($aAllowedProfiles as $sProfile) {
                         if (array_key_exists($sProfile, $aUserProfiles)) {
                             $bCanKill = true;
                             break;
                         }
                     }
                     if ($bCanKill) {
                         $this->AddMenuSeparator($aActions);
                         $aActions['concurrent_lock_unlock'] = array('label' => Dict::S('UI:Menu:KillConcurrentLock'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=kill_lock&class={$sClass}&id={$id}{$sContext}");
                     }
                 }
                 /*
                 $this->AddMenuSeparator($aActions);
                 // Static menus: Email this page & CSV Export
                 $sUrl = ApplicationContext::MakeObjectUrl($sClass, $id);
                 $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl));
                 $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
                 // The style tells us whether the menu is displayed on a list of one object, or on the details of the given object 
                 if ($this->m_sStyle == 'list')
                 {
                 	// Actions specific to the list
                 	$sOQL = addslashes($sFilterDesc);
                 	$aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
                 }
                 */
             }
             $this->AddMenuSeparator($aActions);
             foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) {
                 $oSet->Rewind();
                 foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl) {
                     $aActions[$sLabel] = array('label' => $sLabel, 'url' => $sUrl);
                 }
             }
             break;
         default:
             // Check rights
             // New / Modify
             $bIsModifyAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
             $bIsBulkModifyAllowed = !MetaModel::IsAbstract($sClass) && UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_MODIFY, $oSet) && $oReflectionClass->IsSubclassOf('cmdbAbstractObject');
             $bIsBulkDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, $oSet);
             if (isset($aExtraParams['link_attr'])) {
                 $id = $aExtraParams['object_id'];
                 $sTargetAttr = $aExtraParams['target_attr'];
                 $oAttDef = MetaModel::GetAttributeDef($sClass, $sTargetAttr);
                 $sTargetClass = $oAttDef->GetTargetClass();
                 $bIsDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet);
                 if ($bIsModifyAllowed) {
                     $aActions['UI:Menu:Add'] = array('label' => Dict::S('UI:Menu:Add'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify_links&class={$sClass}&link_attr=" . $aExtraParams['link_attr'] . "&target_class={$sTargetClass}&id={$id}&addObjects=true{$sContext}");
                 }
                 if ($bIsBulkModifyAllowed) {
                     $aActions['UI:Menu:Manage'] = array('label' => Dict::S('UI:Menu:Manage'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify_links&class={$sClass}&link_attr=" . $aExtraParams['link_attr'] . "&target_class={$sTargetClass}&id={$id}{$sContext}");
                 }
                 //if ($bIsBulkDeleteAllowed) { $aActions[] = array ('label' => 'Remove All...', 'url' => "#"); }
             } else {
                 // many objects in the set, possible actions are: new / modify all / delete all
                 if ($bIsCreationAllowed) {
                     $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}");
                 }
                 if ($bIsBulkModifyAllowed) {
                     $aActions['UI:Menu:ModifyAll'] = array('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=select_for_modify_all&class={$sClass}&filter=" . urlencode($sFilter) . "{$sContext}");
                 }
                 if ($bIsBulkDeleteAllowed) {
                     $aActions['UI:Menu:BulkDelete'] = array('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=select_for_deletion&filter=" . urlencode($sFilter) . "{$sContext}");
                 }
                 // Stimuli
                 $aStates = MetaModel::EnumStates($sClass);
                 // Do not perform time consuming computations if there are too may objects in the list
                 $iLimit = MetaModel::GetConfig()->Get('complex_actions_limit');
                 if (count($aStates) > 0 && ($iLimit == 0 || $oSet->Count() < $iLimit)) {
                     // Life cycle actions may be available... if all objects are in the same state
                     //
                     // Group by <state>
                     $oGroupByExp = new FieldExpression(MetaModel::GetStateAttributeCode($sClass), $this->m_oFilter->GetClassAlias());
                     $aGroupBy = array('__state__' => $oGroupByExp);
                     $aQueryParams = array();
                     if (isset($aExtraParams['query_params'])) {
                         $aQueryParams = $aExtraParams['query_params'];
                     }
                     $sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy);
                     $aRes = CMDBSource::QueryToArray($sSql);
                     if (count($aRes) == 1) {
                         // All objects are in the same state...
                         $sState = $aRes[0]['__state__'];
                         $aTransitions = Metamodel::EnumTransitions($sClass, $sState);
                         if (count($aTransitions)) {
                             $this->AddMenuSeparator($aActions);
                             $aStimuli = Metamodel::EnumStimuli($sClass);
                             foreach ($aTransitions as $sStimulusCode => $aTransitionDef) {
                                 $oSet->Rewind();
                                 // As soon as the user rights implementation will browse the object set,
                                 // then we might consider using OptimizeColumnLoad() here
                                 $iActionAllowed = UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet);
                                 $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? $iActionAllowed : UR_ALLOWED_NO;
                                 switch ($iActionAllowed) {
                                     case UR_ALLOWED_YES:
                                     case UR_ALLOWED_DEPENDS:
                                         $aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=select_bulk_stimulus&stimulus={$sStimulusCode}&state={$sState}&class={$sClass}&filter=" . urlencode($sFilter) . "{$sContext}");
                                         break;
                                     default:
                                         // Do nothing
                                 }
                             }
                         }
                     }
                 }
                 /*
                 $this->AddMenuSeparator($aActions);
                 $sUrl = utils::GetAbsoluteUrlAppRoot();
                 $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."{$sContext}"));
                 $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
                 $sOQL = addslashes($sFilterDesc);
                 $aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
                 */
             }
     }
     $this->AddMenuSeparator($aActions);
     foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) {
         $oSet->Rewind();
         foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $data) {
             if (is_array($data)) {
                 // New plugins can provide javascript handlers via the 'onclick' property
                 //TODO: enable extension of different menus by checking the 'target' property ??
                 $aActions[$sLabel] = array('label' => $sLabel, 'url' => isset($data['url']) ? $data['url'] : '#', 'onclick' => isset($data['onclick']) ? $data['onclick'] : '');
             } else {
                 // Backward compatibility with old plugins
                 $aActions[$sLabel] = array('label' => $sLabel, 'url' => $data);
             }
         }
     }
     // New extensions based on iPopupMenuItem interface
     switch ($this->m_sStyle) {
         case 'list':
             $oSet->Rewind();
             $param = $oSet;
             $iMenuId = iPopupMenuExtension::MENU_OBJLIST_ACTIONS;
             break;
         case 'details':
             $oSet->Rewind();
             $param = $oSet->Fetch();
             $iMenuId = iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS;
             break;
     }
     utils::GetPopupMenuItems($oPage, $iMenuId, $param, $aActions);
     $aFavoriteActions = array();
     $aCallSpec = array($sClass, 'GetShortcutActions');
     if (is_callable($aCallSpec)) {
         $aShortcutActions = call_user_func($aCallSpec, $sClass);
         foreach ($aActions as $key => $aAction) {
             if (in_array($key, $aShortcutActions)) {
                 $aFavoriteActions[] = $aAction;
                 unset($aActions[$key]);
             }
         }
     } else {
         $aShortcutActions = array();
     }
     if (count($aFavoriteActions) > 0) {
         $sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>" . Dict::S('UI:Menu:OtherActions') . "\n<ul>\n";
     } else {
         $sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>" . Dict::S('UI:Menu:Actions') . "\n<ul>\n";
     }
     $sHtml .= $oPage->RenderPopupMenuItems($aActions, $aFavoriteActions);
     static $bPopupScript = false;
     if (!$bPopupScript) {
         // Output this once per page...
         $oPage->add_ready_script("\$(\"div.itop_popup>ul\").popupmenu();\n");
         $bPopupScript = true;
     }
     return $sHtml;
 }
示例#4
0
 case 'export_cancel':
     $token = utils::ReadParam('token', null);
     if ($token !== null) {
         $oExporter = BulkExport::FindExporterFromToken($token);
         if ($oExporter) {
             $oExporter->Cleanup();
         }
     }
     $aResult = array('code' => 'error', 'percentage' => 100, 'message' => Dict::S('Core:BulkExport:ExportCancelledByUser'));
     $oPage->add(json_encode($aResult));
     break;
 case 'extend_lock':
     $sObjClass = utils::ReadParam('obj_class', '', false, 'class');
     $iObjKey = (int) utils::ReadParam('obj_key', 0, false, 'integer');
     $sToken = utils::ReadParam('token', 0, false, 'raw_data');
     $aResult = iTopOwnershipLock::ExtendLock($sObjClass, $iObjKey, $sToken);
     if (!$aResult['status']) {
         if ($aResult['operation'] == 'lost') {
             $sName = $aResult['owner']->GetName();
             if ($aResult['owner']->Get('contactid') != 0) {
                 $sName .= ' (' . $aResult['owner']->Get('contactid_friendlyname') . ')';
             }
             $aResult['message'] = Dict::Format('UI:CurrentObjectIsLockedBy_User', $sName);
             $aResult['popup_message'] = Dict::Format('UI:CurrentObjectIsLockedBy_User_Explanation', $sName);
         } else {
             if ($aResult['operation'] == 'expired') {
                 $aResult['message'] = Dict::S('UI:CurrentObjectLockExpired');
                 $aResult['popup_message'] = Dict::S('UI:CurrentObjectLockExpired_Explanation');
             }
         }
     }
示例#5
0
文件: UI.php 项目: henryavila/itop
         $oDisplayGraph->Display($oP, $aResults, $sRelation, $oAppContext, array(), $sClassForAttachment, $iIdForAttachment, $sContextKey, array('this' => $oObj));
         DisplayNavigatorGroupTab($oP, $aGroups, $sRelation, $oObj);
     } else {
         $oP->SetCurrentTab(Dict::S('UI:RelationshipGraph'));
         $oDisplayGraph->Display($oP, $aResults, $sRelation, $oAppContext, array(), $sClassForAttachment, $iIdForAttachment, $sContextKey, array('this' => $oObj));
         DisplayNavigatorListTab($oP, $aResults, $sRelation, $oObj);
         DisplayNavigatorGroupTab($oP, $aGroups, $sRelation, $oObj);
     }
     $oP->SetCurrentTab('');
     break;
     ///////////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////
 case 'kill_lock':
     $sClass = utils::ReadParam('class', '');
     $id = utils::ReadParam('id', '');
     iTopOwnershipLock::KillLock($sClass, $id);
     $oObj = MetaModel::GetObject($sClass, $id);
     ReloadAndDisplay($oP, $oObj, 'concurrent_lock_killed', Dict::S('UI:ConcurrentLockKilled'), 'info');
     break;
     ///////////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////
 case 'cancel':
     // An action was cancelled
     $oP->set_title(Dict::S('UI:OperationCancelled'));
     $oP->add('<h1>' . Dict::S('UI:OperationCancelled') . '</h1>');
     break;
     ///////////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////
 default:
     // Menu node rendering (templates)
     ApplicationMenu::LoadAdditionalMenus();
 /**
  * Checks if an exclusive lock exists on the specified DBObject.
  * @param string $sObjClass The class of the object for which to acquire the lock
  * @param integer $iObjKey The identifier of the object for which to acquire the lock
  * @return multitype:boolean iTopOwnershipLock Ambigous <boolean, string, DBObjectSet>
  */
 public static function IsLocked($sObjClass, $iObjKey)
 {
     $bLocked = false;
     $oMutex = new iTopMutex('lock_' . $sObjClass . '::' . $iObjKey);
     $oMutex->Lock();
     $oOwnershipLock = new iTopOwnershipLock($sObjClass, $iObjKey);
     if ($oOwnershipLock->IsOwned()) {
         $bLocked = true;
     }
     $oMutex->Unlock();
     return array('locked' => $bLocked, 'owner' => $oOwnershipLock->GetOwner());
 }