diff options
author | Serge Krot <Serge.Krot@cib.de> | 2017-10-09 12:15:05 +0200 |
---|---|---|
committer | Thorsten Behrens <Thorsten.Behrens@CIB.de> | 2017-10-10 19:35:28 +0200 |
commit | f5c266695a4a88da7db971a21915e2bbf758d48e (patch) | |
tree | b11516ba17e51898a66152e4e75eb2ff34244ef3 | |
parent | 9c4d690b73b30aa144828935ad4e87eb13442d0c (diff) |
tdf#66398 Parse and output permissions for DOCX using bookmarks
Change-Id: Id08998ae775c5f383edc4bf0410d16f88c70dfd6
Reviewed-on: https://gerrit.libreoffice.org/43275
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 206 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.hxx | 15 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper.cxx | 25 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.cxx | 117 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.hxx | 53 | ||||
-rw-r--r-- | writerfilter/source/ooxml/model.xml | 70 |
6 files changed, 416 insertions, 70 deletions
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 3d7d8b53957e..e2e000c00bc0 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -1235,8 +1235,13 @@ void DocxAttributeOutput::EndRun() // if there is some redlining in the document, output it StartRedline( m_pRedlineData ); - DoWriteBookmarks( ); - DoWriteAnnotationMarks( ); + // XML_r node should be surrounded with bookmark-begin and bookmark-end nodes if it has bookmarks. + // The same is applied for permission ranges. + // But due to unit test "testFdo85542" let's output bookmark-begin with bookmark-end. + DoWriteBookmarksStart(); + DoWriteBookmarksEnd(); + DoWritePermissionsStart(); + DoWriteAnnotationMarks(); if( m_closeHyperlinkInThisRun && m_startedHyperlink && !m_hyperLinkAnchor.isEmpty() && m_hyperLinkAnchor.startsWith("_Toc")) { @@ -1312,6 +1317,9 @@ void DocxAttributeOutput::EndRun() m_pSerializer->mergeTopMarks(Tag_StartRun_1); + // XML_r node should be surrounded with permission-begin and permission-end nodes if it has permission. + DoWritePermissionsEnd(); + for (std::vector<const SwOLENode*>::iterator it = m_aPostponedMaths.begin(); it != m_aPostponedMaths.end(); ++it) WritePostponedMath(*it); m_aPostponedMaths.clear(); @@ -1371,41 +1379,159 @@ void DocxAttributeOutput::EndRun() } } -void DocxAttributeOutput::DoWriteBookmarks() +void DocxAttributeOutput::DoWriteBookmarkTagStart(const OUString & bookmarkName) +{ + const OString rId = OString::number(m_nNextBookmarkId); + const OString rName = OUStringToOString(BookmarkToWord(bookmarkName), RTL_TEXTENCODING_UTF8).getStr(); + + m_pSerializer->singleElementNS(XML_w, XML_bookmarkStart, + FSNS(XML_w, XML_id), rId.getStr(), + FSNS(XML_w, XML_name), rName.getStr(), + FSEND); +} + +void DocxAttributeOutput::DoWriteBookmarkTagEnd(const OUString & bookmarkName) { - // Write the start bookmarks - for ( const auto & it : m_rBookmarksStart ) + const auto nameToIdIter = m_rOpenedBookmarksIds.find(bookmarkName); + if (nameToIdIter != m_rOpenedBookmarksIds.end()) { - OString rName = OUStringToOString( BookmarkToWord( it ), RTL_TEXTENCODING_UTF8 ).getStr(); + const sal_Int32 nId = nameToIdIter->second; + const OString rId = OString::number(nId); + + m_pSerializer->singleElementNS(XML_w, XML_bookmarkEnd, + FSNS(XML_w, XML_id), rId.getStr(), + FSEND); + } +} +/// Write the start bookmarks +void DocxAttributeOutput::DoWriteBookmarksStart() +{ + for (const OUString & bookmarkName : m_rBookmarksStart) + { // Output the bookmark - const sal_Int32 nId = m_nNextBookmarkId++; - m_rOpenedBookmarksIds[it] = nId; - m_pSerializer->singleElementNS( XML_w, XML_bookmarkStart, - FSNS( XML_w, XML_id ), OString::number( nId ).getStr( ), - FSNS( XML_w, XML_name ), rName.getStr(), - FSEND ); - m_sLastOpenedBookmark = rName; + DoWriteBookmarkTagStart(bookmarkName); + + m_rOpenedBookmarksIds[bookmarkName] = m_nNextBookmarkId; + m_sLastOpenedBookmark = OUStringToOString(BookmarkToWord(bookmarkName), RTL_TEXTENCODING_UTF8).getStr(); + m_nNextBookmarkId++; } m_rBookmarksStart.clear(); +} - // export the end bookmarks - for ( const auto & it : m_rBookmarksEnd ) +/// export the end bookmarks +void DocxAttributeOutput::DoWriteBookmarksEnd() +{ + for (const OUString & bookmarkName : m_rBookmarksEnd) { // Get the id of the bookmark - auto pPos = m_rOpenedBookmarksIds.find(it); - if ( pPos != m_rOpenedBookmarksIds.end() ) + auto pPos = m_rOpenedBookmarksIds.find(bookmarkName); + if (pPos != m_rOpenedBookmarksIds.end()) { - const sal_Int32 nId = ( *pPos ).second; - m_pSerializer->singleElementNS( XML_w, XML_bookmarkEnd, - FSNS( XML_w, XML_id ), OString::number( nId ).getStr(), - FSEND ); - m_rOpenedBookmarksIds.erase( it ); + // Output the bookmark + DoWriteBookmarkTagEnd(bookmarkName); + + m_rOpenedBookmarksIds.erase(bookmarkName); } } m_rBookmarksEnd.clear(); } +// For construction of the special bookmark name template for permissions: +// see, PermInsertPosition::createBookmarkName() +// +// Syntax: +// - "permission-for-user:<permission-id>:<permission-user-name>" +// - "permission-for-group:<permission-id>:<permission-group-name>" +// +void DocxAttributeOutput::DoWritePermissionTagStart(const OUString & permission) +{ + OUString permissionIdAndName; + + if (permission.startsWith("permission-for-group:", &permissionIdAndName)) + { + const sal_Int32 sparatorIndex = permissionIdAndName.indexOf(':'); + const OUString permissionId = permissionIdAndName.copy(0, sparatorIndex); + const OUString permissionName = permissionIdAndName.copy(sparatorIndex + 1); + + const OString rId = OUStringToOString(BookmarkToWord(permissionId), RTL_TEXTENCODING_UTF8).getStr(); + const OString rName = OUStringToOString(BookmarkToWord(permissionName), RTL_TEXTENCODING_UTF8).getStr(); + + m_pSerializer->singleElementNS(XML_w, XML_permStart, + FSNS(XML_w, XML_id), rId.getStr(), + FSNS(XML_w, XML_edGrp), rName.getStr(), + FSEND); + } + else // if (permission.startsWith("permission-for-user:", &permissionIdAndName)) + { + const sal_Int32 sparatorIndex = permissionIdAndName.indexOf(':'); + const OUString permissionId = permissionIdAndName.copy(0, sparatorIndex); + const OUString permissionName = permissionIdAndName.copy(sparatorIndex + 1); + + const OString rId = OUStringToOString(BookmarkToWord(permissionId), RTL_TEXTENCODING_UTF8).getStr(); + const OString rName = OUStringToOString(BookmarkToWord(permissionName), RTL_TEXTENCODING_UTF8).getStr(); + + m_pSerializer->singleElementNS(XML_w, XML_permStart, + FSNS(XML_w, XML_id), rId.getStr(), + FSNS(XML_w, XML_ed), rName.getStr(), + FSEND); + } +} + + +// For construction of the special bookmark name template for permissions: +// see, PermInsertPosition::createBookmarkName() +// +// Syntax: +// - "permission-for-user:<permission-id>:<permission-user-name>" +// - "permission-for-group:<permission-id>:<permission-group-name>" +// +void DocxAttributeOutput::DoWritePermissionTagEnd(const OUString & permission) +{ + OUString permissionIdAndName; + + if (permission.startsWith("permission-for-group:", &permissionIdAndName)) + { + const sal_Int32 sparatorIndex = permissionIdAndName.indexOf(':'); + const OUString permissionId = permissionIdAndName.copy(0, sparatorIndex); + const OString rId = OUStringToOString(BookmarkToWord(permissionId), RTL_TEXTENCODING_UTF8).getStr(); + + m_pSerializer->singleElementNS(XML_w, XML_permEnd, + FSNS(XML_w, XML_id), rId.getStr(), + FSEND); + } + else // if (permission.startsWith("permission-for-user:", &permissionIdAndName)) + { + const sal_Int32 sparatorIndex = permissionIdAndName.indexOf(':'); + const OUString permissionId = permissionIdAndName.copy(0, sparatorIndex); + const OString rId = OUStringToOString(BookmarkToWord(permissionId), RTL_TEXTENCODING_UTF8).getStr(); + + m_pSerializer->singleElementNS(XML_w, XML_permEnd, + FSNS(XML_w, XML_id), rId.getStr(), + FSEND); + } +} + +/// Write the start permissions +void DocxAttributeOutput::DoWritePermissionsStart() +{ + for (const OUString & permission : m_rPermissionsStart) + { + DoWritePermissionTagStart(permission); + } + m_rPermissionsStart.clear(); +} + +/// export the end permissions +void DocxAttributeOutput::DoWritePermissionsEnd() +{ + for (const OUString & permission : m_rPermissionsEnd) + { + DoWritePermissionTagEnd(permission); + } + m_rPermissionsEnd.clear(); +} + void DocxAttributeOutput::DoWriteAnnotationMarks() { // Write the start annotation marks @@ -1629,10 +1755,7 @@ void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos ) OUString aBkmName( m_sFieldBkm ); if ( !aBkmName.isEmpty() ) { - m_pSerializer->singleElementNS( XML_w, XML_bookmarkStart, - FSNS( XML_w, XML_id ), OString::number( m_nNextBookmarkId ).getStr( ), - FSNS( XML_w, XML_name ), OUStringToOString( aBkmName, RTL_TEXTENCODING_UTF8 ).getStr( ), - FSEND ); + DoWriteBookmarkTagEnd(aBkmName); } if (rInfos.pField ) // For hyperlinks and TOX @@ -1658,9 +1781,7 @@ void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos ) // Write the bookmark end if any if ( !aBkmName.isEmpty() ) { - m_pSerializer->singleElementNS( XML_w, XML_bookmarkEnd, - FSNS( XML_w, XML_id ), OString::number( m_nNextBookmarkId ).getStr( ), - FSEND ); + DoWriteBookmarkTagEnd(aBkmName); m_nNextBookmarkId++; } @@ -6980,18 +7101,33 @@ void DocxAttributeOutput::WriteFormData_Impl( const ::sw::mark::IFieldmark& rFie m_Fields.begin()->pFieldmark = &rFieldmark; } -void DocxAttributeOutput::WriteBookmarks_Impl( std::vector< OUString >& rStarts, - std::vector< OUString >& rEnds ) +void DocxAttributeOutput::WriteBookmarks_Impl( std::vector< OUString >& rStarts, std::vector< OUString >& rEnds ) { - for ( const auto & it : rStarts ) + for ( const OUString & name : rStarts ) { - m_rBookmarksStart.push_back( it ); + if (name.startsWith("permission-for-group:") || + name.startsWith("permission-for-user:")) + { + m_rPermissionsStart.push_back(name); + } + else + { + m_rBookmarksStart.push_back(name); + } } rStarts.clear(); - for ( const auto & it : rEnds ) + for ( const OUString & name : rEnds ) { - m_rBookmarksEnd.push_back( it ); + if (name.startsWith("permission-for-group:") || + name.startsWith("permission-for-user:")) + { + m_rPermissionsEnd.push_back(name); + } + else + { + m_rBookmarksEnd.push_back(name); + } } rEnds.clear(); } diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 65334bc07a50..3fdfd95cd312 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -695,7 +695,16 @@ protected: private: - void DoWriteBookmarks( ); + void DoWriteBookmarkTagStart(const OUString & bookmarkName); + void DoWriteBookmarkTagEnd(const OUString & bookmarkName); + void DoWriteBookmarksStart(); + void DoWriteBookmarksEnd(); + + void DoWritePermissionTagStart(const OUString & permission); + void DoWritePermissionTagEnd(const OUString & permission); + void DoWritePermissionsStart(); + void DoWritePermissionsEnd(); + void DoWriteAnnotationMarks( ); void WritePostponedGraphic(); void WritePostponedMath(const SwOLENode* pObject); @@ -776,6 +785,10 @@ private: std::vector<OUString> m_rBookmarksStart; std::vector<OUString> m_rBookmarksEnd; + /// Permissions to output + std::vector<OUString> m_rPermissionsStart; + std::vector<OUString> m_rPermissionsEnd; + /// Annotation marks to output std::vector<OString> m_rAnnotationMarksStart; std::vector<OString> m_rAnnotationMarksEnd; diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index f492c2c2d033..227f55935ee3 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -1125,6 +1125,26 @@ void DomainMapper::lcl_attribute(Id nName, Value & val) } break; } + case NS_ooxml::LN_CT_PermStart_ed: + { + m_pImpl->setPermissionRangeEd(sStringValue); + break; + } + case NS_ooxml::LN_CT_PermStart_edGrp: + { + m_pImpl->setPermissionRangeEdGrp(sStringValue); + break; + } + case NS_ooxml::LN_CT_PermStart_id: + { + m_pImpl->startOrEndPermissionRange(nIntValue); + break; + } + case NS_ooxml::LN_CT_PermEnd_id: + { + m_pImpl->startOrEndPermissionRange(nIntValue); + break; + } default: SAL_WARN("writerfilter", "DomainMapper::lcl_attribute: unhandled token: " << nName); } @@ -2816,11 +2836,6 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext ) pProperties->resolve(*this); } break; - case NS_ooxml::LN_EG_RunLevelElts_permStart: // 93164 - case NS_ooxml::LN_EG_RunLevelElts_permEnd: // 93165 - { - break; - } default: { #ifdef DEBUG_WRITERFILTER diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index be16a2307eaf..8e1423cf1380 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -202,6 +202,7 @@ DomainMapper_Impl::DomainMapper_Impl( m_bStartBibliography(false), m_bStartGenericField(false), m_bTextInserted(false), + m_sCurrentPermId(0), m_pLastSectionContext( ), m_pLastCharacterContext(), m_sCurrentParaStyleId(), @@ -4791,6 +4792,7 @@ void DomainMapper_Impl::SetBookmarkName( const OUString& rBookmarkName ) m_sCurrentBkmkName = rBookmarkName; } +// This method was used as-is for DomainMapper_Impl::startOrEndPermissionRange() implementation. void DomainMapper_Impl::StartOrEndBookmark( const OUString& rId ) { /* @@ -4869,6 +4871,121 @@ void DomainMapper_Impl::StartOrEndBookmark( const OUString& rId ) } } +void DomainMapper_Impl::setPermissionRangeEd(const OUString& user) +{ + PermMap_t::iterator aPremIter = m_aPermMap.find(m_sCurrentPermId); + if (aPremIter != m_aPermMap.end()) + aPremIter->second.m_Ed = user; + else + m_sCurrentPermEd = user; +} + +void DomainMapper_Impl::setPermissionRangeEdGrp(const OUString& group) +{ + PermMap_t::iterator aPremIter = m_aPermMap.find(m_sCurrentPermId); + if (aPremIter != m_aPermMap.end()) + aPremIter->second.m_EdGrp = group; + else + m_sCurrentPermEdGrp = group; +} + +// This method is based on implementation from DomainMapper_Impl::StartOrEndBookmark() +void DomainMapper_Impl::startOrEndPermissionRange(sal_Int32 permissinId) +{ + /* + * Add the dummy paragraph to handle section properties + * if the first element in the section is a table. If the dummy para is not added yet, then add it; + * So permission is not attached to the wrong paragraph. + */ + if (getTableManager().isInCell() && m_nTableDepth == 0 && GetIsFirstParagraphInSection() + && !GetIsDummyParaAddedForTableInSection() && !GetIsTextFrameInserted()) + { + AddDummyParaForTableInSection(); + } + + if (m_aTextAppendStack.empty()) + return; + + const bool bIsAfterDummyPara = GetIsDummyParaAddedForTableInSection() && GetIsFirstParagraphInSection(); + + uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend; + PermMap_t::iterator aPermIter = m_aPermMap.find(permissinId); + + //is the bookmark name already registered? + try + { + if (aPermIter == m_aPermMap.end()) + { + //otherwise insert a text range as marker + bool bIsStart = true; + uno::Reference< text::XTextRange > xCurrent; + if (xTextAppend.is()) + { + uno::Reference< text::XTextCursor > xCursor = xTextAppend->createTextCursorByRange(xTextAppend->getEnd()); + + if (!bIsAfterDummyPara) + bIsStart = !xCursor->goLeft(1, false); + xCurrent = xCursor->getStart(); + } + + // register the start of the new permission + m_sCurrentPermId = permissinId; + m_aPermMap.emplace(permissinId, PermInsertPosition(bIsStart, permissinId, m_sCurrentPermEd, m_sCurrentPermEdGrp, xCurrent)); + + // clean up + m_sCurrentPermEd.clear(); + m_sCurrentPermEdGrp.clear(); + } + else + { + if (m_xTextFactory.is()) + { + uno::Reference< text::XTextCursor > xCursor; + uno::Reference< text::XText > xText = aPermIter->second.m_xTextRange->getText(); + if (aPermIter->second.m_bIsStartOfText && !bIsAfterDummyPara) + { + xCursor = xText->createTextCursorByRange(xText->getStart()); + } + else + { + xCursor = xText->createTextCursorByRange(aPermIter->second.m_xTextRange); + xCursor->goRight(1, false); + } + + xCursor->gotoRange(xTextAppend->getEnd(), true); + // A Paragraph was recently finished, and a new Paragraph has not been started as yet + // then move the bookmark-End to the earlier paragraph + if (IsOutsideAParagraph()) + { + xCursor->goLeft(1, false); + } + + // create a new bookmark using specific bookmark name pattern for permissions + uno::Reference< text::XTextContent > xPerm(m_xTextFactory->createInstance("com.sun.star.text.Bookmark"), uno::UNO_QUERY_THROW); + uno::Reference< container::XNamed > xPermNamed(xPerm, uno::UNO_QUERY_THROW); + xPermNamed->setName(aPermIter->second.createBookmarkName()); + + // add new bookmark + const bool bAbsorb = !xCursor->isCollapsed(); + uno::Reference< text::XTextRange > xCurrent = uno::Reference< text::XTextRange >(xCursor, uno::UNO_QUERY_THROW); + xTextAppend->insertTextContent(xCurrent, xPerm, bAbsorb); + } + + // remove proccessed permission + m_aPermMap.erase(aPermIter); + + // clean up + m_sCurrentPermId = 0; + m_sCurrentPermEd.clear(); + m_sCurrentPermEdGrp.clear(); + } + } + catch (const uno::Exception&) + { + //TODO: What happens to bookmarks where start and end are at different XText objects? + } +} + void DomainMapper_Impl::AddAnnotationPosition( const bool bStart, const sal_Int32 nAnnotationId) diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx index 208318c81c12..df22413a8cbd 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx @@ -258,6 +258,49 @@ struct BookmarkInsertPosition {} }; +struct PermInsertPosition +{ + bool m_bIsStartOfText; + sal_Int32 m_Id; + OUString m_Ed; + OUString m_EdGrp; + + css::uno::Reference<css::text::XTextRange> m_xTextRange; + + PermInsertPosition(bool bIsStartOfText, sal_Int32 id, const OUString& ed, const OUString& edGrp, css::uno::Reference<css::text::XTextRange> const& xTextRange) + : m_bIsStartOfText(bIsStartOfText) + , m_Id(id) + , m_Ed(ed) + , m_EdGrp(edGrp) + , m_xTextRange(xTextRange) + {} + + OUString createBookmarkName() const + { + OUString bookmarkName; + + assert((!m_Ed.isEmpty()) || (!m_EdGrp.isEmpty())); + + if (m_Ed.isEmpty()) + { + bookmarkName += "permission-for-group:"; + bookmarkName += OUString::number(m_Id); + bookmarkName += ":"; + bookmarkName += m_EdGrp; + } + else + { + bookmarkName += "permission-for-user:"; + bookmarkName += OUString::number(m_Id); + bookmarkName += ":"; + bookmarkName += m_Ed; + } + + //todo: make sure the name is not used already! + return bookmarkName; + } +}; + /// Stores the start/end positions of an annotation before its insertion. struct AnnotationPosition { @@ -334,6 +377,7 @@ class DomainMapper_Impl final { public: typedef std::map < OUString, BookmarkInsertPosition > BookmarkMap_t; + typedef std::map < sal_Int32, PermInsertPosition > PermMap_t; private: SourceDocumentType m_eDocumentType; @@ -375,6 +419,11 @@ private: OUString m_sCurrentBkmkId; OUString m_sCurrentBkmkName; + PermMap_t m_aPermMap; + sal_Int32 m_sCurrentPermId; + OUString m_sCurrentPermEd; + OUString m_sCurrentPermEdGrp; + PageMar m_aPageMargins; SymbolData m_aSymbolData; @@ -705,6 +754,10 @@ public: void SetBookmarkName( const OUString& rBookmarkName ); void StartOrEndBookmark( const OUString& rId ); + void setPermissionRangeEd(const OUString& user); + void setPermissionRangeEdGrp(const OUString& group); + void startOrEndPermissionRange(sal_Int32 permissinId); + void AddAnnotationPosition( const bool bStart, const sal_Int32 nAnnotationId ); diff --git a/writerfilter/source/ooxml/model.xml b/writerfilter/source/ooxml/model.xml index 81cdc3ff9c77..a9ffbdfa6c65 100644 --- a/writerfilter/source/ooxml/model.xml +++ b/writerfilter/source/ooxml/model.xml @@ -12126,6 +12126,9 @@ </attribute> <ref name="CT_MarkupRange"/> </define> + <define name="CT_MarkupRangePerm"> + <ref name="CT_MarkupRange"/> + </define> <define name="CT_MarkupRangeCommentStart"> <ref name="CT_Markup"/> </define> @@ -12166,6 +12169,24 @@ <ref name="ST_String"/> </attribute> </define> + <define name="CT_PermStart"> + <ref name="CT_MarkupRangePerm"/> + <attribute name="ed"> + <data type="string"/> + </attribute> + <attribute name="edGrp"> + <data type="string"/> + </attribute> + <attribute name="colFirst"> + <data type="ST_DecimalNumber"/> + </attribute> + <attribute name="colLast"> + <data type="ST_DecimalNumber"/> + </attribute> + </define> + <define name="CT_PermEnd"> + <ref name="CT_MarkupRangePerm"/> + </define> <define name="CT_TrackChangeNumbering"> <ref name="CT_TrackChange"/> <attribute name="original"> @@ -12254,6 +12275,12 @@ <element name="bookmarkEnd"> <ref name="CT_MarkupRangeBookmark"/> </element> + <element name="permStart"> + <ref name="CT_PermStart"/> + </element> + <element name="permEnd"> + <ref name="CT_PermEnd"/> + </element> <element name="moveFromRangeStart"> <ref name="CT_MoveBookmark"/> </element> @@ -13279,29 +13306,6 @@ <data type="string"/> </attribute> </define> - <define name="CT_Perm"> - <attribute name="id"> - <data type="string"/> - </attribute> - <attribute name="displacedByCustomXml"> - <data type="string"/> - </attribute> - </define> - <define name="CT_PermStart"> - <ref name="CT_Perm"/> - <attribute name="edGrp"> - <data type="string"/> - </attribute> - <attribute name="ed"> - <data type="string"/> - </attribute> - <attribute name="colFirst"> - <data type="string"/> - </attribute> - <attribute name="colLast"> - <data type="string"/> - </attribute> - </define> <define name="CT_Text"> <ref name="ST_String"/> <attribute name="xml:space"> @@ -16291,12 +16295,6 @@ <element name="proofErr"> <ref name="CT_ProofErr"/> </element> - <element name="permStart"> - <ref name="CT_PermStart"/> - </element> - <element name="permEnd"> - <ref name="CT_Perm"/> - </element> <ref name="EG_RangeMarkupElements"/> <element name="ins"> <ref name="CT_RunTrackChange"/> @@ -17363,6 +17361,18 @@ <resource name="CT_MarkupRangeBookmark" resource="Properties"> <attribute name="id" tokenid="ooxml:CT_MarkupRangeBookmark_id"/> </resource> + <resource name="CT_PermStart" resource="Properties"> + <attribute name="id" tokenid="ooxml:CT_PermStart_id"/> + <attribute name="colFirst" tokenid="ooxml:CT_PermStart_colFirst"/> + <attribute name="colLast" tokenid="ooxml:CT_PermStart_colLast"/> + <attribute name="ed" tokenid="ooxml:CT_PermStart_ed"/> + <attribute name="edGrp" tokenid="ooxml:CT_PermStart_edGrp"/> + <attribute name="displacedByCustomXml" tokenid="ooxml:CT_PermStart_displacedByCustomXml"/> + </resource> + <resource name="CT_PermEnd" resource="Properties"> + <attribute name="id" tokenid="ooxml:CT_PermEnd_id"/> + <attribute name="displacedByCustomXml" tokenid="ooxml:CT_PermEnd_displacedByCustomXml"/> + </resource> <resource name="CT_MarkupRangeCommentStart" resource="Properties"> <attribute name="id" tokenid="ooxml:EG_RangeMarkupElements_commentRangeStart"/> </resource> @@ -17425,6 +17435,8 @@ <resource name="EG_RangeMarkupElements" resource="Properties"> <element name="bookmarkStart" tokenid="ooxml:EG_RangeMarkupElements_bookmarkStart"/> <element name="bookmarkEnd" tokenid="ooxml:EG_RangeMarkupElements_bookmarkEnd"/> + <element name="permStart" tokenid="ooxml:EG_RangeMarkupElements_PermStart"/> + <element name="permEnd" tokenid="ooxml:EG_RangeMarkupElements_PermEnd"/> <element name="moveFromRangeStart" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeStart"/> <element name="moveFromRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeEnd"/> <element name="moveToRangeStart" tokenid="ooxml:EG_RangeMarkupElements_moveToRangeStart"/> |