protected function DisplayEditInPlace(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
 {
     $aAttribs = $this->GetTableConfig();
     $oValue->Rewind();
     $oPage->add('<table class="listContainer" id="' . $this->sInputid . '"><tr><td>');
     $aData = array();
     while ($oLinkObj = $oValue->Fetch()) {
         $aRow = array();
         $aRow['form::select'] = '<input type="checkbox" class="selectList' . $this->sInputid . '" value="' . $oLinkObj->GetKey() . '"/>';
         foreach ($this->aZlist as $sLinkedAttCode) {
             $aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
         }
         $aData[] = $aRow;
     }
     $oPage->table($aAttribs, $aData);
     $oPage->add('</td></tr></table>');
     //listcontainer
     $sInputName = $sFormPrefix . 'attr_' . $this->sAttCode;
     $aLabels = array('delete' => Dict::S('UI:Button:Delete'), 'creation_title' => Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sLinkedClass)), 'create' => Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($this->sLinkedClass)), 'remove' => Dict::S('UI:Button:Remove'), 'add' => Dict::Format('UI:AddAnExisting_Class', MetaModel::GetName($this->sLinkedClass)), 'selection_title' => Dict::Format('UI:SelectionOf_Class', MetaModel::GetName($this->sLinkedClass)));
     $oContext = new ApplicationContext();
     $sSubmitUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?' . $oContext->GetForLink();
     $sJSONLabels = json_encode($aLabels);
     $sJSONButtons = json_encode($aButtons);
     $sWizHelper = 'oWizardHelper' . $sFormPrefix;
     $oPage->add_ready_script("\$('#{$this->sInputid}').directlinks({class_name: '{$this->sClass}', att_code: '{$this->sAttCode}', input_name:'{$sInputName}', labels: {$sJSONLabels}, submit_to: '{$sSubmitUrl}', buttons: {$sJSONButtons}, oWizardHelper: {$sWizHelper} });");
 }
 /**
  * Perform all the needed checks to delete one (or more) objects
  */
 public static function DeleteObjects(WebPage $oP, $sClass, $aObjects, $bPreview, $sCustomOperation, $aContextData = array())
 {
     $oDeletionPlan = new DeletionPlan();
     foreach ($aObjects as $oObj) {
         if ($bPreview) {
             $oObj->CheckToDelete($oDeletionPlan);
         } else {
             $oObj->DBDeleteTracked(CMDBObject::GetCurrentChange(), null, $oDeletionPlan);
         }
     }
     if ($bPreview) {
         if (count($aObjects) == 1) {
             $oObj = $aObjects[0];
             $oP->add("<h1>" . Dict::Format('UI:Delete:ConfirmDeletionOf_Name', $oObj->GetName()) . "</h1>\n");
         } else {
             $oP->add("<h1>" . Dict::Format('UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass)) . "</h1>\n");
         }
         // Explain what should be done
         //
         $aDisplayData = array();
         foreach ($oDeletionPlan->ListDeletes() as $sTargetClass => $aDeletes) {
             foreach ($aDeletes as $iId => $aData) {
                 $oToDelete = $aData['to_delete'];
                 $bAutoDel = $aData['mode'] == DEL_SILENT || $aData['mode'] == DEL_AUTO;
                 if (array_key_exists('issue', $aData)) {
                     if ($bAutoDel) {
                         if (isset($aData['requested_explicitely'])) {
                             $sConsequence = Dict::Format('UI:Delete:CannotDeleteBecause', $aData['issue']);
                         } else {
                             $sConsequence = Dict::Format('UI:Delete:ShouldBeDeletedAtomaticallyButNotPossible', $aData['issue']);
                         }
                     } else {
                         $sConsequence = Dict::Format('UI:Delete:MustBeDeletedManuallyButNotPossible', $aData['issue']);
                     }
                 } else {
                     if ($bAutoDel) {
                         if (isset($aData['requested_explicitely'])) {
                             $sConsequence = '';
                             // not applicable
                         } else {
                             $sConsequence = Dict::S('UI:Delete:WillBeDeletedAutomatically');
                         }
                     } else {
                         $sConsequence = Dict::S('UI:Delete:MustBeDeletedManually');
                     }
                 }
                 $aDisplayData[] = array('class' => MetaModel::GetName(get_class($oToDelete)), 'object' => $oToDelete->GetHyperLink(), 'consequence' => $sConsequence);
             }
         }
         foreach ($oDeletionPlan->ListUpdates() as $sRemoteClass => $aToUpdate) {
             foreach ($aToUpdate as $iId => $aData) {
                 $oToUpdate = $aData['to_reset'];
                 if (array_key_exists('issue', $aData)) {
                     $sConsequence = Dict::Format('UI:Delete:CannotUpdateBecause_Issue', $aData['issue']);
                 } else {
                     $sConsequence = Dict::Format('UI:Delete:WillAutomaticallyUpdate_Fields', $aData['attributes_list']);
                 }
                 $aDisplayData[] = array('class' => MetaModel::GetName(get_class($oToUpdate)), 'object' => $oToUpdate->GetHyperLink(), 'consequence' => $sConsequence);
             }
         }
         $iImpactedIndirectly = $oDeletionPlan->GetTargetCount() - count($aObjects);
         if ($iImpactedIndirectly > 0) {
             if (count($aObjects) == 1) {
                 $oObj = $aObjects[0];
                 $oP->p(Dict::Format('UI:Delete:Count_Objects/LinksReferencing_Object', $iImpactedIndirectly, $oObj->GetName()));
             } else {
                 $oP->p(Dict::Format('UI:Delete:Count_Objects/LinksReferencingTheObjects', $iImpactedIndirectly));
             }
             $oP->p(Dict::S('UI:Delete:ReferencesMustBeDeletedToEnsureIntegrity'));
         }
         if ($iImpactedIndirectly > 0 || $oDeletionPlan->FoundStopper()) {
             $aDisplayConfig = array();
             $aDisplayConfig['class'] = array('label' => 'Class', 'description' => '');
             $aDisplayConfig['object'] = array('label' => 'Object', 'description' => '');
             $aDisplayConfig['consequence'] = array('label' => 'Consequence', 'description' => Dict::S('UI:Delete:Consequence+'));
             $oP->table($aDisplayConfig, $aDisplayData);
         }
         if ($oDeletionPlan->FoundStopper()) {
             if ($oDeletionPlan->FoundSecurityIssue()) {
                 $oP->p(Dict::S('UI:Delete:SorryDeletionNotAllowed'));
             } elseif ($oDeletionPlan->FoundManualOperation()) {
                 $oP->p(Dict::S('UI:Delete:PleaseDoTheManualOperations'));
             } else {
                 $oP->p(Dict::S('UI:Delete:PleaseDoTheManualOperations'));
             }
             $oAppContext = new ApplicationContext();
             $oP->add("<form method=\"post\">\n");
             $oP->add("<input type=\"hidden\" name=\"transaction_id\" value=\"" . utils::ReadParam('transaction_id') . "\">\n");
             $oP->add("<input type=\"button\" onclick=\"window.history.back();\" value=\"" . Dict::S('UI:Button:Back') . "\">\n");
             $oP->add("<input DISABLED type=\"submit\" name=\"\" value=\"" . Dict::S('UI:Button:Delete') . "\">\n");
             $oP->add($oAppContext->GetForForm());
             $oP->add("</form>\n");
         } else {
             if (count($aObjects) == 1) {
                 $oObj = $aObjects[0];
                 $id = $oObj->GetKey();
                 $oP->p('<h1>' . Dict::Format('UI:Delect:Confirm_Object', $oObj->GetHyperLink()) . '</h1>');
             } else {
                 $oP->p('<h1>' . Dict::Format('UI:Delect:Confirm_Count_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass)) . '</h1>');
             }
             foreach ($aObjects as $oObj) {
                 $aKeys[] = $oObj->GetKey();
             }
             $oFilter = new DBObjectSearch($sClass);
             $oFilter->AddCondition('id', $aKeys, 'IN');
             $oSet = new CMDBobjectSet($oFilter);
             $oP->add('<div id="0">');
             CMDBAbstractObject::DisplaySet($oP, $oSet, array('display_limit' => false, 'menu' => false));
             $oP->add("</div>\n");
             $oP->add("<form method=\"post\">\n");
             foreach ($aContextData as $sKey => $value) {
                 $oP->add("<input type=\"hidden\" name=\"{$sKey}\" value=\"{$value}\">\n");
             }
             $oP->add("<input type=\"hidden\" name=\"transaction_id\" value=\"" . utils::GetNewTransactionId() . "\">\n");
             $oP->add("<input type=\"hidden\" name=\"operation\" value=\"{$sCustomOperation}\">\n");
             $oP->add("<input type=\"hidden\" name=\"filter\" value=\"" . $oFilter->Serialize() . "\">\n");
             $oP->add("<input type=\"hidden\" name=\"class\" value=\"{$sClass}\">\n");
             foreach ($aObjects as $oObj) {
                 $oP->add("<input type=\"hidden\" name=\"selectObject[]\" value=\"" . $oObj->GetKey() . "\">\n");
             }
             $oP->add("<input type=\"button\" onclick=\"window.history.back();\" value=\"" . Dict::S('UI:Button:Back') . "\">\n");
             $oP->add("<input type=\"submit\" name=\"\" value=\"" . Dict::S('UI:Button:Delete') . "\">\n");
             $oAppContext = new ApplicationContext();
             $oP->add($oAppContext->GetForForm());
             $oP->add("</form>\n");
         }
     } else {
         // Execute the deletion
         //
         if (count($aObjects) == 1) {
             $oObj = $aObjects[0];
             $oP->add("<h1>" . Dict::Format('UI:Title:DeletionOf_Object', $oObj->GetName()) . "</h1>\n");
         } else {
             $oP->add("<h1>" . Dict::Format('UI:Title:BulkDeletionOf_Count_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass)) . "</h1>\n");
         }
         // Security - do not allow the user to force a forbidden delete by the mean of page arguments...
         if ($oDeletionPlan->FoundSecurityIssue()) {
             throw new CoreException(Dict::S('UI:Error:NotEnoughRightsToDelete'));
         }
         if ($oDeletionPlan->FoundManualOperation()) {
             throw new CoreException(Dict::S('UI:Error:CannotDeleteBecauseManualOpNeeded'));
         }
         if ($oDeletionPlan->FoundManualDelete()) {
             throw new CoreException(Dict::S('UI:Error:CannotDeleteBecauseOfDepencies'));
         }
         // Report deletions
         //
         $aDisplayData = array();
         foreach ($oDeletionPlan->ListDeletes() as $sTargetClass => $aDeletes) {
             foreach ($aDeletes as $iId => $aData) {
                 $oToDelete = $aData['to_delete'];
                 if (isset($aData['requested_explicitely'])) {
                     $sMessage = Dict::S('UI:Delete:Deleted');
                 } else {
                     $sMessage = Dict::S('UI:Delete:AutomaticallyDeleted');
                 }
                 $aDisplayData[] = array('class' => MetaModel::GetName(get_class($oToDelete)), 'object' => $oToDelete->GetName(), 'consequence' => $sMessage);
             }
         }
         // Report updates
         //
         foreach ($oDeletionPlan->ListUpdates() as $sTargetClass => $aToUpdate) {
             foreach ($aToUpdate as $iId => $aData) {
                 $oToUpdate = $aData['to_reset'];
                 $aDisplayData[] = array('class' => MetaModel::GetName(get_class($oToUpdate)), 'object' => $oToUpdate->GetHyperLink(), 'consequence' => Dict::Format('UI:Delete:AutomaticResetOf_Fields', $aData['attributes_list']));
             }
         }
         // Report automatic jobs
         //
         if ($oDeletionPlan->GetTargetCount() > 0) {
             if (count($aObjects) == 1) {
                 $oObj = $aObjects[0];
                 $oP->p(Dict::Format('UI:Delete:CleaningUpRefencesTo_Object', $oObj->GetName()));
             } else {
                 $oP->p(Dict::Format('UI:Delete:CleaningUpRefencesTo_Several_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass)));
             }
             $aDisplayConfig = array();
             $aDisplayConfig['class'] = array('label' => 'Class', 'description' => '');
             $aDisplayConfig['object'] = array('label' => 'Object', 'description' => '');
             $aDisplayConfig['consequence'] = array('label' => 'Done', 'description' => Dict::S('UI:Delete:Done+'));
             $oP->table($aDisplayConfig, $aDisplayData);
         }
     }
 }
    /**
     * Display the history of bulk imports
     */
    static function DisplayImportHistory(WebPage $oPage, $bFromAjax = false, $bShowAll = false)
    {
        $sAjaxDivId = "CSVImportHistory";
        if (!$bFromAjax) {
            $oPage->add('<div id="' . $sAjaxDivId . '">');
        }
        $oPage->p(Dict::S('UI:History:BulkImports+') . ' <span id="csv_history_reload"></span>');
        $oBulkChangeSearch = DBObjectSearch::FromOQL("SELECT CMDBChange WHERE origin IN ('csv-interactive', 'csv-import.php')");
        $iQueryLimit = $bShowAll ? 0 : appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
        $oBulkChanges = new DBObjectSet($oBulkChangeSearch, array('date' => false), array(), null, $iQueryLimit);
        $oAppContext = new ApplicationContext();
        $bLimitExceeded = false;
        if ($oBulkChanges->Count() > appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit())) {
            $bLimitExceeded = true;
            if (!$bShowAll) {
                $iMaxObjects = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
                $oBulkChanges->SetLimit($iMaxObjects);
            }
        }
        $oBulkChanges->Seek(0);
        $aDetails = array();
        while ($oChange = $oBulkChanges->Fetch()) {
            $sDate = '<a href="csvimport.php?step=10&changeid=' . $oChange->GetKey() . '&' . $oAppContext->GetForLink() . '">' . $oChange->Get('date') . '</a>';
            $sUser = $oChange->GetUserName();
            if (preg_match('/^(.*)\\(CSV\\)$/i', $oChange->Get('userinfo'), $aMatches)) {
                $sUser = $aMatches[1];
            } else {
                $sUser = $oChange->Get('userinfo');
            }
            $oOpSearch = DBObjectSearch::FromOQL("SELECT CMDBChangeOpCreate WHERE change = :change_id");
            $oOpSet = new DBObjectSet($oOpSearch, array(), array('change_id' => $oChange->GetKey()));
            $iCreated = $oOpSet->Count();
            // Get the class from the first item found (assumption: a CSV load is done for a single class)
            if ($oCreateOp = $oOpSet->Fetch()) {
                $sClass = $oCreateOp->Get('objclass');
            }
            $oOpSearch = DBObjectSearch::FromOQL("SELECT CMDBChangeOpSetAttribute WHERE change = :change_id");
            $oOpSet = new DBObjectSet($oOpSearch, array(), array('change_id' => $oChange->GetKey()));
            $aModified = array();
            $aAttList = array();
            while ($oModified = $oOpSet->Fetch()) {
                // Get the class (if not done earlier on object creation)
                $sClass = $oModified->Get('objclass');
                $iKey = $oModified->Get('objkey');
                $sAttCode = $oModified->Get('attcode');
                $aAttList[$sClass][$sAttCode] = true;
                $aModified["{$sClass}::{$iKey}"] = true;
            }
            $iModified = count($aModified);
            // Assumption: there is only one class of objects being loaded
            // Then the last class found gives us the class for every object
            if ($iModified > 0 || $iCreated > 0) {
                $aDetails[] = array('date' => $sDate, 'user' => $sUser, 'class' => $sClass, 'created' => $iCreated, 'modified' => $iModified);
            }
        }
        $aConfig = array('date' => array('label' => Dict::S('UI:History:Date'), 'description' => Dict::S('UI:History:Date+')), 'user' => array('label' => Dict::S('UI:History:User'), 'description' => Dict::S('UI:History:User+')), 'class' => array('label' => Dict::S('Core:AttributeClass'), 'description' => Dict::S('Core:AttributeClass+')), 'created' => array('label' => Dict::S('UI:History:StatsCreations'), 'description' => Dict::S('UI:History:StatsCreations+')), 'modified' => array('label' => Dict::S('UI:History:StatsModifs'), 'description' => Dict::S('UI:History:StatsModifs+')));
        if ($bLimitExceeded) {
            if ($bShowAll) {
                // Collapsible list
                $oPage->add('<p>' . Dict::Format('UI:CountOfResults', $oBulkChanges->Count()) . '&nbsp;&nbsp;<a class="truncated" onclick="OnTruncatedHistoryToggle(false);">' . Dict::S('UI:CollapseList') . '</a></p>');
            } else {
                // Truncated list
                $iMinDisplayLimit = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
                $sCollapsedLabel = Dict::Format('UI:TruncatedResults', $iMinDisplayLimit, $oBulkChanges->Count());
                $sLinkLabel = Dict::S('UI:DisplayAll');
                $oPage->add('<p>' . $sCollapsedLabel . '&nbsp;&nbsp;<a class="truncated" onclick="OnTruncatedHistoryToggle(true);">' . $sLinkLabel . '</p>');
                $oPage->add_ready_script(<<<EOF
\t\$('#{$sAjaxDivId} table.listResults').addClass('truncated');
\t\$('#{$sAjaxDivId} table.listResults tr:last td').addClass('truncated');
EOF
);
                $sAppContext = $oAppContext->GetForLink();
                $oPage->add_script(<<<EOF
\tfunction OnTruncatedHistoryToggle(bShowAll)
\t{
\t\t\$('#csv_history_reload').html('<img src="../images/indicator.gif"/>');
\t\t\$.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
\t\t\t{
\t\t\t\t\$('#{$sAjaxDivId}').html(data);
\t\t\t\tvar table = \$('#{$sAjaxDivId} .listResults');
\t\t\t\ttable.tableHover(); // hover tables
\t\t\t\ttable.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
\t\t\t}
\t\t);
\t}
EOF
);
            }
        } else {
            // Normal display - full list without any decoration
        }
        $oPage->table($aConfig, $aDetails);
        if (!$bFromAjax) {
            $oPage->add('</div>');
        }
    }