diff options
Diffstat (limited to 'www/wiki/extensions/SemanticResultFormats/src/Graph/GraphPrinter.php')
-rw-r--r-- | www/wiki/extensions/SemanticResultFormats/src/Graph/GraphPrinter.php | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/www/wiki/extensions/SemanticResultFormats/src/Graph/GraphPrinter.php b/www/wiki/extensions/SemanticResultFormats/src/Graph/GraphPrinter.php new file mode 100644 index 00000000..91def23d --- /dev/null +++ b/www/wiki/extensions/SemanticResultFormats/src/Graph/GraphPrinter.php @@ -0,0 +1,419 @@ +<?php + +namespace SRF\Graph; + +use SMWResultPrinter; +use SMWQueryResult; +use SMWDataValue; +use SMWWikiPageValue; + +/** + * SMW result printer for graphs using graphViz. + * In order to use this printer you need to have both + * the graphViz library installed on your system and + * have the graphViz MediaWiki extension installed. + * + * @file SRF_Graph.php + * @ingroup SemanticResultFormats + * + * @licence GNU GPL v2+ + * @author Frank Dengler + * @author Jeroen De Dauw < jeroendedauw@gmail.com > + */ +class GraphPrinter extends SMWResultPrinter { + + const NODELABEL_DISPLAYTITLE = 'displaytitle'; + + public static $NODE_LABELS = [ + self::NODELABEL_DISPLAYTITLE, + ]; + + public static $NODE_SHAPES = [ + 'box', + 'box3d', + 'circle', + 'component', + 'diamond', + 'doublecircle', + 'doubleoctagon', + 'egg', + 'ellipse', + 'folder', + 'hexagon', + 'house', + 'invhouse', + 'invtrapezium', + 'invtriangle', + 'Mcircle', + 'Mdiamond', + 'Msquare', + 'none', + 'note', + 'octagon', + 'parallelogram', + 'pentagon ', + 'plaintext', + 'point', + 'polygon', + 'rect', + 'rectangle', + 'septagon', + 'square', + 'tab', + 'trapezium', + 'triangle', + 'tripleoctagon', + ]; + + protected $m_graphName; + protected $m_graphLabel; + protected $m_graphColor; + protected $m_graphLegend; + protected $m_graphLink; + protected $m_rankdir; + protected $m_graphSize; + protected $m_labelArray = []; + protected $m_graphColors = [ + 'black', + 'red', + 'green', + 'blue', + 'darkviolet', + 'gold', + 'deeppink', + 'brown', + 'bisque', + 'darkgreen', + 'yellow', + 'darkblue', + 'magenta', + 'steelblue2' ]; + protected $m_nameProperty; + protected $m_nodeShape; + protected $m_parentRelation; + protected $m_wordWrapLimit; + protected $m_nodeLabel; + + /** + * (non-PHPdoc) + * @see SMWResultPrinter::handleParameters() + */ + protected function handleParameters( array $params, $outputmode ) { + parent::handleParameters( $params, $outputmode ); + + $this->m_graphName = trim( $params['graphname'] ); + $this->m_graphSize = trim( $params['graphsize'] ); + + $this->m_graphLegend = $params['graphlegend']; + $this->m_graphLabel = $params['graphlabel']; + + $this->m_rankdir = strtoupper( trim( $params['arrowdirection'] ) ); + + $this->m_graphLink = $params['graphlink']; + $this->m_graphColor = $params['graphcolor']; + + $this->m_nameProperty = $params['nameproperty'] === false ? false : trim( $params['nameproperty'] ); + + $this->m_parentRelation = strtolower( trim( $params['relation'] ) ) == 'parent'; + + $this->m_nodeShape = $params['nodeshape']; + $this->m_wordWrapLimit = $params['wordwraplimit']; + + $this->m_nodeLabel = $params['nodelabel']; + } + + protected function getResultText( SMWQueryResult $res, $outputmode ) { + + if ( !class_exists( 'GraphViz' ) + && !class_exists( '\\MediaWiki\\Extension\\GraphViz\\GraphViz' ) + ) { + wfWarn( 'The SRF Graph printer needs the GraphViz extension to be installed.' ); + return ''; + } + + $this->isHTML = true; + + $graphInput = "digraph $this->m_graphName {"; + if ( $this->m_graphSize != '' ) { + $graphInput .= "size=\"$this->m_graphSize\";"; + } + if ( $this->m_nodeShape ) { + $graphInput .= "node [shape=$this->m_nodeShape];"; + } + $graphInput .= "rankdir=$this->m_rankdir;"; + + while ( $row = $res->getNext() ) { + $graphInput .= $this->getGVForItem( $row, $outputmode ); + } + + $graphInput .= "}"; + + // Calls graphvizParserHook function from MediaWiki GraphViz extension + $result = $GLOBALS['wgParser']->recursiveTagParse( "<graphviz>$graphInput</graphviz>" ); + + if ( $this->m_graphLegend && $this->m_graphColor ) { + $arrayCount = 0; + $arraySize = count( $this->m_graphColors ); + $result .= "<P>"; + + foreach ( $this->m_labelArray as $m_label ) { + if ( $arrayCount >= $arraySize ) { + $arrayCount = 0; + } + + $color = $this->m_graphColors[$arrayCount]; + $result .= "<font color=$color>$color: $m_label </font><br />"; + + $arrayCount += 1; + } + + $result .= "</P>"; + } + + return $result; + } + + /** + * Returns the GV for a single subject. + * + * @since 1.5.4 + * + * @param array $row + * @param $outputmode + * + * @return string + */ + protected function getGVForItem( array /* of SMWResultArray */ + $row, $outputmode ) { + $segments = []; + + // Loop throught all fields of the record. + foreach ( $row as $i => $resultArray ) { + + // Loop throught all the parts of the field value. + while ( ( $object = $resultArray->getNextDataValue() ) !== false ) { + $propName = $resultArray->getPrintRequest()->getLabel(); + $isName = $this->m_nameProperty ? ( $i != 0 && $this->m_nameProperty === $propName ) : $i == 0; + + if ( $isName ) { + $name = $this->getWordWrappedText( $object->getShortText( $outputmode ), $this->m_wordWrapLimit ); + } + + if ( !( $this->m_nameProperty && $i == 0 ) ) { + $segments[] = $this->getGVForDataValue( $object, $outputmode, $isName, $name, $propName ); + } + } + } + + return implode( "\n", $segments ); + } + + /** + * Returns the GV for a single SMWDataValue. + * + * @since 1.5.4 + * + * @param SMWDataValue $object + * @param $outputmode + * @param boolean $isName Is this the name that should be used for the node? + * @param string $name + * @param string $labelName + * + * @return string + */ + protected function getGVForDataValue( SMWDataValue $object, $outputmode, $isName, $name, $labelName ) { + $graphInput = ''; + $nodeLabel = ''; + $text = $object->getShortText( $outputmode ); + + if ( $this->m_graphLink ) { + $nodeLinkURL = "[[" . $text . "]]"; + } + + $text = $this->getWordWrappedText( $text, $this->m_wordWrapLimit ); + + if ( $this->m_nodeLabel === self::NODELABEL_DISPLAYTITLE && $object instanceof SMWWikiPageValue ) { + $objectDisplayTitle = $object->getDisplayTitle(); + if ( !empty( $objectDisplayTitle )) { + $nodeLabel = $this->getWordWrappedText( $objectDisplayTitle, $this->m_wordWrapLimit ); + } + } + + if ( $this->m_graphLink ) { + if( $nodeLabel === '' ) { + $graphInput .= " \"$text\" [URL = \"$nodeLinkURL\"]; "; + } else { + $graphInput .= " \"$text\" [URL = \"$nodeLinkURL\", label = \"$nodeLabel\"]; "; + } + } + + if ( !$isName ) { + $graphInput .= $this->m_parentRelation ? " \"$text\" -> \"$name\" " : " \"$name\" -> \"$text\" "; + + if ( $this->m_graphLabel || $this->m_graphColor ) { + $graphInput .= ' ['; + + if ( array_search( $labelName, $this->m_labelArray, true ) === false ) { + $this->m_labelArray[] = $labelName; + } + + $color = $this->m_graphColors[array_search( $labelName, $this->m_labelArray, true )]; + + if ( $this->m_graphLabel ) { + $graphInput .= "label=\"$labelName\""; + if ( $this->m_graphColor ) { + $graphInput .= ",fontcolor=$color,"; + } + } + + if ( $this->m_graphColor ) { + $graphInput .= "color=$color"; + } + + $graphInput .= ']'; + + } + + $graphInput .= ';'; + } + + return $graphInput; + } + + /** + * Returns the word wrapped version of the provided text. + * + * @since 1.5.4 + * + * @param string $text + * @param integer $charLimit + * + * @return string + */ + protected function getWordWrappedText( $text, $charLimit ) { + $charLimit = max( [ $charLimit, 1 ] ); + $segments = []; + + while ( strlen( $text ) > $charLimit ) { + // Find the last space in the allowed range. + $splitPosition = strrpos( substr( $text, 0, $charLimit ), ' ' ); + + if ( $splitPosition === false ) { + // If there is no space (lond word), find the next space. + $splitPosition = strpos( $text, ' ' ); + + if ( $splitPosition === false ) { + // If there are no spaces, everything goes on one line. + $splitPosition = strlen( $text ) - 1; + } + } + + $segments[] = substr( $text, 0, $splitPosition + 1 ); + $text = substr( $text, $splitPosition + 1 ); + } + + $segments[] = $text; + + return implode( '\n', $segments ); + } + + /** + * (non-PHPdoc) + * @see SMWResultPrinter::getName() + */ + public function getName() { + return wfMessage( 'srf-printername-graph' )->text(); + } + + /** + * @see SMWResultPrinter::getParamDefinitions + * + * @since 1.8 + * + * @param $definitions array of IParamDefinition + * + * @return array of IParamDefinition|array + */ + public function getParamDefinitions( array $definitions ) { + $params = parent::getParamDefinitions( $definitions ); + + $params['graphname'] = [ + 'default' => 'QueryResult', + 'message' => 'srf-paramdesc-graphname', + ]; + + $params['graphsize'] = [ + 'type' => 'string', + 'default' => '', + 'message' => 'srf-paramdesc-graphsize', + 'manipulatedefault' => false, + ]; + + $params['graphlegend'] = [ + 'type' => 'boolean', + 'default' => false, + 'message' => 'srf-paramdesc-graphlegend', + ]; + + $params['graphlabel'] = [ + 'type' => 'boolean', + 'default' => false, + 'message' => 'srf-paramdesc-graphlabel', + ]; + + $params['graphlink'] = [ + 'type' => 'boolean', + 'default' => false, + 'message' => 'srf-paramdesc-graphlink', + ]; + + $params['graphcolor'] = [ + 'type' => 'boolean', + 'default' => false, + 'message' => 'srf-paramdesc-graphcolor', + ]; + + $params['arrowdirection'] = [ + 'aliases' => 'rankdir', + 'default' => 'LR', + 'message' => 'srf-paramdesc-rankdir', + 'values' => [ 'LR', 'RL', 'TB', 'BT' ], + ]; + + $params['nodeshape'] = [ + 'default' => false, + 'message' => 'srf-paramdesc-graph-nodeshape', + 'manipulatedefault' => false, + 'values' => self::$NODE_SHAPES, + ]; + + $params['relation'] = [ + 'default' => 'child', + 'message' => 'srf-paramdesc-graph-relation', + 'manipulatedefault' => false, + 'values' => [ 'parent', 'child' ], + ]; + + $params['nameproperty'] = [ + 'default' => false, + 'message' => 'srf-paramdesc-graph-nameprop', + 'manipulatedefault' => false, + ]; + + $params['wordwraplimit'] = [ + 'type' => 'integer', + 'default' => 25, + 'message' => 'srf-paramdesc-graph-wwl', + 'manipulatedefault' => false, + ]; + + $params['nodelabel'] = [ + 'default' => '', + 'message' => 'srf-paramdesc-nodelabel', + 'values' => self::$NODE_LABELS, + ]; + + return $params; + } + +} |