[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.4' - filter/source

Marco Cecchetti (via logerrit) logerrit at kemper.freedesktop.org
Tue Jan 19 13:21:18 UTC 2021


 filter/source/svg/presentation_engine.js |  158 +++++++++++++++++++++++++------
 filter/source/svg/svgwriter.cxx          |   35 ++++++
 filter/source/svg/svgwriter.hxx          |    1 
 3 files changed, 164 insertions(+), 30 deletions(-)

New commits:
commit 736f6906abe5cca474c256add07ba54e144cb8f1
Author:     Marco Cecchetti <marco.cecchetti at collabora.com>
AuthorDate: Sun Jan 17 23:36:53 2021 +0100
Commit:     Ashod Nakashian <ash at collabora.com>
CommitDate: Tue Jan 19 14:20:37 2021 +0100

    filter: svg: js engine: improving text fields handling
    
    Added support for slide number and current date, current time fields
    inserted by the user on slides or master pages.
    
    Change-Id: If21b06c58e8fdcc240a540ee6fa87f48a6eb86af
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/109496
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Ashod Nakashian <ash at collabora.com>

diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 848f2dd84226..c1a6a4ef988e 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -4458,6 +4458,8 @@ var aSlideNumberClassName = 'Slide_Number';
 var aDateTimeClassName = 'Date/Time';
 var aFooterClassName = 'Footer';
 var aHeaderClassName = 'Header';
+var aDateClassName = 'Date';
+var aTimeClassName = 'Time';
 
 // Creating a namespace dictionary.
 var NSS = {};
@@ -4909,6 +4911,8 @@ function MetaDocument()
     this.aTextFieldHandlerSet = {};
     this.aTextFieldContentProviderSet = [];
     this.aSlideNumberProvider = new SlideNumberProvider( this.nStartSlideNumber + 1, this.sPageNumberingType );
+    this.aCurrentDateProvider = new CurrentDateTimeProvider( null, '<date>' );
+    this.aCurrentTimeProvider = new CurrentDateTimeProvider( null, '<time>' );
 
     // We create a map with key an id and value the svg element containing
     // the animations performed on the slide with such an id.
@@ -5064,6 +5068,9 @@ function MetaSlide( sMetaSlideId, aMetaDoc )
         this.backgroundId = this.backgroundElement.getAttribute( 'id' );
     }
 
+    // We initialize text fields
+    this.initPlaceholderElements();
+
     // We initialize the MasterPage object that provides direct access to
     // the target master page element.
     this.masterPage = this.initMasterPage();
@@ -5090,6 +5097,8 @@ function MetaSlide( sMetaSlideId, aMetaDoc )
     this.aTextFieldContentProviderSet[aDateTimeClassName]      = this.initDateTimeFieldContentProvider( aOOOAttrDateTimeField );
     this.aTextFieldContentProviderSet[aFooterClassName]        = this.initFixedTextFieldContentProvider( aOOOAttrFooterField );
     this.aTextFieldContentProviderSet[aHeaderClassName]        = this.initFixedTextFieldContentProvider( aOOOAttrHeaderField );
+    this.aTextFieldContentProviderSet[aDateClassName]          = this.theMetaDoc.aCurrentDateProvider;
+    this.aTextFieldContentProviderSet[aTimeClassName]          = this.theMetaDoc.aCurrentTimeProvider;
 
     // We init the slide duration when automatic slide transition is enabled
     this.fDuration = this.initSlideDuration();
@@ -5160,6 +5169,23 @@ updateMasterPageView : function()
 },
 
 /*** private methods ***/
