diff options
Diffstat (limited to 'www/wiki/extensions/SemanticMediaWiki/includes/datavalues/SMW_DV_Quantity.php')
-rw-r--r-- | www/wiki/extensions/SemanticMediaWiki/includes/datavalues/SMW_DV_Quantity.php | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/www/wiki/extensions/SemanticMediaWiki/includes/datavalues/SMW_DV_Quantity.php b/www/wiki/extensions/SemanticMediaWiki/includes/datavalues/SMW_DV_Quantity.php new file mode 100644 index 00000000..75e1dc57 --- /dev/null +++ b/www/wiki/extensions/SemanticMediaWiki/includes/datavalues/SMW_DV_Quantity.php @@ -0,0 +1,218 @@ +<?php + +use SMW\DataValues\Number\UnitConverter; +use SMW\Message; + +/** + * @ingroup SMWDataValues + */ + +/** + * This datavalue implements unit support custom units, for which users have + * provided linear conversion factors within the wiki. Those user settings + * are retrieved from a property page associated with this object. + * + * @author Markus Krötzsch + * @ingroup SMWDataValues + */ +class SMWQuantityValue extends SMWNumberValue { + + /** + * DV identifier + */ + const TYPE_ID = '_qty'; + + /** + * Array with format (canonical unit ID string) => (conversion factor) + * @var float[]|bool + */ + protected $m_unitfactors = false; + + /** + * Array with format (normalised unit string) => (canonical unit ID string) + * @var string[]|bool + */ + protected $m_unitids = false; + + /** + * Ordered array of (normalized) units that should be displayed in tooltips, etc. + * @var string[]|bool + */ + protected $m_displayunits = false; + + /** + * Main unit in canonical form (recognised by the conversion factor 1) + * @var string|bool + */ + protected $m_mainunit = false; + + protected function convertToMainUnit( $number, $unit ) { + $this->initConversionData(); + + if ( array_key_exists( $unit, $this->m_unitids ) ) { + $this->m_unitin = $this->m_unitids[$unit]; + assert( $this->m_unitfactors[$this->m_unitin] != 0 /* Should be filtered by initConversionData() */ ); + $this->m_dataitem = new SMWDINumber( $number / $this->m_unitfactors[$this->m_unitin], $this->m_typeid ); + return true; + } else { // unsupported unit + return false; + } + } + + protected function makeConversionValues() { + if ( $this->m_unitvalues !== false ) { + return; // do this only once + } + + $this->m_unitvalues = []; + + if ( !$this->isValid() ) { + return; + } + + $this->initDisplayData(); + + if ( count( $this->m_displayunits ) == 0 ) { // no display units, just show all + foreach ( $this->m_unitfactors as $unit => $factor ) { + if ( $unit !== '' ) { // filter out the empty fallback unit that is always there + $this->m_unitvalues[$unit] = $this->m_dataitem->getNumber() * $factor; + } + } + } else { + foreach ( $this->m_displayunits as $unit ) { + /// NOTE We keep non-ID units unless the input unit is used, so display units can be used to pick + /// the preferred form of a unit. Doing this requires us to recompute the conversion values whenever + /// the m_unitin changes. + $unitkey = ( $this->m_unitids[$unit] == $this->m_unitin ) ? $this->m_unitids[$unit] : $unit; + $this->m_unitvalues[$unitkey] = $this->m_dataitem->getNumber() * $this->m_unitfactors[$this->m_unitids[$unit]]; + } + } + } + + protected function makeUserValue() { + + // The normalised string of a known unit to use for printouts + $printunit = false; + $unitfactor = 1; + + // Check if a known unit is given as outputformat: + if ( ( $this->m_outformat ) && ( $this->m_outformat != '-' ) && + ( $this->m_outformat != '-n' ) && ( $this->m_outformat != '-u' ) ) { // first try given output unit + $wantedunit = $this->normalizeUnit( $this->m_outformat ); + if ( array_key_exists( $wantedunit, $this->m_unitids ) ) { + $printunit = $wantedunit; + } + } + + // Alternatively, try to use the main display unit as a default: + if ( $printunit === false ) { + $this->initDisplayData(); + if ( count( $this->m_displayunits ) > 0 ) { + $printunit = reset( $this->m_displayunits ); + } + } + // Finally, fall back to main unit: + if ( $printunit === false ) { + $printunit = $this->getUnit(); + } + + $asPrefix = isset( $this->prefixalUnitPreference[$printunit] ) && $this->prefixalUnitPreference[$printunit]; + $this->m_unitin = isset( $this->m_unitids[$printunit] ) ? $this->m_unitids[$printunit] : 0; + + // This array depends on m_unitin if displayunits were used, better + // invalidate it here + $this->m_unitvalues = false; + $this->m_caption = ''; + + if ( isset( $this->m_unitfactors[$this->m_unitin] ) ) { + $unitfactor = $this->m_unitfactors[$this->m_unitin]; + } + + $value = $this->m_dataitem->getNumber() * $unitfactor; + + // -u is the format for displaying the unit only + if ( $this->m_outformat != '-u' ) { + $this->m_caption .= ( ( $this->m_outformat != '-' ) && ( $this->m_outformat != '-n' ) ? $this->getLocalizedFormattedNumber( $value ) : $this->getNormalizedFormattedNumber( $value ) ); + } + + // -n is the format for displaying the number only + if ( ( $printunit !== '' ) && ( $this->m_outformat != '-n' ) ) { + + $sep = ''; + + if ( $this->m_outformat != '-u' ) { + $sep = ( $this->m_outformat != '-' ? ' ' : ' ' ); + } + + $this->m_caption = $asPrefix ? $printunit . $sep . $this->m_caption : $this->m_caption . $sep . $printunit; + } + } + + public function getUnitList() { + $this->initConversionData(); + return array_keys( $this->m_unitfactors ); + } + + public function getUnit() { + $this->initConversionData(); + return $this->m_mainunit; + } + +/// The remaining functions are relatively "private" but are kept protected since +/// subclasses might exploit this to, e.g., "fake" conversion factors instead of +/// getting them from the database. A cheap way of making built-in types. + + /** + * This method initializes $m_unitfactors, $m_unitids, and $m_mainunit. + */ + protected function initConversionData() { + + if ( $this->m_unitids !== false ) { + return; + } + + $unitConverter = new UnitConverter( $this ); + $unitConverter->initConversionData( $this->m_property ); + + if ( $unitConverter->getErrors() !== [] ) { + foreach ( $unitConverter->getErrors() as $error ) { + $this->addErrorMsg( + $error, + Message::TEXT, + Message::USER_LANGUAGE + ); + } + } + + $this->m_unitids = $unitConverter->getUnitIds(); + $this->m_unitfactors = $unitConverter->getUnitFactors(); + $this->m_mainunit = $unitConverter->getMainUnit(); + $this->prefixalUnitPreference = $unitConverter->getPrefixalUnitPreference(); + } + + /** + * This method initializes $m_displayunits. + */ + protected function initDisplayData() { + if ( $this->m_displayunits !== false ) { + return; // do the below only once + } + $this->initConversionData(); // needed to normalise unit strings + $this->m_displayunits = []; + + if ( is_null( $this->m_property ) || is_null( $this->m_property->getDIWikiPage() ) ) { + return; + } + + $units = $this->dataValueServiceFactory->getPropertySpecificationLookup()->getDisplayUnits( + $this->getProperty() + ); + + foreach ( $units as $unit ) { + $unit = $this->normalizeUnit( $unit ); + if ( array_key_exists( $unit, $this->m_unitids ) ) { + $this->m_displayunits[] = $unit; // do not avoid duplicates, users can handle this + } // note: we ignore unsuppported units -- no way to display them + } + } +} |