diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php
index f0284c815..fb0edca6b 100644
--- a/application/cmdbabstract.class.inc.php
+++ b/application/cmdbabstract.class.inc.php
@@ -1172,6 +1172,146 @@ EOF
return $sHtml;
}
+ static function DisplaySetAsHTMLSpreadsheet(WebPage $oPage, CMDBObjectSet $oSet, $aParams = array())
+ {
+ $oPage->add(self::GetSetAsHTMLSpreadsheet($oSet, $aParams));
+ }
+
+ static function GetSetAsHTMLSpreadsheet(DBObjectSet $oSet, $aParams = array())
+ {
+ $aFields = null;
+ if (isset($aParams['fields']) && (strlen($aParams['fields']) > 0))
+ {
+ $aFields = explode(',', $aParams['fields']);
+ }
+
+ $aList = array();
+
+ $oAppContext = new ApplicationContext();
+ $aClasses = $oSet->GetFilter()->GetSelectedClasses();
+ $aAuthorizedClasses = array();
+ foreach($aClasses as $sAlias => $sClassName)
+ {
+ if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS))
+ {
+ $aAuthorizedClasses[$sAlias] = $sClassName;
+ }
+ }
+ $aAttribs = array();
+ $aHeader = array();
+ foreach($aAuthorizedClasses as $sAlias => $sClassName)
+ {
+ foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef)
+ {
+ if (is_null($aFields) || (count($aFields) == 0))
+ {
+ // Standard list of attributes (no link sets)
+ if ($oAttDef->IsScalar() && ($oAttDef->IsWritable() || $oAttDef->IsExternalField()))
+ {
+ $aList[$sClassName][$sAttCode] = $oAttDef;
+ }
+ }
+ else
+ {
+ // User defined list of attributes
+ if (in_array($sAttCode, $aFields))
+ {
+ $aList[$sClassName][$sAttCode] = $oAttDef;
+ }
+ }
+ }
+ $aHeader[] = 'id';
+ foreach($aList[$sClassName] as $sAttCode => $oAttDef)
+ {
+ $sStar = '';
+ if ($oAttDef->IsExternalField())
+ {
+ $sExtKeyLabel = MetaModel::GetLabel($sClassName, $oAttDef->GetKeyAttCode());
+ $oExtKeyAttDef = MetaModel::GetAttributeDef($sClassName, $oAttDef->GetKeyAttCode());
+ if (!$oExtKeyAttDef->IsNullAllowed() && isset($aParams['showMandatoryFields']))
+ {
+ $sStar = '*';
+ }
+ $sRemoteAttLabel = MetaModel::GetLabel($oAttDef->GetTargetClass(), $oAttDef->GetExtAttCode());
+ $oTargetAttDef = MetaModel::GetAttributeDef($oAttDef->GetTargetClass(), $oAttDef->GetExtAttCode());
+ $sSuffix = '';
+ if ($oTargetAttDef->IsExternalKey())
+ {
+ $sSuffix = '->id';
+ }
+ $sColLabel = $sExtKeyLabel.'->'.$sRemoteAttLabel.$sSuffix.$sStar;
+ }
+ else
+ {
+ if (!$oAttDef->IsNullAllowed() && isset($aParams['showMandatoryFields']))
+ {
+ $sStar = '*';
+ }
+ $sColLabel = MetaModel::GetLabel($sClassName, $sAttCode).$sStar;
+ }
+ $oFinalAttDef = $oAttDef->GetFinalAttDef();
+ if (get_class($oFinalAttDef) == 'AttributeDateTime')
+ {
+ $aHeader[] = $sColLabel.' ('.Dict::S('UI:SplitDateTime-Date').')';
+ $aHeader[] = $sColLabel.' ('.Dict::S('UI:SplitDateTime-Time').')';
+ }
+ else
+ {
+ $aHeader[] = $sColLabel;
+ }
+ }
+ }
+
+
+ $sHtml = "
\n";
+ $sHtml .= "\n";
+ $sHtml .= "| ".implode(" | ", $aHeader)." | \n";
+ $sHtml .= "
\n";
+ $oSet->Seek(0);
+ while ($aObjects = $oSet->FetchAssoc())
+ {
+ $aRow = array();
+ foreach($aAuthorizedClasses as $sAlias => $sClassName)
+ {
+ $oObj = $aObjects[$sAlias];
+ if (is_null($oObj))
+ {
+ $aRow[] = '';
+ }
+ else
+ {
+ $aRow[] = ''.$oObj->GetKey().' | ';
+ }
+ foreach($aList[$sClassName] as $sAttCode => $oAttDef)
+ {
+ if (is_null($oObj))
+ {
+ $aRow[] = '';
+ }
+ else
+ {
+ $oFinalAttDef = $oAttDef->GetFinalAttDef();
+ if (get_class($oFinalAttDef) == 'AttributeDateTime')
+ {
+ $iDate = AttributeDateTime::GetAsUnixSeconds($oObj->Get($sAttCode));
+ $aRow[] = ''.date('Y-m-d', $iDate).' | ';
+ $aRow[] = ''.date('h:i:s', $iDate).' | ';
+ }
+ else
+ {
+ $aRow[] = ''.(string) $oObj->Get($sAttCode).' | ';
+ }
+ }
+ }
+ }
+ $sHtml .= implode("\n", $aRow);
+ $sHtml .= "\n";
+ }
+ $sHtml .= "
\n";
+
+ return $sHtml;
+ }
+
static function DisplaySetAsXML(WebPage $oPage, CMDBObjectSet $oSet, $aParams = array())
{
$oAppContext = new ApplicationContext();
diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php
index 01ccd0681..8ab182eee 100644
--- a/core/attributedef.class.inc.php
+++ b/core/attributedef.class.inc.php
@@ -162,6 +162,10 @@ abstract class AttributeDefinition
return "";
// e.g: return array("Site", "infrid", "name");
}
+ public function GetFinalAttDef()
+ {
+ return $this;
+ }
public function IsDirectField() {return false;}
public function IsScalar() {return false;}
public function IsLinkSet() {return false;}
@@ -2761,6 +2765,13 @@ class AttributeExternalField extends AttributeDefinition
}
public function GetEditClass() {return "ExtField";}
+
+ public function GetFinalAttDef()
+ {
+ $oExtAttDef = $this->GetExtAttDef();
+ return $oExtAttDef->GetFinalAttDef();
+ }
+
protected function GetSQLCol()
{
// throw new CoreException("external attribute: does it make any sense to request its type ?");
diff --git a/dictionaries/dictionary.itop.ui.php b/dictionaries/dictionary.itop.ui.php
index e060859b9..d22890747 100644
--- a/dictionaries/dictionary.itop.ui.php
+++ b/dictionaries/dictionary.itop.ui.php
@@ -429,6 +429,8 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:UndefinedObject' => 'undefined',
'UI:Document:OpenInNewWindow:Download' => 'Open in new window: %1$s, Download: %2$s',
'UI:SelectAllToggle+' => 'Select / Deselect All',
+ 'UI:SplitDateTime-Date' => 'date',
+ 'UI:SplitDateTime-Time' => 'time',
'UI:TruncatedResults' => '%1$d objects displayed out of %2$d',
'UI:DisplayAll' => 'Display All',
'UI:CollapseList' => 'Collapse',
diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php
index d7792f271..3d5ca2e36 100644
--- a/dictionaries/fr.dictionary.itop.ui.php
+++ b/dictionaries/fr.dictionary.itop.ui.php
@@ -316,6 +316,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:Document:OpenInNewWindow:Download' => 'Ouvrir dans un nouvelle fenêtre: %1$s, Télécharger: %2$s',
'UI:SelectAllToggle+' => 'Tout sélectionner / Tout déselectionner',
'UI:TruncatedResults' => '%1$d objets affichés sur %2$d',
+ 'UI:SplitDateTime-Date' => 'date',
+ 'UI:SplitDateTime-Time' => 'heure',
'UI:DisplayAll' => 'Tout afficher',
'UI:CollapseList' => 'Refermer',
'UI:CountOfResults' => '%1$d objet(s)',
diff --git a/pages/UI.php b/pages/UI.php
index ba277b33b..af0281cdb 100644
--- a/pages/UI.php
+++ b/pages/UI.php
@@ -2109,7 +2109,7 @@ EOF
DisplayWelcomePopup($oP);
$oP->output();
}
-catch(CoreException $e)
+catch(xxxCoreException $e)
{
require_once(APPROOT.'/setup/setuppage.class.inc.php');
$oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError'));
@@ -2152,7 +2152,7 @@ catch(CoreException $e)
// For debugging only
//throw $e;
}
-catch(Exception $e)
+catch(xxxException $e)
{
require_once(APPROOT.'/setup/setuppage.class.inc.php');
$oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError'));
diff --git a/webservices/export.php b/webservices/export.php
index ab138a1c8..b9c59e6b6 100644
--- a/webservices/export.php
+++ b/webservices/export.php
@@ -126,6 +126,19 @@ if (!empty($sExpression))
cmdbAbstractObject::DisplaySetAsCSV($oP, $oSet, array('fields' => $sFields));
break;
+ case 'spreadsheet':
+ $oP = new WebPage("iTop - Export for spreadsheet");
+
+ // Integration within MS-Excel web queries + HTTPS + IIS:
+ // MS-IIS set these header values with no-cache... while Excel fails to do the job if using HTTPS
+ // Then the fix is to force the reset of header values Pragma and Cache-control
+ header("Pragma:", true);
+ header("Cache-control:", true);
+
+ $sFields = implode(',', $aFields);
+ cmdbAbstractObject::DisplaySetAsHTMLSpreadsheet($oP, $oSet, array('fields' => $sFields));
+ break;
+
case 'xml':
$oP = new XMLPage("iTop - Export", true /* passthrough */);
cmdbAbstractObject::DisplaySetAsXML($oP, $oSet);