+
+// It handles a text field inserted on a slide, not on a master page.
+initPlaceholderElements : function()
+{
+    var aPlaceholderList = getElementsByClassName(this.pageElement , 'PlaceholderText' );
+    var i = 0;
+    for( ; i < aPlaceholderList.length; ++i )
+    {
+        var aPlaceholderElem = aPlaceholderList[i];
+        var sContent = aPlaceholderElem.textContent;
+        if( sContent === '<date>' )
+            aPlaceholderElem.textContent = new Date().toLocaleDateString();
+        else if( sContent === '<time>' )
+            aPlaceholderElem.textContent = new Date().toLocaleTimeString();
+    }
+},
+
 initMasterPage : function()
 {
     var sMasterPageId = this.element.getAttributeNS( NSS['ooo'], aOOOAttrMaster );
@@ -5336,6 +5362,34 @@ getSlideAnimationsRoot : function()
 
 }; // end MetaSlide prototype
 
+function getTextFieldType ( elem )
+{
+    var sFieldType = null;
+    var sClass = elem.getAttribute('class');
+    if( sClass.endsWith( 'TextShape' ) )
+    {
+        var aPlaceholderElement = getElementByClassName( elem, 'PlaceholderText' );
+        if (aPlaceholderElement)
+        {
+            var sContent = aPlaceholderElement.textContent
+            if (sContent === '<number>')
+                sFieldType = aSlideNumberClassName;
+            else if (sContent === '<date>')
+                sFieldType = aDateClassName;
+            else if (sContent === '<time>')
+                sFieldType = aTimeClassName;
+        }
+    }
+    return sFieldType;
+}
+
+function isTextFieldByClassName ( sClassName )
+{
+    return sClassName === aDateTimeClassName || sClassName === aFooterClassName
+        || sClassName === aHeaderClassName || sClassName.startsWith( aSlideNumberClassName )
+        || sClassName.startsWith( aDateClassName ) || sClassName.startsWith( aTimeClassName );
+}
+
 /** Class MasterPage
  *  This class gives direct access to a master page element and to the following
  *  elements included in the master page:
@@ -5398,6 +5452,7 @@ function MasterPage( sMasterPageId, aMetaSlide )
     // The background objects group element that contains every element presents
     // on the master page except the background element.
     this.backgroundObjects = getElementByClassName( this.element, 'BackgroundObjects' );
+    this.aBackgroundObjectSubGroupIdList = [];
     if( this.backgroundObjects )
     {
         this.backgroundObjectsId = this.backgroundObjects.getAttribute( 'id' );
@@ -5411,13 +5466,26 @@ function MasterPage( sMasterPageId, aMetaSlide )
             var nSubGroupId = 1;
             var sClass;
             var sId = '';
-            this.aBackgroundObjectSubGroupIdList = [];
             var i = 0;
             for( ; i < aBackgroundObjectList.length; ++i )
             {
-                sClass = aBackgroundObjectList[i].getAttribute( 'class' );
-                if( !sClass || ( ( sClass !== aDateTimeClassName ) && ( sClass !== aFooterClassName )
-                                     && ( sClass !== aHeaderClassName ) && ( sClass !== aSlideNumberClassName ) ) )
+                var aObject = aBackgroundObjectList[i];
+                sClass = null;
+                var sFieldType = getTextFieldType( aObject );
+                if( sFieldType && aObject.firstElementChild )
+                {
+                    var sObjId = aObject.firstElementChild.getAttribute( 'id' );
+                    if( sObjId )
+                    {
+                         sClass = sFieldType + '.' + sObjId;
+                         aObject.setAttribute('class', sClass);
+                    }
+                }
+                if( !sClass )
+                {
+                    sClass = aBackgroundObjectList[i].getAttribute('class');
+                }
+                if( !sClass || !isTextFieldByClassName( sClass ) )
                 {
                     if( nCount === 0 )
                     {
@@ -5461,10 +5529,14 @@ MasterPage.prototype =
 
 initPlaceholderShapes : function()
 {
-    this.aPlaceholderShapeSet[ aSlideNumberClassName ] = new PlaceholderShape( this, aSlideNumberClassName );
-    this.aPlaceholderShapeSet[ aDateTimeClassName ] = new PlaceholderShape( this, aDateTimeClassName );
-    this.aPlaceholderShapeSet[ aFooterClassName ] = new PlaceholderShape( this, aFooterClassName );
-    this.aPlaceholderShapeSet[ aHeaderClassName ] = new PlaceholderShape( this, aHeaderClassName );
+    var sClassName;
+    var i = 0;
+    for( ; i < this.aBackgroundObjectSubGroupIdList.length; ++i )
+    {
+        sClassName = this.aBackgroundObjectSubGroupIdList[i];
+        if( isTextFieldByClassName( sClassName ) )
+            this.aPlaceholderShapeSet[ sClassName ] = new PlaceholderShape( this, sClassName );
+    }
 }
 
 }; // end MasterPage prototype
@@ -5708,22 +5780,25 @@ MasterPageView.prototype.createElement = function()
         for( ; i < aBackgroundObjectSubGroupIdList.length; ++i )
         {
             sId = aBackgroundObjectSubGroupIdList[i];
-            if( sId === aSlideNumberClassName )
+            if( sId.startsWith( aSlideNumberClassName ) )
             {
                 // Slide Number Field
                 // The cloned element is appended directly to the field group element
                 // since there is no slide number field content shared between two slide
                 // (because the slide number of two slide is always different).
-                if( aPlaceholderShapeSet[aSlideNumberClassName] &&
-                    aPlaceholderShapeSet[aSlideNumberClassName].isValid() &&
-                    this.aMetaSlide.nIsPageNumberVisible &&
+                var nIsPageNumberVisible = sId === aSlideNumberClassName ? this.aMetaSlide.nIsPageNumberVisible : true;
+                if( aPlaceholderShapeSet[sId] &&
+                    aPlaceholderShapeSet[sId].isValid() &&
+                    nIsPageNumberVisible &&
                     aTextFieldContentProviderSet[aSlideNumberClassName] )
                 {
-                    this.aSlideNumberFieldHandler =
-                        new SlideNumberFieldHandler( aPlaceholderShapeSet[aSlideNumberClassName],
-                                                     aTextFieldContentProviderSet[aSlideNumberClassName] );
-                    this.aSlideNumberFieldHandler.update( this.aMetaSlide.nSlideNumber );
-                    this.aSlideNumberFieldHandler.appendTo( this.aBackgroundObjectsElement );
+                    var aSlideNumberFieldHandler =
+                        new SlideNumberFieldHandler( aPlaceholderShapeSet[sId],
+                            aTextFieldContentProviderSet[aSlideNumberClassName] );
+                    aSlideNumberFieldHandler.update( this.aMetaSlide.nSlideNumber );
+                    aSlideNumberFieldHandler.appendTo( this.aBackgroundObjectsElement );
+                    if ( sId === aSlideNumberClassName )
+                        this.aSlideNumberFieldHandler = aSlideNumberFieldHandler;
                 }
             }
             else if( sId === aDateTimeClassName )
@@ -5759,6 +5834,18 @@ MasterPageView.prototype.createElement = function()
                                                    aTextFieldHandlerSet, sMasterSlideId );
                 }
             }
+            else if( sId.startsWith( aDateClassName ) )
+            {
+                this.initTextFieldHandler( sId, aPlaceholderShapeSet,
+                                           aTextFieldContentProviderSet, aDefsElement,
+                                           aTextFieldHandlerSet, sMasterSlideId );
+            }
+            else if( sId.startsWith( aTimeClassName ) )
+            {
+                this.initTextFieldHandler( sId, aPlaceholderShapeSet,
+                                           aTextFieldContentProviderSet, aDefsElement,
+                                           aTextFieldHandlerSet, sMasterSlideId );
+            }
             else
             {
                 // init BackgroundObjectSubGroup elements
@@ -5780,23 +5867,25 @@ MasterPageView.prototype.createElement = function()
 };
 
 MasterPageView.prototype.initTextFieldHandler =
-    function( sClassName, aPlaceholderShapeSet, aTextFieldContentProviderSet,
+    function( sId, aPlaceholderShapeSet, aTextFieldContentProviderSet,
               aDefsElement, aTextFieldHandlerSet, sMasterSlideId )
 {
     var sRefId = null;
     var aTextFieldHandler = null;
-    var aPlaceholderShape = aPlaceholderShapeSet[sClassName];
+    var sClassName = sId.split('.')[0];
+    var aPlaceholderShape = aPlaceholderShapeSet[sId];
+    var aTextFieldContentProvider = aTextFieldContentProviderSet[sClassName];
     if( aPlaceholderShape  && aPlaceholderShape.isValid()
-        && aTextFieldContentProviderSet[sClassName] )
+        && aTextFieldContentProvider )
     {
-        var sTextFieldContentProviderId = aTextFieldContentProviderSet[sClassName].sId;
+        var sTextFieldContentProviderId = aTextFieldContentProvider.sId;
         // We create only one single TextFieldHandler object (and so one only
         // text field clone) per master slide and text content.
         if ( !aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ] )
         {
             aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ] =
                 new TextFieldHandler( aPlaceholderShape,
-                                      aTextFieldContentProviderSet[sClassName] );
+                                      aTextFieldContentProvider );
             aTextFieldHandler = aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ];
             aTextFieldHandler.update();
             aTextFieldHandler.appendTo( aDefsElement );
@@ -5808,7 +5897,7 @@ MasterPageView.prototype.initTextFieldHandler =
         sRefId = aTextFieldHandler.sId;
     }
     else if( aPlaceholderShape && aPlaceholderShape.element && aPlaceholderShape.element.firstElementChild
-        && !aPlaceholderShape.textElement && !aTextFieldContentProviderSet[sClassName] )
+        && !aPlaceholderShape.textElement && !aTextFieldContentProvider )
     {
         sRefId = aPlaceholderShape.element.firstElementChild.getAttribute('id');
     }
@@ -6027,10 +6116,16 @@ FixedTextProvider.prototype.update = function( aFixedTextField )
  *      The svg element that contains the date/time format for one or more
  *      master slide date/time field.
  */
