diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php
index ec4a04412..e50e37d35 100644
--- a/application/cmdbabstract.class.inc.php
+++ b/application/cmdbabstract.class.inc.php
@@ -895,6 +895,18 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
$aFields = explode(',', $aParams['fields']);
}
+ $bFieldsAdvanced = false;
+ if (isset($aParams['fields_advanced']))
+ {
+ $bFieldsAdvanced = (bool) $aParams['fields_advanced'];
+ }
+
+ $bLocalize = true;
+ if (isset($aParams['localize_values']))
+ {
+ $bLocalize = (bool) $aParams['localize_values'];
+ }
+
$aList = array();
$oAppContext = new ApplicationContext();
@@ -920,7 +932,29 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
// Standard list of attributes (no link sets)
if ($oAttDef->IsScalar() && ($oAttDef->IsWritable() || $oAttDef->IsExternalField()))
{
- $aList[$sAlias][$sAttCode] = $oAttDef;
+ $sAttCodeEx = $oAttDef->IsExternalField() ? $oAttDef->GetKeyAttCode().'->'.$oAttDef->GetExtAttCode() : $sAttCode;
+
+ if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
+ {
+ if ($bFieldsAdvanced)
+ {
+ $aList[$sAlias][$sAttCodeEx] = $oAttDef;
+
+ if ($oAttDef->IsExternalKey(EXTKEY_RELATIVE))
+ {
+ $sRemoteClass = $oAttDef->GetTargetClass();
+ foreach(MetaModel::GetReconcKeys($sRemoteClass) as $sRemoteAttCode)
+ {
+ $aList[$sAlias][$sAttCode.'->'.$sRemoteAttCode] = MetaModel::GetAttributeDef($sRemoteClass, $sRemoteAttCode);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Any other attribute
+ $aList[$sAlias][$sAttCodeEx] = $oAttDef;
+ }
}
}
else
@@ -932,36 +966,18 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
}
}
}
- $aHeader[] = 'id';
- foreach($aList[$sAlias] as $sAttCode => $oAttDef)
+ if ($bFieldsAdvanced)
+ {
+ $aHeader[] = 'id';
+ }
+ foreach($aList[$sAlias] as $sAttCodeEx => $oAttDef)
{
$sStar = '';
- if ($oAttDef->IsExternalField())
+ if (!$oAttDef->IsNullAllowed() && isset($aParams['showMandatoryFields']))
{
- $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';
- }
-
- $aHeader[] = $sExtKeyLabel.'->'.$sRemoteAttLabel.$sSuffix.$sStar;
- }
- else
- {
- if (!$oAttDef->IsNullAllowed() && isset($aParams['showMandatoryFields']))
- {
- $sStar = '*';
- }
- $aHeader[] = MetaModel::GetLabel($sClassName, $sAttCode).$sStar;
+ $sStar = '*';
}
+ $aHeader[] = ($bLocalize ? MetaModel::GetLabel($sClassName, $sAttCodeEx) : $sAttCodeEx).$sStar;
}
}
$sHtml = implode($sSeparator, $aHeader)."\n";
@@ -972,15 +988,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
foreach($aAuthorizedClasses as $sAlias => $sClassName)
{
$oObj = $aObjects[$sAlias];
- if (is_null($oObj))
- {
- $aRow[] = '';
- }
- else
- {
- $aRow[] = $oObj->GetKey();
- }
- foreach($aList[$sAlias] as $sAttCode => $oAttDef)
+ if ($bFieldsAdvanced)
{
if (is_null($oObj))
{
@@ -988,7 +996,19 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
}
else
{
- $aRow[] = $oObj->GetAsCSV($sAttCode, $sSeparator, $sTextQualifier);
+ $aRow[] = $oObj->GetKey();
+ }
+ }
+ foreach($aList[$sAlias] as $sAttCodeEx => $oAttDef)
+ {
+ if (is_null($oObj))
+ {
+ $aRow[] = '';
+ }
+ else
+ {
+ $value = $oObj->Get($sAttCodeEx);
+ $aRow[] = $oAttDef->GetAsCSV($value, $sSeparator, $sTextQualifier, $oObj, $bLocalize);
}
}
}
@@ -1015,6 +1035,18 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
$aFields = explode(',', $aParams['fields']);
}
+ $bFieldsAdvanced = false;
+ if (isset($aParams['fields_advanced']))
+ {
+ $bFieldsAdvanced = (bool) $aParams['fields_advanced'];
+ }
+
+ $bLocalize = true;
+ if (isset($aParams['localize_values']))
+ {
+ $bLocalize = (bool) $aParams['localize_values'];
+ }
+
$aList = array();
$oAppContext = new ApplicationContext();
@@ -1040,7 +1072,18 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
// Standard list of attributes (no link sets)
if ($oAttDef->IsScalar() && ($oAttDef->IsWritable() || $oAttDef->IsExternalField()))
{
- $aList[$sAlias][$sAttCode] = $oAttDef;
+ $sAttCodeEx = $oAttDef->IsExternalField() ? $oAttDef->GetKeyAttCode().'->'.$oAttDef->GetExtAttCode() : $sAttCode;
+
+ $aList[$sAlias][$sAttCodeEx] = $oAttDef;
+
+ if ($bFieldsAdvanced && $oAttDef->IsExternalKey(EXTKEY_RELATIVE))
+ {
+ $sRemoteClass = $oAttDef->GetTargetClass();
+ foreach(MetaModel::GetReconcKeys($sRemoteClass) as $sRemoteAttCode)
+ {
+ $aList[$sAlias][$sAttCode.'->'.$sRemoteAttCode] = MetaModel::GetAttributeDef($sRemoteClass, $sRemoteAttCode);
+ }
+ }
}
}
else
@@ -1067,25 +1110,10 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
}
}
- foreach($aList[$sAlias] as $sAttCode => $oAttDef)
+ foreach($aList[$sAlias] as $sAttCodeEx => $oAttDef)
{
- if ($oAttDef->IsExternalField())
- {
- $sExtKeyLabel = MetaModel::GetLabel($sClassName, $oAttDef->GetKeyAttCode());
- $oExtKeyAttDef = MetaModel::GetAttributeDef($sClassName, $oAttDef->GetKeyAttCode());
- $sRemoteAttLabel = MetaModel::GetLabel($oAttDef->GetTargetClass(), $oAttDef->GetExtAttCode());
- $oTargetAttDef = MetaModel::GetAttributeDef($oAttDef->GetTargetClass(), $oAttDef->GetExtAttCode());
- $sSuffix = '';
- if ($oTargetAttDef->IsExternalKey())
- {
- $sSuffix = '->id';
- }
- $sColLabel = $sExtKeyLabel.'->'.$sRemoteAttLabel.$sSuffix;
- }
- else
- {
- $sColLabel = MetaModel::GetLabel($sClassName, $sAttCode);
- }
+ $sColLabel = $bLocalize ? MetaModel::GetLabel($sClassName, $sAttCodeEx) : $sAttCodeEx;
+
$oFinalAttDef = $oAttDef->GetFinalAttDef();
if (get_class($oFinalAttDef) == 'AttributeDateTime')
{
@@ -1111,8 +1139,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
foreach($aAuthorizedClasses as $sAlias => $sClassName)
{
$oObj = $aObjects[$sAlias];
- foreach($aList[$sAlias] as $sAttCode => $oAttDef)
-
+ foreach($aList[$sAlias] as $sAttCodeEx => $oAttDef)
{
if (is_null($oObj))
{
@@ -1123,13 +1150,22 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
$oFinalAttDef = $oAttDef->GetFinalAttDef();
if (get_class($oFinalAttDef) == 'AttributeDateTime')
{
- $iDate = AttributeDateTime::GetAsUnixSeconds($oObj->Get($sAttCode));
+ $iDate = AttributeDateTime::GetAsUnixSeconds($oObj->Get($sAttCodeEx));
$aRow[] = '
'.date('Y-m-d', $iDate).' | ';
$aRow[] = ''.date('H:i:s', $iDate).' | ';
}
else
{
- $aRow[] = ''.(string) $oObj->Get($sAttCode).' | ';
+ $rawValue = $oObj->Get($sAttCodeEx);
+ if ($bLocalize)
+ {
+ $outputValue = htmlentities($oFinalAttDef->GetValueLabel($rawValue), ENT_QUOTES, 'UTF-8');
+ }
+ else
+ {
+ $outputValue = htmlentities($rawValue, ENT_QUOTES, 'UTF-8');
+ }
+ $aRow[] = ''.$outputValue.' | ';
}
}
}
@@ -1144,6 +1180,12 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
static function DisplaySetAsXML(WebPage $oPage, CMDBObjectSet $oSet, $aParams = array())
{
+ $bLocalize = true;
+ if (isset($aParams['localize_values']))
+ {
+ $bLocalize = (bool) $aParams['localize_values'];
+ }
+
$oAppContext = new ApplicationContext();
$aClasses = $oSet->GetFilter()->GetSelectedClasses();
$aAuthorizedClasses = array();
@@ -1189,7 +1231,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
{
if (!$oAttDef->IsLinkSet())
{
- $sValue = $oObj->GetAsXML($sAttCode);
+ $sValue = $oObj->GetAsXML($sAttCode, $bLocalize);
$oPage->add("<$sAttCode>$sValue$sAttCode>\n");
}
}
diff --git a/application/csvpage.class.inc.php b/application/csvpage.class.inc.php
index 0d657776e..05b47af02 100644
--- a/application/csvpage.class.inc.php
+++ b/application/csvpage.class.inc.php
@@ -31,8 +31,9 @@ class CSVPage extends WebPage
function __construct($s_title)
{
parent::__construct($s_title);
- $this->add_header("Content-type: text/html; charset=utf-8");
+ $this->add_header("Content-type: text/plain; charset=utf-8");
$this->add_header("Cache-control: no-cache");
+ //$this->add_header("Content-Transfer-Encoding: binary");
}
public function output()
diff --git a/application/datatable.class.inc.php b/application/datatable.class.inc.php
index 44bd7e3c8..b9a20e9fe 100644
--- a/application/datatable.class.inc.php
+++ b/application/datatable.class.inc.php
@@ -73,6 +73,10 @@ class DataTable
$this->oSet->SetOrderBy($oCustomSettings->GetSortOrder());
$bToolkitMenu = true;
+ if (isset($aExtraParams['toolkit_menu']))
+ {
+ $bToolkitMenu = (bool) $aExtraParams['toolkit_menu'];
+ }
if (UserRights::IsPortalUser())
{
// Portal users have a limited access to data, for now they can only see what's configured for them
@@ -341,6 +345,12 @@ EOF;
protected function GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{
+ $bLocalize = true;
+ if (isset($aExtraParams['localize_values']))
+ {
+ $bLocalize = (bool) $aExtraParams['localize_values'];
+ }
+
$aValues = array();
$this->oSet->Seek(0);
$iMaxObjects = $iPageSize;
@@ -384,7 +394,7 @@ EOF;
}
else
{
- $aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode);
+ $aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize);
}
}
}
diff --git a/application/displayblock.class.inc.php b/application/displayblock.class.inc.php
index 964e93d82..5b05ff194 100644
--- a/application/displayblock.class.inc.php
+++ b/application/displayblock.class.inc.php
@@ -711,7 +711,7 @@ class DisplayBlock
$oFilter->AddCondition($sStateAttrCode, $sStateValue, '=');
$oSet = new DBObjectSet($oFilter);
$aCounts[$sStateValue] = $oSet->Count();
- $aStateLabels[$sStateValue] = $oAttDef->GetValueLabel($sStateValue);
+ $aStateLabels[$sStateValue] = htmlentities($oAttDef->GetValueLabel($sStateValue), ENT_QUOTES, 'UTF-8');
if ($aCounts[$sStateValue] == 0)
{
$aCounts[$sStateValue] = '-';
@@ -733,8 +733,67 @@ class DisplayBlock
break;
case 'csv':
+ $bAdvancedMode = utils::ReadParam('advanced', false);
+
+ $sCsvFile = strtolower($this->m_oFilter->GetClass()).'.csv';
+ $sDownloadLink = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?expression='.urlencode($this->m_oFilter->ToOQL()).'&format=csv&filename='.urlencode($sCsvFile);
+ $sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize()).'&format=csv';
+ if ($bAdvancedMode)
+ {
+ $sDownloadLink .= '&fields_advanced=1';
+ $sChecked = 'CHECKED';
+ }
+ else
+ {
+ $sLinkToToggle = $sLinkToToggle.'&advanced=1';
+ $sChecked = '';
+ }
+
+ $sCSVData = cmdbAbstractObject::GetSetAsCSV($this->m_oSet, array('fields_advanced' => $bAdvancedMode));
+ $sCharset = MetaModel::GetConfig()->Get('csv_file_default_charset');
+ if ($sCharset == 'UTF-8')
+ {
+ $bLostChars = false;
+ }
+ else
+ {
+ $sConverted = @iconv('UTF-8', $sCharset, $sCSVData);
+ $sRestored = @iconv($sCharset, 'UTF-8', $sConverted);
+ $bLostChars = ($sRestored != $sCSVData);
+ }
+
+ if ($bLostChars)
+ {
+ $sCharsetNotice = " ";
+ $sCharsetNotice .= '
';
+ $sCharsetNotice .= "";
+
+ $sTip = "".htmlentities(Dict::S('UI:CSVExport:LostChars'), ENT_QUOTES, 'UTF-8')."
";
+ $sTip .= "".htmlentities(Dict::Format('UI:CSVExport:LostChars+', $sCharset), ENT_QUOTES, 'UTF-8')."
";
+ $oPage->add_ready_script("$('#csv_charset_issue').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
+ }
+ else
+ {
+ $sCharsetNotice = '';
+ }
+
+ $sHtml .= "";
+ $sHtml .= '
';
+ if ($bAdvancedMode)
+ {
+ $sHtml .= "
";
+ $sHtml .= htmlentities(Dict::S('UI:CSVExport:AdvancedMode+'), ENT_QUOTES, 'UTF-8');
+ $sHtml .= "
";
+ }
+ $sHtml .= "
";
+
$sHtml .= "\n";
break;
diff --git a/application/itopwebpage.class.inc.php b/application/itopwebpage.class.inc.php
index 8b35e6aa0..623ca0b00 100644
--- a/application/itopwebpage.class.inc.php
+++ b/application/itopwebpage.class.inc.php
@@ -60,8 +60,6 @@ class iTopWebPage extends NiceWebPage
$this->add_linked_script('../js/jquery.ba-bbq.min.js');
$this->add_linked_script("../js/jquery.treeview.js");
$this->add_linked_script("../js/jquery.autocomplete.js");
- $this->add_linked_script("../js/jquery.positionBy.js");
- $this->add_linked_script("../js/jquery.popupmenu.js");
$this->add_linked_script("../js/date.js");
$this->add_linked_script("../js/jquery.blockUI.js");
$this->add_linked_script("../js/utils.js");
@@ -77,8 +75,6 @@ class iTopWebPage extends NiceWebPage
$this->add_linked_script('../js/g.pie.js');
$this->add_linked_script('../js/g.dot.js');
$this->add_linked_script('../js/charts.js');
- $this->add_linked_script('../js/field_sorter.js');
- $this->add_linked_script('../js/datatable.js');
$this->m_sInitScript =
<<< EOF
diff --git a/application/nicewebpage.class.inc.php b/application/nicewebpage.class.inc.php
index 312e2bc9e..5976755ce 100644
--- a/application/nicewebpage.class.inc.php
+++ b/application/nicewebpage.class.inc.php
@@ -44,6 +44,10 @@ class NiceWebPage extends WebPage
$this->add_linked_script("../js/jquery.tablesorter.min.js");
$this->add_linked_script("../js/jquery.tablesorter.pager.js");
$this->add_linked_script("../js/jquery.tablehover.js");
+ $this->add_linked_script('../js/field_sorter.js');
+ $this->add_linked_script('../js/datatable.js');
+ $this->add_linked_script("../js/jquery.positionBy.js");
+ $this->add_linked_script("../js/jquery.popupmenu.js");
$this->add_ready_script(
<<< EOF
//add new widget called TruncatedList to properly display truncated lists when they are sorted
diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php
index fecac2f81..f7d2da4a6 100644
--- a/core/attributedef.class.inc.php
+++ b/core/attributedef.class.inc.php
@@ -235,12 +235,21 @@ abstract class AttributeDefinition
}
/**
- * Get the label corresponding to the given value
+ * Get the label corresponding to the given value (in plain text)
* To be overloaded for localized enums
*/
public function GetValueLabel($sValue)
{
- return $this->GetAsHTML($sValue);
+ return $sValue;
+ }
+
+ /**
+ * Get the value from a given string (plain text, CSV import)
+ * Return null if no match could be found
+ */
+ public function MakeValueFromString($sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null, $sAttributeQualifier = null)
+ {
+ return $this->MakeRealValue($sProposedValue, null);
}
public function GetLabel_Obsolete()
@@ -422,7 +431,7 @@ abstract class AttributeDefinition
/**
* Override to display the value in the GUI
*/
- public function GetAsHTML($sValue, $oHostObject = null)
+ public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
return Str::pure2html((string)$sValue);
}
@@ -430,7 +439,7 @@ abstract class AttributeDefinition
/**
* Override to export the value in XML
*/
- public function GetAsXML($sValue, $oHostObject = null)
+ public function GetAsXML($sValue, $oHostObject = null, $bLocalize = true)
{
return Str::pure2xml((string)$sValue);
}
@@ -438,7 +447,7 @@ abstract class AttributeDefinition
/**
* Override to escape the value when read by DBObject::GetAsCSV()
*/
- public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
+ public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
{
return (string)$sValue;
}
@@ -591,7 +600,7 @@ class AttributeLinkedSet extends AttributeDefinition
public function GetBasicFilterLooseOperator() {return '';}
public function GetBasicFilterSQLExpr($sOpCode, $value) {return '';}
- public function GetAsHTML($sValue, $oHostObject = null)
+ public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
if (is_object($sValue) && ($sValue instanceof DBObjectSet))
{
@@ -619,12 +628,12 @@ class AttributeLinkedSet extends AttributeDefinition
return null;
}
- public function GetAsXML($sValue, $oHostObject = null)
+ public function GetAsXML($sValue, $oHostObject = null, $bLocalize = true)
{
return "Sorry, no yet implemented";
}
- public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
+ public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
{
$sSepItem = MetaModel::GetConfig()->Get('link_set_item_separator');
$sSepAttribute = MetaModel::GetConfig()->Get('link_set_attribute_separator');
@@ -684,8 +693,7 @@ class AttributeLinkedSet extends AttributeDefinition
return $aColumns;
}
- // Specific to this kind of attribute : transform a string into a value
- public function MakeValueFromString($sProposedValue, $sSepItem = null, $sSepAttribute = null, $sSepValue = null, $sAttributeQualifier = null)
+ public function MakeValueFromString($sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null, $sAttributeQualifier = null)
{
if (is_null($sSepItem) || empty($sSepItem))
{
@@ -1080,7 +1088,7 @@ class AttributeInteger extends AttributeDBField
*/
class AttributePercentage extends AttributeInteger
{
- public function GetAsHTML($sValue, $oHostObject = null)
+ public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
$iWidth = 5; // Total width of the percentage bar graph, in em...
$iValue = (int)$sValue;
@@ -1237,7 +1245,7 @@ class AttributeBoolean extends AttributeInteger
return 0;
}
- public function GetAsXML($sValue, $oHostObject = null)
+ public function GetAsXML($sValue, $oHostObject = null, $bLocalize = true)
{
return $sValue ? '1' : '0';
}
@@ -1355,7 +1363,7 @@ class AttributeString extends AttributeDBField
return $value;
}
- public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
+ public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
{
$sFrom = array("\r\n", $sTextQualifier);
$sTo = array("\n", $sTextQualifier.$sTextQualifier);
@@ -1403,7 +1411,7 @@ class AttributeClass extends AttributeString
return $sDefault;
}
- public function GetAsHTML($sValue, $oHostObject = null)
+ public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
if (empty($sValue)) return '';
return MetaModel::GetName($sValue);
@@ -1492,7 +1500,7 @@ class AttributeFinalClass extends AttributeString
return $this->m_sValue;
}
- public function GetAsHTML($sValue, $oHostObject = null)
+ public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
if (empty($sValue)) return '';
return MetaModel::GetName($sValue);
@@ -1550,7 +1558,7 @@ class AttributePassword extends AttributeString
return array();
}
- public function GetAsHTML($sValue, $oHostObject = null)
+ public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
if (strlen($sValue) == 0)
{
@@ -1708,9 +1716,9 @@ class AttributeText extends AttributeString
return $sText;
}
- public function GetAsHTML($sValue, $oHostObject = null)
+ public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
- $sValue = parent::GetAsHTML($sValue);
+ $sValue = parent::GetAsHTML($sValue, $oHostObject, $bLocalize);
$sValue = self::RenderWikiHtml($sValue);
$aStyles = array();
if ($this->GetWidth() != '')
@@ -1772,7 +1780,7 @@ class AttributeText extends AttributeString
return $sValue;
}
- public function GetAsXML($value, $oHostObject = null)
+ public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
{
return Str::pure2xml($value);
}
@@ -1948,7 +1956,7 @@ class AttributeCaseLog extends AttributeLongText
return $aColumns;
}
- public function GetAsHTML($value, $oHostObject = null)
+ public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
{
if ($value instanceOf ormCaseLog)
{
@@ -1975,11 +1983,11 @@ class AttributeCaseLog extends AttributeLongText
return "".$sContent.'
'; }
- public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
+ public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
{
if ($value instanceOf ormCaseLog)
{
- return parent::GetAsCSV($value->GetText(), $sSeparator, $sTextQualifier, $oHostObject);
+ return parent::GetAsCSV($value->GetText(), $sSeparator, $sTextQualifier, $oHostObject, $bLocalize);
}
else
{
@@ -1987,11 +1995,11 @@ class AttributeCaseLog extends AttributeLongText
}
}
- public function GetAsXML($value, $oHostObject = null)
+ public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
{
if ($value instanceOf ormCaseLog)
{
- return parent::GetAsXML($value->GetText(), $oHostObject);
+ return parent::GetAsXML($value->GetText(), $oHostObject, $bLocalize);
}
else
{
@@ -2009,7 +2017,7 @@ class AttributeHTML extends AttributeLongText
{
public function GetEditClass() {return "HTML";}
- public function GetAsHTML($sValue, $oHostObject = null)
+ public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
return $sValue;
}
@@ -2028,7 +2036,7 @@ class AttributeEmailAddress extends AttributeString
return "^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$";
}
- public function GetAsHTML($sValue, $oHostObject = null)
+ public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
if (empty($sValue)) return '';
return ''.parent::GetAsHTML($sValue).'';
@@ -2092,7 +2100,7 @@ class AttributeTemplateHTML extends AttributeText
{
public function GetEditClass() {return "HTML";}
- public function GetAsHTML($sValue, $oHostObject = null)
+ public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
return $sValue;
}
@@ -2226,14 +2234,51 @@ class AttributeEnum extends AttributeString
return $sDescription;
}
- public function GetAsHTML($sValue, $oHostObject = null)
+ public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
- $sLabel = $this->GetValueLabel($sValue);
- $sDescription = $this->GetValueDescription($sValue);
- // later, we could imagine a detailed description in the title
- return "".parent::GetAsHtml($sLabel)."";
+ if ($bLocalize)
+ {
+ $sLabel = $this->GetValueLabel($sValue);
+ $sDescription = $this->GetValueDescription($sValue);
+ // later, we could imagine a detailed description in the title
+ $sRes = "".parent::GetAsHtml($sLabel)."";
+ }
+ else
+ {
+ $sRes = parent::GetAsHtml($sValue, $oHostObject, $bLocalize);
+ }
+ return $sRes;
}
+ public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
+ {
+ if ($bLocalize)
+ {
+ $sFinalValue = $this->GetValueLabel($value);
+ }
+ else
+ {
+ $sFinalValue = $value;
+ }
+ $sRes = parent::GetAsXML($sFinalValue, $oHostObject, $bLocalize);
+ return $sRes;
+ }
+
+ public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
+ {
+ if ($bLocalize)
+ {
+ $sFinalValue = $this->GetValueLabel($sValue);
+ }
+ else
+ {
+ $sFinalValue = $sValue;
+ }
+ $sRes = parent::GetAsCSV($sFinalValue, $sSeparator, $sTextQualifier, $oHostObject, $bLocalize);
+ return $sRes;
+ }
+
+
public function GetEditValue($sValue, $oHostObj = null)
{
return $this->GetValueLabel($sValue);
@@ -2254,11 +2299,46 @@ class AttributeEnum extends AttributeString
$aLocalizedValues = array();
foreach ($aRawValues as $sKey => $sValue)
{
- $aLocalizedValues[$sKey] = $this->GetValueLabel($sKey);
+ $aLocalizedValues[$sKey] = Str::pure2html($this->GetValueLabel($sKey));
}
return $aLocalizedValues;
}
+ /**
+ * An enum can be localized
+ */
+ public function MakeValueFromString($sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null, $sAttributeQualifier = null)
+ {
+ if ($bLocalizedValue)
+ {
+ // Lookup for the value matching the input
+ //
+ $sFoundValue = null;
+ $aRawValues = parent::GetAllowedValues();
+ if (!is_null($aRawValues))
+ {
+ foreach ($aRawValues as $sKey => $sValue)
+ {
+ $sRefValue = $this->GetValueLabel($sKey);
+ if ($sProposedValue == $sRefValue)
+ {
+ $sFoundValue = $sKey;
+ break;
+ }
+ }
+ }
+ if (is_null($sFoundValue))
+ {
+ return null;
+ }
+ return $this->MakeRealValue($sFoundValue, null);
+ }
+ else
+ {
+ return parent::MakeValueFromString($sProposedValue, $bLocalizedValue, $sSepItem, $sSepAttribute, $sSepValue, $sAttributeQualifier);
+ }
+ }
+
/**
* Processes the input value to align it with the values supported
* by this type of attribute. In this case: turns empty strings into nulls
@@ -2424,17 +2504,17 @@ class AttributeDateTime extends AttributeDBField
return $value;
}
- public function GetAsHTML($value, $oHostObject = null)
+ public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
{
return Str::pure2html($value);
}
- public function GetAsXML($value, $oHostObject = null)
+ public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
{
return Str::pure2xml($value);
}
- public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
+ public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
{
$sFrom = array("\r\n", $sTextQualifier);
$sTo = array("\n", $sTextQualifier.$sTextQualifier);
@@ -2546,7 +2626,7 @@ class AttributeDuration extends AttributeInteger
return $value;
}
- public function GetAsHTML($value, $oHostObject = null)
+ public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
{
return Str::pure2html(self::FormatDuration($value));
}
@@ -2625,7 +2705,7 @@ class AttributeDate extends AttributeDateTime
*/
class AttributeDeadline extends AttributeDateTime
{
- public function GetAsHTML($value, $oHostObject = null)
+ public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
{
$sResult = self::FormatDeadline($value);
return $sResult;
@@ -3140,20 +3220,20 @@ class AttributeExternalField extends AttributeDefinition
return $oExtAttDef->FromSQLToValue($aCols, $sPrefix);
}
- public function GetAsHTML($value, $oHostObject = null)
+ public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
{
$oExtAttDef = $this->GetExtAttDef();
- return $oExtAttDef->GetAsHTML($value);
+ return $oExtAttDef->GetAsHTML($value, null, $bLocalize);
}
- public function GetAsXML($value, $oHostObject = null)
+ public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
{
$oExtAttDef = $this->GetExtAttDef();
- return $oExtAttDef->GetAsXML($value);
+ return $oExtAttDef->GetAsXML($value, null, $bLocalize);
}
- public function GetAsCSV($value, $sSeparator = ',', $sTestQualifier = '"', $oHostObject = null)
+ public function GetAsCSV($value, $sSeparator = ',', $sTestQualifier = '"', $oHostObject = null, $bLocalize = true)
{
$oExtAttDef = $this->GetExtAttDef();
- return $oExtAttDef->GetAsCSV($value, $sSeparator, $sTestQualifier);
+ return $oExtAttDef->GetAsCSV($value, $sSeparator, $sTestQualifier, null, $bLocalize);
}
}
@@ -3172,7 +3252,7 @@ class AttributeURL extends AttributeString
public function GetEditClass() {return "String";}
- public function GetAsHTML($sValue, $oHostObject = null)
+ public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
$sTarget = $this->Get("target");
if (empty($sTarget)) $sTarget = "_blank";
@@ -3322,7 +3402,7 @@ class AttributeBlob extends AttributeDefinition
return 'true';
}
- public function GetAsHTML($value, $oHostObject = null)
+ public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
{
if (is_object($value))
{
@@ -3330,12 +3410,12 @@ class AttributeBlob extends AttributeDefinition
}
}
- public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
+ public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
{
return ''; // Not exportable in CSV !
}
- public function GetAsXML($value, $oHostObject = null)
+ public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
{
return ''; // Not exportable in XML, or as CDATA + some subtags ??
}
@@ -3561,7 +3641,7 @@ class AttributeStopWatch extends AttributeDefinition
return 'true';
}
- public function GetAsHTML($value, $oHostObject = null)
+ public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
{
if (is_object($value))
{
@@ -3569,12 +3649,12 @@ class AttributeStopWatch extends AttributeDefinition
}
}
- public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
+ public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
{
return $value->GetTimeSpent();
}
- public function GetAsXML($value, $oHostObject = null)
+ public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
{
return $value->GetTimeSpent();
}
@@ -3891,21 +3971,21 @@ class AttributeSubItem extends AttributeDefinition
return $res;
}
- public function GetAsHTML($value, $oHostObject = null)
+ public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
{
$oParent = $this->GetTargetAttDef();
$res = $oParent->GetSubItemAsHTML($this->Get('item_code'), $value);
return $res;
}
- public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
+ public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
{
$oParent = $this->GetTargetAttDef();
$res = $oParent->GetSubItemAsCSV($this->Get('item_code'), $value, $sSeparator = ',', $sTextQualifier = '"');
return $res;
}
- public function GetAsXML($value, $oHostObject = null)
+ public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
{
$oParent = $this->GetTargetAttDef();
$res = $oParent->GetSubItemAsXML($this->Get('item_code'), $value);
@@ -4057,7 +4137,7 @@ class AttributeOneWayPassword extends AttributeDefinition
return 'true';
}
- public function GetAsHTML($value, $oHostObject = null)
+ public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
{
if (is_object($value))
{
@@ -4065,12 +4145,12 @@ class AttributeOneWayPassword extends AttributeDefinition
}
}
- public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
+ public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
{
return ''; // Not exportable in CSV
}
- public function GetAsXML($value, $oHostObject = null)
+ public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
{
return ''; // Not exportable in XML
}
@@ -4132,7 +4212,7 @@ class AttributeTable extends AttributeDBField
return $aValues;
}
- public function GetAsHTML($value, $oHostObject = null)
+ public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
{
if (!is_array($value))
{
@@ -4160,13 +4240,13 @@ class AttributeTable extends AttributeDBField
return $sRes;
}
- public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
+ public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
{
// Not implemented
return '';
}
- public function GetAsXML($value, $oHostObject = null)
+ public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
{
if (count($value) == 0)
{
@@ -4203,7 +4283,7 @@ class AttributePropertySet extends AttributeTable
return $proposedValue;
}
- public function GetAsHTML($value, $oHostObject = null)
+ public function GetAsHTML($value, $oHostObject = null, $bLocalize = true)
{
if (!is_array($value))
{
@@ -4232,7 +4312,7 @@ class AttributePropertySet extends AttributeTable
return $sRes;
}
- public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null)
+ public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
{
if (count($value) == 0)
{
@@ -4258,7 +4338,7 @@ class AttributePropertySet extends AttributeTable
return $sTextQualifier.$sEscaped.$sTextQualifier;
}
- public function GetAsXML($value, $oHostObject = null)
+ public function GetAsXML($value, $oHostObject = null, $bLocalize = true)
{
if (count($value) == 0)
{
@@ -4455,7 +4535,7 @@ class AttributeFriendlyName extends AttributeComputedFieldVoid
return $this->m_sValue;
}
- public function GetAsHTML($sValue, $oHostObject = null)
+ public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
return Str::pure2html((string)$sValue);
}
diff --git a/core/bulkchange.class.inc.php b/core/bulkchange.class.inc.php
index 47e31a215..7daf5e4d0 100644
--- a/core/bulkchange.class.inc.php
+++ b/core/bulkchange.class.inc.php
@@ -24,6 +24,10 @@
*/
+// The BOM is added at the head of exported UTF-8 CSV data, and removed (if present) from input UTF-8 data.
+// This helps MS-Excel (Version > 2007, Windows only) in changing its interpretation of a CSV file (by default Excel reads data as ISO-8859-1 -not 100% sure!)
+define('UTF8_BOM', chr(239).chr(187).chr(191)); // 0xEF, 0xBB, 0xBF
+
/**
* BulkChange
* Interpret a given data set and update the DB accordingly (fake mode avail.)
@@ -84,15 +88,16 @@ class CellStatus_Modify extends CellChangeSpec
{
protected $m_previousValue;
- public function __construct($proposedValue, $previousValue)
+ public function __construct($proposedValue, $previousValue = null)
{
- $this->m_previousValue = $previousValue;
+ // Unused (could be costly to know -see the case of reconciliation on ext keys)
+ //$this->m_previousValue = $previousValue;
parent::__construct($proposedValue);
}
public function GetDescription()
{
- return 'Modified';
+ return Dict::S('UI:CSVReport-Value-Modified');
}
//public function GetPreviousValue()
@@ -115,9 +120,9 @@ class CellStatus_Issue extends CellStatus_Modify
{
if (is_null($this->m_proposedValue))
{
- return 'Could not be changed - reason: '.$this->m_sReason;
+ return Dict::Format('UI:CSVReport-Value-SetIssue', $this->m_sReason);
}
- return 'Could not be changed to '.$this->m_proposedValue.' - reason: '.$this->m_sReason;
+ return Dict::Format('UI:CSVReport-Value-ChangeIssue', $this->m_proposedValue, $this->m_sReason);
}
}
@@ -130,7 +135,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
public function GetDescription()
{
- return 'No match';
+ return Dict::S('UI:CSVReport-Value-NoMatch');
}
}
@@ -143,7 +148,7 @@ class CellStatus_NullIssue extends CellStatus_Issue
public function GetDescription()
{
- return 'Missing mandatory value';
+ return Dict::S('UI:CSVReport-Value-Missing');
}
}
@@ -162,7 +167,7 @@ class CellStatus_Ambiguous extends CellStatus_Issue
public function GetDescription()
{
$sCount = $this->m_iCount;
- return "Ambiguous: found $sCount objects";
+ return Dict::Format('UI:CSVReport-Value-Ambiguous', $sCount);
}
}
@@ -186,7 +191,7 @@ class RowStatus_NoChange extends RowStatus
{
public function GetDescription()
{
- return "unchanged";
+ return Dict::S('UI:CSVReport-Row-Unchanged');
}
}
@@ -194,7 +199,7 @@ class RowStatus_NewObj extends RowStatus
{
public function GetDescription()
{
- return "created";
+ return Dict::S('UI:CSVReport-Row-Created');
}
}
@@ -209,7 +214,7 @@ class RowStatus_Modify extends RowStatus
public function GetDescription()
{
- return "updated ".$this->m_iChanged." cols";
+ return Dict::Format('UI:CSVReport-Row-Updated', $this->m_iChanged);
}
}
@@ -217,7 +222,7 @@ class RowStatus_Disappeared extends RowStatus_Modify
{
public function GetDescription()
{
- return "disappeared, changed ".$this->m_iChanged." cols";
+ return Dict::Format('UI:CSVReport-Row-Disappeared', $this->m_iChanged);
}
}
@@ -232,7 +237,7 @@ class RowStatus_Issue extends RowStatus
public function GetDescription()
{
- return 'Issue: '.$this->m_sReason;
+ return Dict::Format('UI:CSVReport-Row-Issue', $this->m_sReason);
}
}
@@ -253,8 +258,9 @@ class BulkChange
protected $m_sSynchroScope; // OQL - if specified, then the missing items will be reported
protected $m_aOnDisappear; // array of attcode => value, values to be set when an object gets out of scope (ignored if no scope has been defined)
protected $m_sDateFormat; // Date format specification, see utils::StringToTime()
+ protected $m_bLocalizedValues; // Values in the data set are localized (see AttributeEnum)
- public function __construct($sClass, $aData, $aAttList, $aExtKeys, $aReconcilKeys, $sSynchroScope = null, $aOnDisappear = null, $sDateFormat = null)
+ public function __construct($sClass, $aData, $aAttList, $aExtKeys, $aReconcilKeys, $sSynchroScope = null, $aOnDisappear = null, $sDateFormat = null, $bLocalize = false)
{
$this->m_sClass = $sClass;
$this->m_aData = $aData;
@@ -264,6 +270,7 @@ class BulkChange
$this->m_sSynchroScope = $sSynchroScope;
$this->m_aOnDisappear = $aOnDisappear;
$this->m_sDateFormat = $sDateFormat;
+ $this->m_bLocalizedValues = $bLocalize;
}
protected $m_bReportHtml = false;
@@ -331,6 +338,7 @@ class BulkChange
{
foreach ($aKeyConfig as $sForeignAttCode => $iCol)
{
+ // Default reporting
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
}
if ($oExtKey->IsNullAllowed())
@@ -340,8 +348,8 @@ class BulkChange
}
else
{
- $aErrors[$sAttCode] = "Null not allowed";
- $aResults[$sAttCode]= new CellStatus_Issue(null, $oTargetObj->Get($sAttCode), 'Null not allowed');
+ $aErrors[$sAttCode] = Dict::S('UI:CSVReport-Value-Issue-Null');
+ $aResults[$sAttCode]= new CellStatus_Issue(null, $oTargetObj->Get($sAttCode), Dict::S('UI:CSVReport-Value-Issue-Null'));
}
}
else
@@ -357,7 +365,7 @@ class BulkChange
switch($oExtObjects->Count())
{
case 0:
- $aErrors[$sAttCode] = "Object not found";
+ $aErrors[$sAttCode] = Dict::S('UI:CSVReport-Value-Issue-NotFound');
$aResults[$sAttCode]= new CellStatus_SearchIssue();
break;
case 1:
@@ -366,7 +374,7 @@ class BulkChange
$oTargetObj->Set($sAttCode, $oForeignObj->GetKey());
break;
default:
- $aErrors[$sAttCode] = "Found ".$oExtObjects->Count()." matches";
+ $aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-FoundMany', $oExtObjects->Count());
$aResults[$sAttCode]= new CellStatus_Ambiguous($oTargetObj->Get($sAttCode), $oExtObjects->Count(), $oReconFilter->ToOql());
}
}
@@ -384,6 +392,11 @@ class BulkChange
else
{
$aResults[$sAttCode]= new CellStatus_Modify($iForeignObj, $oTargetObj->GetOriginal($sAttCode));
+ foreach ($aKeyConfig as $sForeignAttCode => $iCol)
+ {
+ // Report the change on reconciliation values as well
+ $aResults[$iCol] = new CellStatus_Modify($aRowData[$iCol]);
+ }
}
}
else
@@ -405,31 +418,39 @@ class BulkChange
$iFlags = $oTargetObj->GetAttributeFlags($sAttCode, $aReasons);
if ( (($iFlags & OPT_ATT_READONLY) == OPT_ATT_READONLY) && ( $oTargetObj->Get($sAttCode) != $aRowData[$iCol]) )
{
- $aErrors[$sAttCode] = "the attribute '$sAttCode' is read-only and cannot be modified (current value: ".$oTargetObj->Get($sAttCode).", proposed value: {$aRowData[$iCol]}).";
+ $aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-Readonly', $sAttCode, $oTargetObj->Get($sAttCode), $aRowData[$iCol]);
}
else if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect())
{
try
{
- $oSet = $oAttDef->MakeValueFromString($aRowData[$iCol]);
+ $oSet = $oAttDef->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
$oTargetObj->Set($sAttCode, $oSet);
}
catch(CoreException $e)
{
- $aErrors[$sAttCode] = "Failed to process input: ".$e->getMessage();
+ $aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-Format', $e->getMessage());
}
}
else
{
- $res = $oTargetObj->CheckValue($sAttCode, $aRowData[$iCol]);
- if ($res === true)
+ $value = $oAttDef->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
+ if (is_null($value) && (strlen($aRowData[$iCol]) > 0))
{
- $oTargetObj->Set($sAttCode, $aRowData[$iCol]);
+ $aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-NoMatch', $sAttCode);
}
else
{
- // $res is a string with the error description
- $aErrors[$sAttCode] = "Unexpected value for attribute '$sAttCode': $res";
+ $res = $oTargetObj->CheckValue($sAttCode, $value);
+ if ($res === true)
+ {
+ $oTargetObj->Set($sAttCode, $value);
+ }
+ else
+ {
+ // $res is a string with the error description
+ $aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-Unknown', $sAttCode, $res);
+ }
}
}
}
@@ -447,17 +468,19 @@ class BulkChange
{
if ($this->m_bReportHtml)
{
- $sCurValue = $oTargetObj->GetAsHTML($sAttCode);
- $sOrigValue = $oTargetObj->GetOriginalAsHTML($sAttCode);
+ $sCurValue = $oTargetObj->GetAsHTML($sAttCode, $this->m_bLocalizedValues);
+ $sOrigValue = $oTargetObj->GetOriginalAsHTML($sAttCode, $this->m_bLocalizedValues);
+ $sInput = htmlentities($aRowData[$iCol], ENT_QUOTES, 'UTF-8');
}
else
{
- $sCurValue = $oTargetObj->GetAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter);
- $sOrigValue = $oTargetObj->GetOriginalAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter);
+ $sCurValue = $oTargetObj->GetAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter, $this->m_bLocalizedValues);
+ $sOrigValue = $oTargetObj->GetOriginalAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter, $this->m_bLocalizedValues);
+ $sInput = $aRowData[$iCol];
}
if (isset($aErrors[$sAttCode]))
{
- $aResults[$iCol]= new CellStatus_Issue($sCurValue, $sOrigValue, $aErrors[$sAttCode]);
+ $aResults[$iCol]= new CellStatus_Issue($aRowData[$iCol], $sOrigValue, $aErrors[$sAttCode]);
}
elseif (array_key_exists($sAttCode, $aChangedFields))
{
@@ -484,7 +507,7 @@ class BulkChange
if ($res !== true)
{
// $res contains the error description
- $aErrors["GLOBAL"] = "Attributes not consistent with each others: $res";
+ $aErrors["GLOBAL"] = Dict::Format('UI:CSVReport-Row-Issue-Inconsistent', $res);
}
return $aResults;
}
@@ -548,7 +571,7 @@ class BulkChange
if ($res !== true)
{
// $res contains the error description
- $aErrors["GLOBAL"] = "Attributes not consistent with each others: $res";
+ $aErrors["GLOBAL"] = Dict::Format('UI:CSVReport-Row-Issue-Inconsistent', $res);
}
return $aResults;
}
@@ -562,7 +585,7 @@ class BulkChange
if (count($aErrors) > 0)
{
$sErrors = implode(', ', $aErrors);
- $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue("Unexpected attribute value(s)");
+ $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Attribute'));
return $oTargetObj;
}
@@ -581,7 +604,7 @@ class BulkChange
if (count($aMissingKeys) > 0)
{
$sMissingKeys = implode(', ', $aMissingKeys);
- $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue("Could not be created, due to missing external key(s): $sMissingKeys");
+ $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::Format('UI:CSVReport-Row-Issue-MissingExtKey', $sMissingKeys));
return $oTargetObj;
}
@@ -615,7 +638,7 @@ class BulkChange
if (count($aErrors) > 0)
{
$sErrors = implode(', ', $aErrors);
- $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue("Unexpected attribute value(s)");
+ $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Attribute'));
return;
}
@@ -656,7 +679,7 @@ class BulkChange
if (count($aErrors) > 0)
{
$sErrors = implode(', ', $aErrors);
- $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue("Unexpected attribute value(s)");
+ $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Attribute'));
return;
}
@@ -732,8 +755,8 @@ class BulkChange
else
{
// Leave the cell unchanged
- $aResult[$iRow]["__STATUS__"]= new RowStatus_Issue("wrong date format");
- $aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, $this->m_aData[$iRow][$iCol], 'Wrong date format');
+ $aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
+ $aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, $this->m_aData[$iRow][$iCol], Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
}
}
}
@@ -753,91 +776,98 @@ class BulkChange
// An issue at the earlier steps - skip the rest
continue;
}
- $oReconciliationFilter = new CMDBSearchFilter($this->m_sClass);
- $bSkipQuery = false;
- foreach($this->m_aReconcilKeys as $sAttCode)
+ try
{
- $valuecondition = null;
- if (array_key_exists($sAttCode, $this->m_aExtKeys))
+ $oReconciliationFilter = new CMDBSearchFilter($this->m_sClass);
+ $bSkipQuery = false;
+ foreach($this->m_aReconcilKeys as $sAttCode)
{
- if ($this->IsNullExternalKeySpec($aRowData, $sAttCode))
+ $valuecondition = null;
+ if (array_key_exists($sAttCode, $this->m_aExtKeys))
{
- $oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
- if ($oExtKey->IsNullAllowed())
+ if ($this->IsNullExternalKeySpec($aRowData, $sAttCode))
{
- $valuecondition = $oExtKey->GetNullValue();
- $aResult[$iRow][$sAttCode] = new CellStatus_Void($oExtKey->GetNullValue());
+ $oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
+ if ($oExtKey->IsNullAllowed())
+ {
+ $valuecondition = $oExtKey->GetNullValue();
+ $aResult[$iRow][$sAttCode] = new CellStatus_Void($oExtKey->GetNullValue());
+ }
+ else
+ {
+ $aResult[$iRow][$sAttCode] = new CellStatus_NullIssue();
+ }
}
else
{
- $aResult[$iRow][$sAttCode] = new CellStatus_NullIssue();
- }
+ // The value has to be found or verified
+ list($sQuery, $aMatches) = $this->ResolveExternalKey($aRowData, $sAttCode, $aResult[$iRow]);
+
+ if (count($aMatches) == 1)
+ {
+ $oRemoteObj = reset($aMatches); // first item
+ $valuecondition = $oRemoteObj->GetKey();
+ $aResult[$iRow][$sAttCode] = new CellStatus_Void($oRemoteObj->GetKey());
+ }
+ elseif (count($aMatches) == 0)
+ {
+ $aResult[$iRow][$sAttCode] = new CellStatus_SearchIssue();
+ }
+ else
+ {
+ $aResult[$iRow][$sAttCode] = new CellStatus_Ambiguous(null, count($aMatches), $sQuery);
+ }
+ }
}
else
{
- // The value has to be found or verified
- list($sQuery, $aMatches) = $this->ResolveExternalKey($aRowData, $sAttCode, $aResult[$iRow]);
-
- if (count($aMatches) == 1)
- {
- $oRemoteObj = reset($aMatches); // first item
- $valuecondition = $oRemoteObj->GetKey();
- $aResult[$iRow][$sAttCode] = new CellStatus_Void($oRemoteObj->GetKey());
- }
- elseif (count($aMatches) == 0)
- {
- $aResult[$iRow][$sAttCode] = new CellStatus_SearchIssue();
- }
- else
- {
- $aResult[$iRow][$sAttCode] = new CellStatus_Ambiguous(null, count($aMatches), $sQuery);
- }
- }
- }
- else
- {
- // The value is given in the data row
- $iCol = $this->m_aAttList[$sAttCode];
- $valuecondition = $aRowData[$iCol];
- }
- if (is_null($valuecondition))
- {
- $bSkipQuery = true;
- }
- else
- {
- $oReconciliationFilter->AddCondition($sAttCode, $valuecondition, '=');
- }
- }
- if ($bSkipQuery)
- {
- $aResult[$iRow]["__STATUS__"]= new RowStatus_Issue("failed to reconcile");
- }
- else
- {
- $oReconciliationSet = new CMDBObjectSet($oReconciliationFilter);
- switch($oReconciliationSet->Count())
- {
- case 0:
- $oTargetObj = $this->CreateObject($aResult, $iRow, $aRowData, $oChange);
- // $aResult[$iRow]["__STATUS__"]=> set in CreateObject
- $aVisited[] = $oTargetObj->GetKey();
- break;
- case 1:
- $oTargetObj = $oReconciliationSet->Fetch();
- $this->UpdateObject($aResult, $iRow, $oTargetObj, $aRowData, $oChange);
- // $aResult[$iRow]["__STATUS__"]=> set in UpdateObject
- if (!is_null($this->m_sSynchroScope))
- {
- $aVisited[] = $oTargetObj->GetKey();
+ // The value is given in the data row
+ $iCol = $this->m_aAttList[$sAttCode];
+ $valuecondition = $aRowData[$iCol];
+ }
+ if (is_null($valuecondition))
+ {
+ $bSkipQuery = true;
+ }
+ else
+ {
+ $oReconciliationFilter->AddCondition($sAttCode, $valuecondition, '=');
}
- break;
- default:
- // Found several matches, ambiguous
- $aResult[$iRow]["__STATUS__"]= new RowStatus_Issue("ambiguous reconciliation");
- $aResult[$iRow]["id"]= new CellStatus_Ambiguous(0, $oReconciliationSet->Count(), $oReconciliationFilter->ToOql());
- $aResult[$iRow]["finalclass"]= 'n/a';
}
+ if ($bSkipQuery)
+ {
+ $aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Reconciliation'));
+ }
+ else
+ {
+ $oReconciliationSet = new CMDBObjectSet($oReconciliationFilter);
+ switch($oReconciliationSet->Count())
+ {
+ case 0:
+ $oTargetObj = $this->CreateObject($aResult, $iRow, $aRowData, $oChange);
+ // $aResult[$iRow]["__STATUS__"]=> set in CreateObject
+ $aVisited[] = $oTargetObj->GetKey();
+ break;
+ case 1:
+ $oTargetObj = $oReconciliationSet->Fetch();
+ $this->UpdateObject($aResult, $iRow, $oTargetObj, $aRowData, $oChange);
+ // $aResult[$iRow]["__STATUS__"]=> set in UpdateObject
+ if (!is_null($this->m_sSynchroScope))
+ {
+ $aVisited[] = $oTargetObj->GetKey();
+ }
+ break;
+ default:
+ // Found several matches, ambiguous
+ $aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Ambiguous'));
+ $aResult[$iRow]["id"]= new CellStatus_Ambiguous(0, $oReconciliationSet->Count(), $oReconciliationFilter->ToOql());
+ $aResult[$iRow]["finalclass"]= 'n/a';
+ }
+ }
+ }
+ catch (Exception $e)
+ {
+ $aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::Format('UI:CSVReport-Row-Issue-Internal', get_class($e), $e->getMessage()));
}
}
@@ -1166,49 +1196,6 @@ EOF
}
$oPage->table($aConfig, $aDetails);
}
-
- /**
- * Get the user friendly name for an 'extended' attribute code i.e 'name', becomes 'Name' and 'org_id->name' becomes 'Organization->Name'
- * @param string $sClassName The name of the class
- * @param string $sAttCodeEx Either an attribute code or ext_key_name->att_code
- * @return string A user friendly format of the string: AttributeName or AttributeName->ExtAttributeName
- */
- public static function GetFriendlyAttCodeName($sClassName, $sAttCodeEx)
- {
- $sFriendlyName = '';
- if (preg_match('/(.+)->(.+)/', $sAttCodeEx, $aMatches) > 0)
- {
- $sAttribute = $aMatches[1];
- $sField = $aMatches[2];
- $oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttribute);
- if ($oAttDef->IsExternalKey())
- {
- $sTargetClass = $oAttDef->GetTargetClass();
- $oTargetAttDef = MetaModel::GetAttributeDef($sTargetClass, $sField);
- $sFriendlyName = $oAttDef->GetLabel().'->'.$oTargetAttDef->GetLabel();
- }
- else
- {
- // hum, hum... should never happen, we'd better raise an exception
- throw(new Exception(Dict::Format('UI:CSVImport:ErrorExtendedAttCode', $sAttCodeEx, $sAttribute, $sClassName)));
- }
-
- }
- else
- {
- if ($sAttCodeEx == 'id')
- {
- $sFriendlyName = Dict::S('UI:CSVImport:idField');
- }
- else
- {
- $oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCodeEx);
- $sFriendlyName = $oAttDef->GetLabel();
- }
- }
- return $sFriendlyName;
- }
-
}
diff --git a/core/config.class.inc.php b/core/config.class.inc.php
index 6c9a4677c..5f44a0a58 100644
--- a/core/config.class.inc.php
+++ b/core/config.class.inc.php
@@ -537,6 +537,16 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => true,
),
+ 'csv_file_default_charset' => array(
+ 'type' => 'string',
+ 'description' => 'Character set used by default for downloading and uploading data as a CSV file. Warning: it is case sensitive (uppercase is preferable).',
+ // examples... not used
+ 'default' => 'ISO-8859-1',
+ 'value' => '',
+ 'source_of_value' => '',
+ 'show_in_conf_sample' => true,
+ ),
+
);
public function IsProperty($sPropCode)
diff --git a/core/dbobject.class.php b/core/dbobject.class.php
index c8c228ac3..408b3083c 100644
--- a/core/dbobject.class.php
+++ b/core/dbobject.class.php
@@ -548,7 +548,7 @@ abstract class DBObject
$this->ComputeValues();
}
- public function GetAsHTML($sAttCode)
+ public function GetAsHTML($sAttCode, $bLocalize = true)
{
$sClass = get_class($this);
$oAtt = MetaModel::GetAttributeDef($sClass, $sAttCode);
@@ -571,7 +571,7 @@ abstract class DBObject
}
// That's a standard attribute (might be an ext field or a direct field, etc.)
- return $oAtt->GetAsHTML($this->Get($sAttCode), $this);
+ return $oAtt->GetAsHTML($this->Get($sAttCode), $this, $bLocalize);
}
public function GetEditValue($sAttCode)
@@ -609,34 +609,34 @@ abstract class DBObject
return $sEditValue;
}
- public function GetAsXML($sAttCode)
+ public function GetAsXML($sAttCode, $bLocalize = true)
{
$oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
- return $oAtt->GetAsXML($this->Get($sAttCode), $this);
+ return $oAtt->GetAsXML($this->Get($sAttCode), $this, $bLocalize);
}
- public function GetAsCSV($sAttCode, $sSeparator = ',', $sTextQualifier = '"')
+ public function GetAsCSV($sAttCode, $sSeparator = ',', $sTextQualifier = '"', $bLocalize = true)
{
$oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
- return $oAtt->GetAsCSV($this->Get($sAttCode), $sSeparator, $sTextQualifier, $this);
+ return $oAtt->GetAsCSV($this->Get($sAttCode), $sSeparator, $sTextQualifier, $this, $bLocalize);
}
- public function GetOriginalAsHTML($sAttCode)
+ public function GetOriginalAsHTML($sAttCode, $bLocalize = true)
{
$oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
- return $oAtt->GetAsHTML($this->GetOriginal($sAttCode), $this);
+ return $oAtt->GetAsHTML($this->GetOriginal($sAttCode), $this, $bLocalize);
}
- public function GetOriginalAsXML($sAttCode)
+ public function GetOriginalAsXML($sAttCode, $bLocalize = true)
{
$oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
- return $oAtt->GetAsXML($this->GetOriginal($sAttCode), $this);
+ return $oAtt->GetAsXML($this->GetOriginal($sAttCode), $this, $bLocalize);
}
- public function GetOriginalAsCSV($sAttCode, $sSeparator = ',', $sTextQualifier = '"')
+ public function GetOriginalAsCSV($sAttCode, $sSeparator = ',', $sTextQualifier = '"', $bLocalize = true)
{
$oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
- return $oAtt->GetAsCSV($this->GetOriginal($sAttCode), $sSeparator, $sTextQualifier, $this);
+ return $oAtt->GetAsCSV($this->GetOriginal($sAttCode), $sSeparator, $sTextQualifier, $this, $bLocalize);
}
public static function MakeHyperLink($sObjClass, $sObjKey, $sLabel = '', $sUrlMakerClass = null, $bWithNavigationContext = true)
diff --git a/core/metamodel.class.php b/core/metamodel.class.php
index bc7d7c285..9a0aa51b1 100644
--- a/core/metamodel.class.php
+++ b/core/metamodel.class.php
@@ -907,11 +907,45 @@ abstract class MetaModel
}
- public static function GetLabel($sClass, $sAttCode)
+ /**
+ * Get the attribute label
+ * @param string sClass Persistent class
+ * @param string sAttCodeEx Extended attribute code: attcode[->attcode]
+ * @return string A user friendly format of the string: AttributeName or AttributeName->ExtAttributeName
+ */
+ public static function GetLabel($sClass, $sAttCodeEx)
{
- $oAttDef = self::GetAttributeDef($sClass, $sAttCode);
- if ($oAttDef) return $oAttDef->GetLabel();
- return "";
+ $sLabel = '';
+ if (preg_match('/(.+)->(.+)/', $sAttCodeEx, $aMatches) > 0)
+ {
+ $sAttribute = $aMatches[1];
+ $sField = $aMatches[2];
+ $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttribute);
+ if ($oAttDef->IsExternalKey())
+ {
+ $sTargetClass = $oAttDef->GetTargetClass();
+ $oTargetAttDef = MetaModel::GetAttributeDef($sTargetClass, $sField);
+ $sLabel = $oAttDef->GetLabel().'->'.$oTargetAttDef->GetLabel();
+ }
+ else
+ {
+ // Let's return something displayable... but this should never happen!
+ $sLabel = $oAttDef->GetLabel().'->'.$aMatches[2];
+ }
+ }
+ else
+ {
+ if ($sAttCodeEx == 'id')
+ {
+ $sLabel = Dict::S('UI:CSVImport:idField');
+ }
+ else
+ {
+ $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCodeEx);
+ $sLabel = $oAttDef->GetLabel();
+ }
+ }
+ return $sLabel;
}
public static function GetDescription($sClass, $sAttCode)
diff --git a/dictionaries/dictionary.itop.ui.php b/dictionaries/dictionary.itop.ui.php
index 2221f7cb2..2201e0b5b 100644
--- a/dictionaries/dictionary.itop.ui.php
+++ b/dictionaries/dictionary.itop.ui.php
@@ -550,7 +550,53 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:UniversalSearchTitle' => 'iTop - Universal Search',
'UI:UniversalSearch:Error' => 'Error: %1$s',
'UI:UniversalSearch:LabelSelectTheClass' => 'Select the class to search: ',
-
+
+ 'UI:CSVReport-Value-Modified' => 'Modified',
+ 'UI:CSVReport-Value-SetIssue' => 'Could not be changed - reason: %1$s',
+ 'UI:CSVReport-Value-ChangeIssue' => 'Could not be changed to %1$s - reason: %2$s',
+ 'UI:CSVReport-Value-NoMatch' => 'No match',
+ 'UI:CSVReport-Value-Missing' => 'Missing mandatory value',
+ 'UI:CSVReport-Value-Ambiguous' => 'Ambiguous: found %1$s objects',
+ 'UI:CSVReport-Row-Unchanged' => 'unchanged',
+ 'UI:CSVReport-Row-Created' => 'created',
+ 'UI:CSVReport-Row-Updated' => 'updated %1$d cols',
+ 'UI:CSVReport-Row-Disappeared' => 'disappeared, changed %1$d cols',
+ 'UI:CSVReport-Row-Issue' => 'Issue: %1$s',
+ 'UI:CSVReport-Value-Issue-Null' => 'Null not allowed',
+ 'UI:CSVReport-Value-Issue-NotFound' => 'Object not found',
+ 'UI:CSVReport-Value-Issue-FoundMany' => 'Found %1$d matches',
+ 'UI:CSVReport-Value-Issue-Readonly' => 'The attribute \'%1$s\' is read-only and cannot be modified (current value: %2$s, proposed value: %3$s)',
+ 'UI:CSVReport-Value-Issue-Format' => 'Failed to process input: %1$s',
+ 'UI:CSVReport-Value-Issue-NoMatch' => 'Unexpected value for attribute \'%1$s\': no match found, check spelling',
+ 'UI:CSVReport-Value-Issue-Unknown' => 'Unexpected value for attribute \'%1$s\': %2$s',
+ 'UI:CSVReport-Row-Issue-Inconsistent' => 'Attributes not consistent with each others: %1$s',
+ 'UI:CSVReport-Row-Issue-Attribute' => 'Unexpected attribute value(s)',
+ 'UI:CSVReport-Row-Issue-MissingExtKey' => 'Could not be created, due to missing external key(s): %1$s',
+ 'UI:CSVReport-Row-Issue-DateFormat' => 'wrong date format',
+ 'UI:CSVReport-Row-Issue-Reconciliation' => 'failed to reconcile',
+ 'UI:CSVReport-Row-Issue-Ambiguous' => 'ambiguous reconciliation',
+ 'UI:CSVReport-Row-Issue-Internal' => 'Internal error: %1$s, %2$s',
+
+ 'UI:CSVReport-Icon-Unchanged' => 'Unchanged',
+ 'UI:CSVReport-Icon-Modified' => 'Modified',
+ 'UI:CSVReport-Icon-Missing' => 'Missing',
+ 'UI:CSVReport-Object-MissingToUpdate' => 'Missing object: will be updated',
+ 'UI:CSVReport-Object-MissingUpdated' => 'Missing object: updated',
+ 'UI:CSVReport-Icon-Created' => 'Created',
+ 'UI:CSVReport-Object-ToCreate' => 'Object will be created',
+ 'UI:CSVReport-Object-Created' => 'Object created',
+ 'UI:CSVReport-Icon-Error' => 'Error',
+ 'UI:CSVReport-Object-Error' => 'ERROR: %1$s',
+ 'UI:CSVReport-Object-Ambiguous' => 'AMBIGUOUS: %1$s',
+ 'UI:CSVReport-Stats-Errors' => '%1$.0f %% of the loaded objects have errors and will be ignored.',
+ 'UI:CSVReport-Stats-Created' => '%1$.0f %% of the loaded objects will be created.',
+ 'UI:CSVReport-Stats-Modified' => '%1$.0f %% of the loaded objects will be modified.',
+
+ 'UI:CSVExport:AdvancedMode' => 'Advanced mode',
+ 'UI:CSVExport:AdvancedMode+' => 'In advanced mode, several columns are added to the export: the id of the object, the id of external keys and their reconciliation attributes.',
+ 'UI:CSVExport:LostChars' => 'Encoding issue',
+ 'UI:CSVExport:LostChars+' => 'The downloaded file will be encoded into %1$s. iTop has detected some characters that are not compatible with this format. Those characters will either be replaced by a substitute (e.g. accentuated chars losing the accent), or they will be discarded. You can copy/paste the data from your web browser. Alternatively, you can contact your administrator to change the encoding (See parameter \'csv_file_default_charset\').',
+
'UI:Audit:Title' => 'iTop - CMDB Audit',
'UI:Audit:InteractiveAudit' => 'Interactive Audit',
'UI:Audit:HeaderAuditRule' => 'Audit Rule',
@@ -870,6 +916,7 @@ When associated with a trigger, each action is given an "order" number, specifyi
'UI:OpenDocumentInNewWindow_' => 'Open this document in a new window: %1$s',
'UI:DownloadDocument_' => 'Download this document: %1$s',
'UI:Document:NoPreview' => 'No preview is available for this type of document',
+ 'UI:Download-CSV' => 'Download %1$s',
'UI:DeadlineMissedBy_duration' => 'Missed by %1$s',
'UI:Deadline_LessThan1Min' => '< 1 min',
diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php
index 0ee6b2230..ecfbed56b 100644
--- a/dictionaries/fr.dictionary.itop.ui.php
+++ b/dictionaries/fr.dictionary.itop.ui.php
@@ -423,6 +423,53 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:CSVImport:AlertIncompleteMapping' => 'Veuillez choisir le correspondance de chacun des champs.',
'UI:CSVImport:AlertNoSearchCriteria' => 'Veuillez choisir au moins une clef de recherche.',
'UI:CSVImport:Encoding' => 'Encodage des caractères',
+
+ 'UI:CSVReport-Value-Modified' => 'Modifié',
+ 'UI:CSVReport-Value-SetIssue' => 'Modification impossible - cause : %1$s',
+ 'UI:CSVReport-Value-ChangeIssue' => 'Ne peut pas prendre la valeur \'%1$s\' - cause : %2$s',
+ 'UI:CSVReport-Value-NoMatch' => 'Pas de correspondance',
+ 'UI:CSVReport-Value-Missing' => 'Absence de valeur obligatoire',
+ 'UI:CSVReport-Value-Ambiguous' => 'Ambigüité: %1$d objets trouvés',
+ 'UI:CSVReport-Row-Unchanged' => 'inchangé',
+ 'UI:CSVReport-Row-Created' => 'créé',
+ 'UI:CSVReport-Row-Updated' => '%1$d colonnes modifiées',
+ 'UI:CSVReport-Row-Disappeared' => 'disparu, %1$d colonnes modifiées',
+ 'UI:CSVReport-Row-Issue' => 'Erreur: %1$s',
+ 'UI:CSVReport-Value-Issue-Null' => 'Valeur obligatoire',
+ 'UI:CSVReport-Value-Issue-NotFound' => 'Objet non trouvé',
+ 'UI:CSVReport-Value-Issue-FoundMany' => 'Plusieurs objets trouvés (%1$d)',
+ 'UI:CSVReport-Value-Issue-Readonly' => 'L\'attribut \'%1$s\' est en lecture seule (valeur courante: %2$s, valeur proposée: %3$s)',
+ 'UI:CSVReport-Value-Issue-Format' => 'Echec de traitement de la valeur: %1$s',
+ 'UI:CSVReport-Value-Issue-NoMatch' => 'Valeur incorrecte pour \'%1$s\': pas de correspondance, veuillez vérifier la syntaxe',
+ 'UI:CSVReport-Value-Issue-Unknown' => 'Valeur incorrecte pour \'%1$s\': %2$s',
+ 'UI:CSVReport-Row-Issue-Inconsistent' => 'Incohérence entre attributs: %1$s',
+ 'UI:CSVReport-Row-Issue-Attribute' => 'Des attributs ont des valeurs incorrectes',
+ 'UI:CSVReport-Row-Issue-MissingExtKey' => 'Ne peut pas être créé car il manque des clés externes : %1$s',
+ 'UI:CSVReport-Row-Issue-DateFormat' => 'Format de date incorrect',
+ 'UI:CSVReport-Row-Issue-Reconciliation' => 'Echec de réconciliation',
+ 'UI:CSVReport-Row-Issue-Ambiguous' => 'Réconciliation ambigüe',
+ 'UI:CSVReport-Row-Issue-Internal' => 'Erreur interne: %1$s, %2$s',
+
+ 'UI:CSVReport-Icon-Unchanged' => 'Non modifié',
+ 'UI:CSVReport-Icon-Modified' => 'Modifié',
+ 'UI:CSVReport-Icon-Missing' => 'A disparu',
+ 'UI:CSVReport-Object-MissingToUpdate' => 'Objet disparu: sera modifié',
+ 'UI:CSVReport-Object-MissingUpdated' => 'Objet disparu: modifié',
+ 'UI:CSVReport-Icon-Created' => 'Créé',
+ 'UI:CSVReport-Object-ToCreate' => 'L\'objet sera créé',
+ 'UI:CSVReport-Object-Created' => 'Objet créé',
+ 'UI:CSVReport-Icon-Error' => 'Erreur',
+ 'UI:CSVReport-Object-Error' => 'Erreur: %1$s',
+ 'UI:CSVReport-Object-Ambiguous' => 'Ambigüité: %1$s',
+ 'UI:CSVReport-Stats-Errors' => '%1$.0f %% des lignes chargées sont en erreur et seront ignorées.',
+ 'UI:CSVReport-Stats-Created' => '%1$.0f %% des lignes chargées vont engendrer un nouvel objet.',
+ 'UI:CSVReport-Stats-Modified' => '%1$.0f %% des lignes chargées vont modifier un objet.',
+
+ 'UI:CSVExport:AdvancedMode' => 'Mode expert',
+ 'UI:CSVExport:AdvancedMode+' => 'Dans le mode expert, des colonnes supplémentaires apparaissent: l\'identifiant de l\'objet, la valeur des clés externes et leurs attributs de reconciliation.',
+ 'UI:CSVExport:LostChars' => 'Problème d\'encodage',
+ 'UI:CSVExport:LostChars+' => 'Le fichier téléchargé sera encodé en %1$s. iTop a détecté des caractères incompatible avec ce format. Ces caractères seront soit remplacés par des caractères de substitution (par exemple: \'é\' transformé en \'e\'), soit perdus. Vous pouvez utiliser le copier/coller depuis votre navigateur web, ou bien contacter votre administrateur pour que l\'encodage corresponde mieux à votre besoin (Cf. paramètre \'csv_file_default_charset\').',
+
'UI:UniversalSearchTitle' => 'iTop - Recherche Universelle',
'UI:UniversalSearch:Error' => 'Erreur : %1$s',
'UI:UniversalSearch:LabelSelectTheClass' => 'Sélectionnez le type d\'objets à rechercher : ',
@@ -716,6 +763,7 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
'UI:OpenDocumentInNewWindow_' => 'Ouvrir ce document dans uns autre fenêtre: %1$s',
'UI:DownloadDocument_' => 'Télécharger ce document: %1$s',
'UI:Document:NoPreview' => 'L\'aperçu n\'est pas disponible pour ce type de documents',
+ 'UI:Download-CSV' => 'Télécharger %1$s',
'UI:DeadlineMissedBy_duration' => 'Passé de %1$s',
'UI:Deadline_LessThan1Min' => '< 1 min',
'UI:Deadline_Minutes' => '%1$d min',
diff --git a/pages/ajax.csvimport.php b/pages/ajax.csvimport.php
index e1836f498..c27089e94 100644
--- a/pages/ajax.csvimport.php
+++ b/pages/ajax.csvimport.php
@@ -98,9 +98,10 @@ function GetMappingsForExtKey($sAttCode, AttributeDefinition $oExtKeyAttDef, $bA
* @param string $sFieldName Name of the field, as it comes from the data file (header line)
* @param integer $iFieldIndex Number of the field in the sequence
* @param bool $bAdvancedMode Whether or not advanced mode was chosen
+ * @param string $sDefaultChoice If set, this will be the item selected by default
* @return string The HTML code corresponding to the drop-down list for this field
*/
-function GetMappingForField($sClassName, $sFieldName, $iFieldIndex, $bAdvancedMode = false)
+function GetMappingForField($sClassName, $sFieldName, $iFieldIndex, $bAdvancedMode, $sDefaultChoice)
{
$aChoices = array('' => Dict::S('UI:CSVImport:MappingSelectOne'));
$aChoices[':none:'] = Dict::S('UI:CSVImport:MappingNotApplicable');
@@ -178,7 +179,7 @@ function GetMappingForField($sClassName, $sFieldName, $iFieldIndex, $bAdvancedMo
}
}
asort($aChoices);
-
+
$sHtml = "