-function CurrentDateTimeProvider( aTextFieldContentElement )
+function CurrentDateTimeProvider( aTextFieldContentElement, sDateTimeFormat )
 {
     CurrentDateTimeProvider.superclass.constructor.call( this, aTextFieldContentElement );
-    this.dateTimeFormat = getOOOAttribute( aTextFieldContentElement, aOOOAttrDateTimeFormat );
+    if( aTextFieldContentElement )
+        this.dateTimeFormat = getOOOAttribute( aTextFieldContentElement, aOOOAttrDateTimeFormat );
+    else
+    {
+        this.dateTimeFormat = sDateTimeFormat;
+        this.sId = 'DateTimeProvider.' + sDateTimeFormat;
+    }
 }
 extend( CurrentDateTimeProvider, TextFieldContentProvider );
 
@@ -6045,17 +6140,22 @@ extend( CurrentDateTimeProvider, TextFieldContentProvider );
  */
 CurrentDateTimeProvider.prototype.update = function( aDateTimeField )
 {
-    var sText = this.createDateTimeText( this.dateTimeFormat );
+    var sText = this.createDateTimeText();
     aDateTimeField.setTextContent( sText );
 };
 
 /*** private methods ***/
 
-CurrentDateTimeProvider.prototype.createDateTimeText = function( /*sDateTimeFormat*/ )
+CurrentDateTimeProvider.prototype.createDateTimeText = function()
 {
     // TODO handle date/time format
-    var aDate = new Date();
-    var sDate = aDate.toLocaleString();
+    var sDate;
+    if( this.dateTimeFormat === '<date>' )
+        sDate = new Date().toLocaleDateString();
+    else if( this.dateTimeFormat === '<time>' )
+        sDate = new Date().toLocaleTimeString();
+    else
+        sDate = new Date().toLocaleDateString();
     return sDate;
 };
 
diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index e2a73a7ff154..2c79522e5af2 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -1090,9 +1090,9 @@ bool SVGTextWriter::nextTextPortion()
 {
     mrCurrentTextPortion.clear();
     mbIsURLField = false;
-    mbIsPlaceholderShape = false;
     if( mrTextPortionEnumeration.is() && mrTextPortionEnumeration->hasMoreElements() )
     {
+        mbIsPlaceholderShape = false;
 #if OSL_DEBUG_LEVEL > 0
         OUString sInfo;
 #endif
@@ -1110,6 +1110,7 @@ bool SVGTextWriter::nextTextPortion()
             }
 #endif
             msPageCount = "";
+            msDateTimeType = "";
             if( xPortionTextRange.is() )
             {
 #if OSL_DEBUG_LEVEL > 0
@@ -1156,6 +1157,31 @@ bool SVGTextWriter::nextTextPortion()
 #if OSL_DEBUG_LEVEL > 0
                         sInfo += "text field type: " + sFieldName + "; content: " + xTextField->getPresentation( /* show command: */ false ) + "; ";
 #endif
+                        // This case handle Date or Time text field inserted by the user
+                        // on both page/master page. It doesn't handle the standard Date/Time field.
+                        if( sFieldName == "DateTime" )
+                        {
+                            Reference<XPropertySet> xTextFieldPropSet(xTextField, UNO_QUERY);
+                            if( xTextFieldPropSet.is() )
+                            {
+                                Reference<XPropertySetInfo> xPropSetInfo = xTextFieldPropSet->getPropertySetInfo();
+                                if( xPropSetInfo.is() )
+                                {
+                                    // The standard Date/Time field has no property.
+                                    // Trying to get a property value on such field would cause a runtime exception.
+                                    // So the hasPropertyByName check is needed.
+                                    bool bIsFixed = true;
+                                    if( xPropSetInfo->hasPropertyByName("IsFixed") && ( ( xTextFieldPropSet->getPropertyValue( "IsFixed" ) ) >>= bIsFixed ) && !bIsFixed )
+                                    {
+                                        bool bIsDate;
+                                        if( xPropSetInfo->hasPropertyByName("IsDate") && ( ( xTextFieldPropSet->getPropertyValue( "IsDate" ) ) >>= bIsDate ) )
+                                        {
+                                            msDateTimeType = OUString::createFromAscii( bIsDate ? "<date>" : "<time>" );
+                                        }
+                                    }
+                                }
+                            }
+                        }
                         if( sFieldName == "DateTime" || sFieldName == "Header"
                                 || sFieldName == "Footer" || sFieldName == "PageNumber" )
                         {
@@ -1682,6 +1708,13 @@ void SVGTextWriter::implWriteTextPortion( const Point& rPos,
         SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
         mrExport.GetDocHandler()->characters( msPageCount );
     }
+    // This case handle Date or Time text field inserted by the user
+    // on both page/master page. It doesn't handle the standard Date/Time field.
+    else if ( !msDateTimeType.isEmpty() )
+    {
+        SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
+        mrExport.GetDocHandler()->characters( msDateTimeType );
+    }
     else
     {
         SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index fc6dbec23b4c..eeaf840807fb 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -249,6 +249,7 @@ class SVGTextWriter final
     OUString                                    msUrl;
     OUString                                    msHyperlinkIdList;
     OUString                                    msPageCount;
+    OUString                                    msDateTimeType;
     bool                                        mbIsPlaceholderShape;
     static const bool                           mbIWS = false;
     vcl::Font                                   maCurrentFont;


More information about the Libreoffice-commits mailing list