diff options
author | Tzvetelina Tzeneva <tzvetelina@gmail.com> | 2011-12-22 17:27:32 +0100 |
---|---|---|
committer | Cédric Bosdonnat <cedric.bosdonnat@free.fr> | 2011-12-22 17:53:53 +0100 |
commit | 062eaeffe7cb986255063bb9b0a5f3fb3fc8e34c (patch) | |
tree | 0f065352d000a11131203cf6832354bde597ff50 | |
parent | 61329db01af7fd7c5915a4d81896d52fda7168db (diff) |
sw: Improved document comparison based on RSIDs.
52 files changed, 1825 insertions, 135 deletions
diff --git a/cui/source/options/treeopt.cxx b/cui/source/options/treeopt.cxx index 8053a3f25711..9d02f0fe4d84 100644 --- a/cui/source/options/treeopt.cxx +++ b/cui/source/options/treeopt.cxx @@ -385,6 +385,7 @@ static OptionsMapping_Impl const OptionsMap_Impl[] = { "Writer", "Print", RID_SW_TP_OPTPRINT_PAGE }, { "Writer", "Table", RID_SW_TP_OPTTABLE_PAGE }, { "Writer", "Changes", RID_SW_TP_REDLINE_OPT }, + { "Writer", "Comparison", RID_SW_TP_COMPARISON_OPT }, { "Writer", "Compatibility", RID_SW_TP_OPTCOMPATIBILITY_PAGE }, { "Writer", "AutoCaption", RID_SW_TP_OPTCAPTION_PAGE }, { "Writer", "MailMerge", RID_SW_TP_MAILCONFIG }, diff --git a/cui/source/options/treeopt.src b/cui/source/options/treeopt.src index 9e4fdeb553b2..37bdc36d7c4f 100644 --- a/cui/source/options/treeopt.src +++ b/cui/source/options/treeopt.src @@ -148,6 +148,7 @@ Resource RID_OFADLG_OPTIONS_TREE_PAGES < "Print" ; RID_SW_TP_OPTPRINT_PAGE ; > ; < "Table" ; RID_SW_TP_OPTTABLE_PAGE ; > ; < "Changes" ; RID_SW_TP_REDLINE_OPT ; > ; + < "Comparison" ; RID_SW_TP_COMPARISON_OPT ; > ; < "Compatibility" ; RID_SW_TP_OPTCOMPATIBILITY_PAGE ; > ; < "AutoCaption" ; RID_SW_TP_OPTCAPTION_PAGE ; > ; < "Mail Merge E-mail" ; RID_SW_TP_MAILCONFIG ; >; diff --git a/editeng/Package_inc.mk b/editeng/Package_inc.mk index 61d060373462..0305a047032a 100644 --- a/editeng/Package_inc.mk +++ b/editeng/Package_inc.mk @@ -113,6 +113,7 @@ $(eval $(call gb_Package_add_file,editeng_inc,inc/editeng/postitem.hxx,editeng/p $(eval $(call gb_Package_add_file,editeng_inc,inc/editeng/prntitem.hxx,editeng/prntitem.hxx)) $(eval $(call gb_Package_add_file,editeng_inc,inc/editeng/protitem.hxx,editeng/protitem.hxx)) $(eval $(call gb_Package_add_file,editeng_inc,inc/editeng/prszitem.hxx,editeng/prszitem.hxx)) +$(eval $(call gb_Package_add_file,editeng_inc,inc/editeng/rsiditem.hxx,editeng/rsiditem.hxx)) $(eval $(call gb_Package_add_file,editeng_inc,inc/editeng/scriptspaceitem.hxx,editeng/scriptspaceitem.hxx)) $(eval $(call gb_Package_add_file,editeng_inc,inc/editeng/scripttypeitem.hxx,editeng/scripttypeitem.hxx)) $(eval $(call gb_Package_add_file,editeng_inc,inc/editeng/shaditem.hxx,editeng/shaditem.hxx)) diff --git a/editeng/inc/editeng/rsiditem.hxx b/editeng/inc/editeng/rsiditem.hxx new file mode 100644 index 000000000000..e98fb8e4e129 --- /dev/null +++ b/editeng/inc/editeng/rsiditem.hxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Version: MPL 1.1 / GPLv3+ / LGPLv3+ + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License or as specified alternatively below. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * Major Contributor(s): + * [ Copyright (C) 2009 Tzvetelina Tzeneva <tzvetelina@gmail.com> (initial developer) ] + */ +#ifndef _SVX_RSIDITEM_HXX +#define _SVX_RSIDITEM_HXX + +#include <svl/intitem.hxx> +#include "editeng/editengdllapi.h" + +//---------------------- +// SvxRsidItem +//---------------------- + +class EDITENG_DLLPUBLIC SvxRsidItem : public SfxUInt32Item +{ +public: + TYPEINFO(); + + SvxRsidItem( sal_uInt32 nRsid, sal_uInt16 nId ) : SfxUInt32Item( nId, nRsid ) {} + SvxRsidItem( SvStream& rIn, sal_uInt16 nId ) : SfxUInt32Item( nId, rIn ) {} + + virtual SfxPoolItem* Clone( SfxItemPool* pPool = NULL ) const; + virtual SfxPoolItem* Create( SvStream& rIn, sal_uInt16 nVer ) const; + + virtual bool QueryValue( com::sun::star::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const; + virtual bool PutValue( const com::sun::star::uno::Any& rVal, sal_uInt8 nMemberId = 0 ); +}; + +#endif // _SVX_RSIDITEM_HXX diff --git a/editeng/inc/editeng/svxenum.hxx b/editeng/inc/editeng/svxenum.hxx index 68849722059b..2d07e9fe7a77 100644 --- a/editeng/inc/editeng/svxenum.hxx +++ b/editeng/inc/editeng/svxenum.hxx @@ -222,6 +222,12 @@ enum SvxExtNumType SVX_NUM_CHARS_LOWER_LETTER_N }; +enum SvxCompareMode +{ + SVX_CMP_AUTO = 0, + SVX_CMP_BY_WORD, + SVX_CMP_BY_CHAR +}; #endif diff --git a/editeng/source/items/textitem.cxx b/editeng/source/items/textitem.cxx index e3069074573a..db0edf2c9ffd 100644 --- a/editeng/source/items/textitem.cxx +++ b/editeng/source/items/textitem.cxx @@ -73,6 +73,7 @@ #include <com/sun/star/lang/Locale.hpp> #include <com/sun/star/text/FontEmphasis.hpp> #include <com/sun/star/i18n/ScriptType.hpp> +#include <editeng/rsiditem.hxx> #include <editeng/memberids.hrc> #include <editeng/flstitem.hxx> #include <editeng/fontitem.hxx> @@ -157,7 +158,7 @@ TYPEINIT1_FACTORY(SvxScriptTypeItem, SfxUInt16Item, new SvxScriptTypeItem); TYPEINIT1_FACTORY(SvxCharRotateItem, SfxUInt16Item, new SvxCharRotateItem(0, sal_False, 0)); TYPEINIT1_FACTORY(SvxCharScaleWidthItem, SfxUInt16Item, new SvxCharScaleWidthItem(100, 0)); TYPEINIT1_FACTORY(SvxCharReliefItem, SfxEnumItem, new SvxCharReliefItem(RELIEF_NONE, 0)); - +TYPEINIT1_FACTORY(SvxRsidItem, SfxUInt32Item, new SvxRsidItem(0, 0)); TYPEINIT1(SvxScriptSetItem, SfxSetItem ); @@ -3740,4 +3741,29 @@ short GetI18NScriptType( sal_uInt16 nItemType ) return 0; } +bool SvxRsidItem::QueryValue( uno::Any& rVal, sal_uInt8 ) const +{ + rVal <<= ( (sal_uInt32)GetValue() ); + return true; +} + +bool SvxRsidItem::PutValue( const uno::Any& rVal, sal_uInt8 ) +{ + sal_uInt32 nRsid = 0; + if( !( rVal >>= nRsid ) ) + return false; + + SetValue( nRsid ); + return true; +} + +SfxPoolItem* SvxRsidItem::Clone( SfxItemPool * ) const +{ + return new SvxRsidItem( *this ); +} + +SfxPoolItem* SvxRsidItem::Create(SvStream& rIn, sal_uInt16 ) const +{ + return new SvxRsidItem( rIn, Which() ); +} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/officecfg/registry/schema/org/openoffice/Office/Writer.xcs b/officecfg/registry/schema/org/openoffice/Office/Writer.xcs index 73645dbd9c43..bacae25fccb8 100644 --- a/officecfg/registry/schema/org/openoffice/Office/Writer.xcs +++ b/officecfg/registry/schema/org/openoffice/Office/Writer.xcs @@ -2810,6 +2810,36 @@ </prop> </group> </group> + <group oor:name="Comparison"> + <info> + <desc>Contains settings for comparing files.</desc> + </info> + <prop oor:name="Mode" oor:type="xs:short"> + <info> + <author>OS</author> + <desc>Defines the Comparison Mode.</desc> + </info> + </prop> + + <prop oor:name="UseRSID" oor:type="xs:boolean"> + <info> + <author>OS</author> + <desc>Specifies if RSIDs are used in comparison.</desc> + </info> + </prop> + <prop oor:name="IgnorePieces" oor:type="xs:boolean"> + <info> + <author>OS</author> + <desc>Specifies if short pieces of matched text are ignored.</desc> + </info> + </prop> + <prop oor:name="IgnoreLength" oor:type="xs:short"> + <info> + <author>OS</author> + <desc>Defines the length of ignored pieces.</desc> + </info> + </prop> + </group> <group oor:name="Insert"> <info> <desc>Specifies the settings for inserting various object types.</desc> diff --git a/svx/inc/svx/dialogs.hrc b/svx/inc/svx/dialogs.hrc index 0ece88fa594e..a1038f1ef1ce 100755 --- a/svx/inc/svx/dialogs.hrc +++ b/svx/inc/svx/dialogs.hrc @@ -136,6 +136,7 @@ #define RID_SW_TP_OPTTABLE_PAGE (RID_OFA_START + 210) #define RID_SW_TP_REDLINE_OPT (RID_OFA_START + 212) #define RID_SW_TP_OPTCOMPATIBILITY_PAGE (RID_OFA_START + 255) +#define RID_SW_TP_COMPARISON_OPT (RID_OFA_START + 257) #define RID_SW_TP_HTML_CONTENT_OPT (RID_OFA_START + 240) #define RID_SW_TP_HTML_OPTPRINT_PAGE (RID_OFA_START + 242) #define RID_SW_TP_HTML_OPTTABLE_PAGE (RID_OFA_START + 243) diff --git a/svx/source/src/app.hrc b/svx/source/src/app.hrc index e2ee4daf3a03..19a17e4e0807 100755 --- a/svx/source/src/app.hrc +++ b/svx/source/src/app.hrc @@ -196,7 +196,8 @@ #define RID_SW_TP_OPTCAPTION_PAGE (RID_OFA_START + 256) #define SID_SC_TP_FORMULA (RID_OFA_START + 257) #define SID_SC_TP_COMPATIBILITY (RID_OFA_START + 258) -#define RID_SC_TP_DEFAULTS (RID_OFA_START + 259) +#define RID_SC_TP_DEFAULTS (RID_OFA_START + 259) +#define RID_SW_TP_COMPARISON_OPT (RID_OFA_START + 260) // Strings ------------------------------------------ diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx index c7255d94f00d..0251d46d3527 100644 --- a/sw/inc/doc.hxx +++ b/sw/inc/doc.hxx @@ -416,6 +416,9 @@ private: RedlineMode_t eRedlineMode; // Current Redline Mode. SwCharCompressType eChrCmprType; // for ASIAN: compress punctuation/kana + sal_uInt32 nRsid; // current session ID of the document + sal_uInt32 nRsidRoot; // session ID when the document was created + sal_Int32 mReferenceCount; sal_Int32 mIdleBlockCount; sal_Int8 nLockExpFld; // If != 0 UpdateExpFlds() has no effect! @@ -732,6 +735,10 @@ public: virtual void setFieldUpdateFlags( /*[in]*/ SwFldUpdateFlags eMode ); virtual SwCharCompressType getCharacterCompressionType() const; virtual void setCharacterCompressionType( /*[in]*/SwCharCompressType nType ); + virtual sal_uInt32 getRsid() const; + virtual void setRsid( sal_uInt32 nVal ); + virtual sal_uInt32 getRsidRoot() const; + virtual void setRsidRoot( sal_uInt32 nVal ); /** IDocumentDeviceAccess */ @@ -859,6 +866,9 @@ public: virtual bool Overwrite(const SwPaM &rRg, const String& rStr); virtual bool InsertString(const SwPaM &rRg, const String&, const enum InsertFlags nInsertMode = INS_EMPTYEXPAND ); + virtual bool UpdateRsid( SwTxtNode *pTxtNode, xub_StrLen nStt, xub_StrLen nEnd ); + virtual bool UpdateParRsid( SwTxtNode *pTxtNode, sal_uInt32 nVal = 0 ); + virtual bool UpdateRsid( const SwPaM &rRg, xub_StrLen nLen ); virtual SwFlyFrmFmt* Insert(const SwPaM &rRg, const String& rGrfName, const String& rFltName, const Graphic* pGraphic, const SfxItemSet* pFlyAttrSet, const SfxItemSet* pGrfAttrSet, SwFrmFmt*); virtual SwFlyFrmFmt* Insert(const SwPaM& rRg, const GraphicObject& rGrfObj, const SfxItemSet* pFlyAttrSet, diff --git a/sw/inc/globals.hrc b/sw/inc/globals.hrc index d68ada7ca26d..17e919d58f61 100644 --- a/sw/inc/globals.hrc +++ b/sw/inc/globals.hrc @@ -273,6 +273,7 @@ #define TP_OPTCOMPATIBILITY_PAGE (RC_GLOBALS_BEGIN + 103) #define TP_MAILCONFIG (RC_GLOBALS_BEGIN + 104) #define TP_TITLEPAGE (RC_GLOBALS_BEGIN + 105) +#define TP_COMPARISON_OPT (RC_GLOBALS_BEGIN + 106) //maximum: RC_GLOBALS_BEGIN + 120 diff --git a/sw/inc/helpid.h b/sw/inc/helpid.h index c5dc7f9dd3db..9f19b8ea2029 100644 --- a/sw/inc/helpid.h +++ b/sw/inc/helpid.h @@ -308,6 +308,7 @@ #define HID_TEXTGRID_PAGE "SW_HID_TEXTGRID_PAGE" #define HID_OPTCOMPATIBILITY_PAGE "SW_HID_OPTCOMPATIBILITY_PAGE" #define HID_COMPATIBILITY_OPTIONS_BOX "SW_HID_COMPATIBILITY_OPTIONS_BOX" +#define HID_COMPARISON_OPT "SW_HID_COMPARISON_OPT" // AutoPilot Help-IDs diff --git a/sw/inc/hintids.hxx b/sw/inc/hintids.hxx index afd57f3bfb4a..9428072fa53a 100644 --- a/sw/inc/hintids.hxx +++ b/sw/inc/hintids.hxx @@ -96,8 +96,8 @@ RES_CHRATR_BEGIN = HINT_BEGIN, RES_CHRATR_RELIEF, // 36 RES_CHRATR_HIDDEN, // 37 RES_CHRATR_OVERLINE, // 38 - RES_CHRATR_DUMMY1, // 39 - RES_CHRATR_DUMMY2, // 40 + RES_CHRATR_RSID, // 39 + RES_CHRATR_DUMMY1, // 40 RES_CHRATR_END }; @@ -168,6 +168,7 @@ RES_PARATR_BEGIN = RES_TXTATR_END, RES_PARATR_SNAPTOGRID, // 72 RES_PARATR_CONNECT_BORDER, // 73 RES_PARATR_OUTLINELEVEL, // 74 + RES_PARATR_RSID, // 75 RES_PARATR_END }; @@ -176,99 +177,99 @@ RES_PARATR_END enum RES_PARATR_LIST { RES_PARATR_LIST_BEGIN = RES_PARATR_END, - RES_PARATR_LIST_ID = RES_PARATR_LIST_BEGIN, // 75 - RES_PARATR_LIST_LEVEL, // 76 - RES_PARATR_LIST_ISRESTART, // 77 - RES_PARATR_LIST_RESTARTVALUE, // 78 - RES_PARATR_LIST_ISCOUNTED, // 79 + RES_PARATR_LIST_ID = RES_PARATR_LIST_BEGIN, // 76 + RES_PARATR_LIST_LEVEL, // 77 + RES_PARATR_LIST_ISRESTART, // 78 + RES_PARATR_LIST_RESTARTVALUE, // 79 + RES_PARATR_LIST_ISCOUNTED, // 80 RES_PARATR_LIST_END }; enum RES_FRMATR { RES_FRMATR_BEGIN = RES_PARATR_LIST_END, - RES_FILL_ORDER = RES_FRMATR_BEGIN, // 80 - RES_FRM_SIZE, // 81 - RES_PAPER_BIN, // 82 - RES_LR_SPACE, // 83 - RES_UL_SPACE, // 84 - RES_PAGEDESC, // 85 - RES_BREAK, // 86 - RES_CNTNT, // 87 - RES_HEADER, // 88 - RES_FOOTER, // 89 - RES_PRINT, // 90 - RES_OPAQUE, // 91 - RES_PROTECT, // 92 - RES_SURROUND, // 93 - RES_VERT_ORIENT, // 94 - RES_HORI_ORIENT, // 95 - RES_ANCHOR, // 96 - RES_BACKGROUND, // 97 - RES_BOX, // 98 - RES_SHADOW, // 99 - RES_FRMMACRO, // 100 - RES_COL, // 101 - RES_KEEP, // 102 - RES_URL, // 103 - RES_EDIT_IN_READONLY, // 104 - RES_LAYOUT_SPLIT, // 105 - RES_CHAIN, // 106 - RES_TEXTGRID, // 107 - RES_LINENUMBER , // 108 - RES_FTN_AT_TXTEND, // 109 - RES_END_AT_TXTEND, // 110 - RES_COLUMNBALANCE, // 111 - RES_FRAMEDIR, // 112 - RES_HEADER_FOOTER_EAT_SPACING, // 113 - RES_ROW_SPLIT, // 114 - RES_FOLLOW_TEXT_FLOW, // 115 - RES_COLLAPSING_BORDERS, // 116 - RES_WRAP_INFLUENCE_ON_OBJPOS, // 117 - RES_AUTO_STYLE, // 118 - RES_FRMATR_STYLE_NAME, // 119 - RES_FRMATR_CONDITIONAL_STYLE_NAME, // 120 + RES_FILL_ORDER = RES_FRMATR_BEGIN, // 81 + RES_FRM_SIZE, // 82 + RES_PAPER_BIN, // 83 + RES_LR_SPACE, // 84 + RES_UL_SPACE, // 85 + RES_PAGEDESC, // 86 + RES_BREAK, // 87 + RES_CNTNT, // 88 + RES_HEADER, // 89 + RES_FOOTER, // 90 + RES_PRINT, // 91 + RES_OPAQUE, // 92 + RES_PROTECT, // 93 + RES_SURROUND, // 94 + RES_VERT_ORIENT, // 95 + RES_HORI_ORIENT, // 96 + RES_ANCHOR, // 97 + RES_BACKGROUND, // 98 + RES_BOX, // 99 + RES_SHADOW, // 100 + RES_FRMMACRO, // 101 + RES_COL, // 102 + RES_KEEP, // 103 + RES_URL, // 104 + RES_EDIT_IN_READONLY, // 105 + RES_LAYOUT_SPLIT, // 106 + RES_CHAIN, // 107 + RES_TEXTGRID, // 108 + RES_LINENUMBER , // 109 + RES_FTN_AT_TXTEND, // 110 + RES_END_AT_TXTEND, // 111 + RES_COLUMNBALANCE, // 112 + RES_FRAMEDIR, // 113 + RES_HEADER_FOOTER_EAT_SPACING, // 114 + RES_ROW_SPLIT, // 115 + RES_FOLLOW_TEXT_FLOW, // 116 + RES_COLLAPSING_BORDERS, // 117 + RES_WRAP_INFLUENCE_ON_OBJPOS, // 118 + RES_AUTO_STYLE, // 119 + RES_FRMATR_STYLE_NAME, // 120 + RES_FRMATR_CONDITIONAL_STYLE_NAME, // 121 RES_FRMATR_END }; enum RES_GRFATR { RES_GRFATR_BEGIN = RES_FRMATR_END, - RES_GRFATR_MIRRORGRF = RES_GRFATR_BEGIN, // 121 - RES_GRFATR_CROPGRF, // 122 - - RES_GRFATR_ROTATION, // 123 - RES_GRFATR_LUMINANCE, // 124 - RES_GRFATR_CONTRAST, // 125 - RES_GRFATR_CHANNELR, // 126 - RES_GRFATR_CHANNELG, // 127 - RES_GRFATR_CHANNELB, // 128 - RES_GRFATR_GAMMA, // 129 - RES_GRFATR_INVERT, // 130 - RES_GRFATR_TRANSPARENCY, // 131 - RES_GRFATR_DRAWMODE, // 132 - - RES_GRFATR_DUMMY1, // 133 - RES_GRFATR_DUMMY2, // 134 - RES_GRFATR_DUMMY3, // 135 - RES_GRFATR_DUMMY4, // 136 - RES_GRFATR_DUMMY5, // 137 + RES_GRFATR_MIRRORGRF = RES_GRFATR_BEGIN, // 122 + RES_GRFATR_CROPGRF, // 123 + + RES_GRFATR_ROTATION, // 124 + RES_GRFATR_LUMINANCE, // 125 + RES_GRFATR_CONTRAST, // 126 + RES_GRFATR_CHANNELR, // 127 + RES_GRFATR_CHANNELG, // 128 + RES_GRFATR_CHANNELB, // 129 + RES_GRFATR_GAMMA, // 130 + RES_GRFATR_INVERT, // 131 + RES_GRFATR_TRANSPARENCY, // 132 + RES_GRFATR_DRAWMODE, // 133 + + RES_GRFATR_DUMMY1, // 134 + RES_GRFATR_DUMMY2, // 135 + RES_GRFATR_DUMMY3, // 136 + RES_GRFATR_DUMMY4, // 137 + RES_GRFATR_DUMMY5, // 138 RES_GRFATR_END }; enum RES_BOXATR { RES_BOXATR_BEGIN = RES_GRFATR_END, - RES_BOXATR_FORMAT = RES_BOXATR_BEGIN, // 138 - RES_BOXATR_FORMULA, // 139 - RES_BOXATR_VALUE, // 140 + RES_BOXATR_FORMAT = RES_BOXATR_BEGIN, // 139 + RES_BOXATR_FORMULA, // 140 + RES_BOXATR_VALUE, // 141 RES_BOXATR_END }; enum RES_UNKNOWNATR { RES_UNKNOWNATR_BEGIN = RES_BOXATR_END, - RES_UNKNOWNATR_CONTAINER = RES_UNKNOWNATR_BEGIN,// 141 + RES_UNKNOWNATR_CONTAINER = RES_UNKNOWNATR_BEGIN,// 142 RES_UNKNOWNATR_END }; diff --git a/sw/inc/modcfg.hxx b/sw/inc/modcfg.hxx index 14a3b2ac2f7e..b1fb71325b07 100644 --- a/sw/inc/modcfg.hxx +++ b/sw/inc/modcfg.hxx @@ -39,6 +39,7 @@ #include "tblenum.hxx" #include "itabenum.hxx" #include <tools/globname.hxx> +#include <editeng/svxenum.hxx> class SwModuleOptions; class InsCaptionOpt; @@ -77,6 +78,26 @@ class SwRevisionConfig : public utl::ConfigItem void SetModified(){ConfigItem::SetModified();} }; +class SwCompareConfig : public utl::ConfigItem +{ + friend class SwModuleOptions; + + sal_uInt16 eCmpMode; //Compare/CompareDocuments; + sal_Bool bUseRsid; //Compare/Settings/Use RSID + sal_Bool bIgnorePieces; //Compare/Settings/Ignore pieces of length + sal_uInt16 nPieceLen; //Compare/Settings/Ignore pieces of length + + const com::sun::star::uno::Sequence<rtl::OUString>& GetPropertyNames(); + public: + SwCompareConfig(); + ~SwCompareConfig(); + + virtual void Commit(); + virtual void Notify( const ::com::sun::star::uno::Sequence< rtl::OUString >& ){ }; + void Load(); + void SetModified() {ConfigItem::SetModified(); } +}; + class SwInsertConfig : public utl::ConfigItem { friend class SwModuleOptions; @@ -167,6 +188,8 @@ class SW_DLLPUBLIC SwModuleOptions SwMiscConfig aMiscConfig; + SwCompareConfig aCompareConfig; + //fiscus: don't show tips of text fields - it's not part of the configuration! sal_Bool bHideFieldTips : 1; @@ -309,20 +332,37 @@ public: //convert word delimiter from or to user interface static String ConvertWordDelimiter(const String& rDelim, sal_Bool bFromUI); - sal_Bool IsShowIndexPreview() const {return aMiscConfig.bShowIndexPreview;} + sal_Bool IsShowIndexPreview() const {return aMiscConfig.bShowIndexPreview;} void SetShowIndexPreview(sal_Bool bSet) {aMiscConfig.bShowIndexPreview = bSet; aMiscConfig.SetModified();} - sal_Bool IsDefaultFontInCurrDocOnly() const { return aMiscConfig.bDefaultFontsInCurrDocOnly;} + sal_Bool IsDefaultFontInCurrDocOnly() const { return aMiscConfig.bDefaultFontsInCurrDocOnly;} void SetDefaultFontInCurrDocOnly(sal_Bool bSet) { aMiscConfig.bDefaultFontsInCurrDocOnly = bSet; aMiscConfig.SetModified(); } - sal_Bool IsHideFieldTips() const {return bHideFieldTips;} + sal_Bool IsHideFieldTips() const {return bHideFieldTips;} void SetHideFieldTips(sal_Bool bSet) {bHideFieldTips = bSet;} + + SvxCompareMode GetCompareMode() const { return (SvxCompareMode)aCompareConfig.eCmpMode; } + void SetCompareMode( SvxCompareMode eMode ) { aCompareConfig.eCmpMode = eMode; + aCompareConfig.SetModified(); } + + sal_Bool IsUseRsid() const { return aCompareConfig.bUseRsid; } + void SetUseRsid( sal_Bool b ) { aCompareConfig.bUseRsid = b; + aCompareConfig.SetModified(); } + + sal_Bool IsIgnorePieces() const { return aCompareConfig.bIgnorePieces; } + void SetIgnorePieces( sal_Bool b ) { aCompareConfig.bIgnorePieces = b; + aCompareConfig.SetModified(); } + + sal_uInt16 GetPieceLen() const { return aCompareConfig.nPieceLen; } + void SetPieceLen( sal_uInt16 nLen ) { aCompareConfig.nPieceLen = nLen; + aCompareConfig.SetModified(); } + }; #endif diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx index b4a772d2455f..b412aa43fadf 100644 --- a/sw/inc/ndtxt.hxx +++ b/sw/inc/ndtxt.hxx @@ -803,6 +803,13 @@ public: virtual void dumpAsXml( xmlTextWriterPtr writer = NULL ); + sal_uInt32 GetRsid( xub_StrLen nStt, xub_StrLen nEnd ) const; + sal_uInt32 GetParRsid() const; + + bool CompareRsid( const SwTxtNode &rTxtNode, xub_StrLen nStt1, xub_StrLen nStt2, + xub_StrLen nEnd1 = 0, xub_StrLen nEnd2 = 0 ) const; + bool CompareParRsid( const SwTxtNode &rTxtNode ) const; + DECL_FIXEDMEMPOOL_NEWDEL(SwTxtNode) }; diff --git a/sw/inc/swmodule.hxx b/sw/inc/swmodule.hxx index 763923725958..aca0d48925db 100644 --- a/sw/inc/swmodule.hxx +++ b/sw/inc/swmodule.hxx @@ -40,6 +40,7 @@ #include <fldupde.hxx> #include <com/sun/star/linguistic2/XLinguServiceEventListener.hpp> #include <com/sun/star/linguistic2/XLanguageGuessing.hpp> +#include <editeng/svxenum.hxx> class SvStringsDtor; class Color; @@ -210,6 +211,15 @@ public: sal_uInt16 GetRedlineMarkPos(); const Color& GetRedlineMarkColor(); + SvxCompareMode GetCompareMode() const; + void SetCompareMode( SvxCompareMode eMode ); + sal_Bool IsUseRsid() const; + void SetUseRsid( sal_Bool b ); + sal_Bool IsIgnorePieces() const; + void SetIgnorePieces( sal_Bool b ); + sal_uInt16 GetPieceLen() const; + void SetPieceLen( sal_uInt16 nLen ); + // Return defined DocStat - WordDelimiter. const String& GetDocStatWordDelim() const; diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx index 8df75ee59bfb..e70963a19ccd 100644 --- a/sw/inc/unoprnms.hxx +++ b/sw/inc/unoprnms.hxx @@ -806,7 +806,9 @@ enum SwPropNameIds /* 0742 */ UNO_NAME_SEPARATOR_LINE_STYLE, /* 0743 */ UNO_NAME_FOOTNOTE_LINE_STYLE, /* 0744 */ UNO_NAME_EMBEDDED_OBJECT, -/* 0745 */ SW_PROPNAME_END +/* 0745 */ UNO_NAME_RSID, +/* 0746 */ UNO_NAME_PARRSID, +/* 0747 */ SW_PROPNAME_END // new items in this array must match SwPropNameTab aPropNameTab }; diff --git a/sw/source/core/bastyp/init.cxx b/sw/source/core/bastyp/init.cxx index c80a8b80d125..e24a7f402f69 100644 --- a/sw/source/core/bastyp/init.cxx +++ b/sw/source/core/bastyp/init.cxx @@ -129,6 +129,7 @@ #include <fmtfollowtextflow.hxx> #include <fmtwrapinfluenceonobjpos.hxx> +#include <editeng/rsiditem.hxx> #include <fmtmeta.hxx> @@ -298,8 +299,8 @@ SfxItemInfo aSlotTab[] = { SID_ATTR_CHAR_RELIEF, SFX_ITEM_POOLABLE }, // RES_CHRATR_RELIEF { SID_ATTR_CHAR_HIDDEN, SFX_ITEM_POOLABLE }, // RES_CHRATR_HIDDEN { SID_ATTR_CHAR_OVERLINE, SFX_ITEM_POOLABLE }, // RES_CHRATR_OVERLINE + { 0, SFX_ITEM_POOLABLE }, // RES_CHRATR_RSID { 0, SFX_ITEM_POOLABLE }, // RES_CHRATR_DUMMY1 - { 0, SFX_ITEM_POOLABLE }, // RES_CHRATR_DUMMY2 { 0, 0 }, // RES_TXTATR_REFMARK { 0, 0 }, // RES_TXTATR_TOXMARK @@ -340,7 +341,7 @@ SfxItemInfo aSlotTab[] = { SID_ATTR_BORDER_CONNECT, SFX_ITEM_POOLABLE }, // RES_PARATR_CONNECT_BORDER { SID_ATTR_PARA_OUTLINE_LEVEL, SFX_ITEM_POOLABLE }, // RES_PARATR_OUTLINELEVEL //#outline level,zhaojianwei - + { 0, SFX_ITEM_POOLABLE }, // RES_PARATR_RSID { 0, SFX_ITEM_POOLABLE }, // RES_PARATR_LIST_ID { 0, SFX_ITEM_POOLABLE }, // RES_PARATR_LIST_LEVEL { 0, SFX_ITEM_POOLABLE }, // RES_PARATR_LIST_ISRESTART @@ -478,6 +479,7 @@ void _InitCore() aAttrTab[ RES_CHRATR_SHADOWED- POOLATTR_BEGIN ] = new SvxShadowedItem( sal_False, RES_CHRATR_SHADOWED ); aAttrTab[ RES_CHRATR_UNDERLINE- POOLATTR_BEGIN ] = new SvxUnderlineItem( UNDERLINE_NONE, RES_CHRATR_UNDERLINE ); aAttrTab[ RES_CHRATR_WEIGHT- POOLATTR_BEGIN ] = new SvxWeightItem( WEIGHT_NORMAL, RES_CHRATR_WEIGHT ); + aAttrTab[ RES_CHRATR_RSID - POOLATTR_BEGIN ] = new SvxRsidItem( 0, RES_CHRATR_RSID ); aAttrTab[ RES_CHRATR_WORDLINEMODE- POOLATTR_BEGIN ] = new SvxWordLineModeItem( sal_False, RES_CHRATR_WORDLINEMODE ); aAttrTab[ RES_CHRATR_AUTOKERN- POOLATTR_BEGIN ] = new SvxAutoKernItem( sal_False, RES_CHRATR_AUTOKERN ); aAttrTab[ RES_CHRATR_BLINK - POOLATTR_BEGIN ] = new SvxBlinkItem( sal_False, RES_CHRATR_BLINK ); @@ -509,7 +511,7 @@ void _InitCore() // CharakterAttr - Dummies aAttrTab[ RES_CHRATR_DUMMY1 - POOLATTR_BEGIN ] = new SfxBoolItem( RES_CHRATR_DUMMY1 ); - aAttrTab[ RES_CHRATR_DUMMY2 - POOLATTR_BEGIN ] = new SfxBoolItem( RES_CHRATR_DUMMY2 ); + // CharakterAttr - Dummies aAttrTab[ RES_TXTATR_AUTOFMT- POOLATTR_BEGIN ] = new SwFmtAutoFmt; @@ -557,6 +559,7 @@ void _InitCore() aAttrTab[ RES_PARATR_CONNECT_BORDER - POOLATTR_BEGIN ] = new SwParaConnectBorderItem; aAttrTab[ RES_PARATR_OUTLINELEVEL - POOLATTR_BEGIN ] = new SfxUInt16Item( RES_PARATR_OUTLINELEVEL, 0 );//#outline level,zhaojianwei + aAttrTab[ RES_PARATR_RSID - POOLATTR_BEGIN ] = new SvxRsidItem( 0, RES_PARATR_RSID ); aAttrTab[ RES_PARATR_LIST_ID - POOLATTR_BEGIN ] = new SfxStringItem( RES_PARATR_LIST_ID, aEmptyStr ); aAttrTab[ RES_PARATR_LIST_LEVEL - POOLATTR_BEGIN ] = new SfxInt16Item( RES_PARATR_LIST_LEVEL, 0 ); diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx index 3a7becd66462..8be6aa72ab5b 100644..100755 --- a/sw/source/core/doc/doc.cxx +++ b/sw/source/core/doc/doc.cxx @@ -34,6 +34,8 @@ #include <tools/shl.hxx> #include <tools/globname.hxx> #include <svx/svxids.hrc> +#include <rtl/random.h> + #include <com/sun/star/i18n/WordType.hdl> #include <com/sun/star/i18n/ForbiddenCharacters.hdl> #include <com/sun/star/lang/XMultiServiceFactory.hpp> @@ -59,6 +61,7 @@ #include <editeng/forbiddencharacterstable.hxx> #include <svx/svdmodel.hxx> #include <editeng/pbinitem.hxx> +#include <editeng/rsiditem.hxx> #include <unotools/charclass.hxx> #include <unotools/localedatawrapper.hxx> @@ -456,6 +459,33 @@ void SwDoc::setLinkUpdateMode( /*[in]*/sal_uInt16 eMode ) nLinkUpdMode = eMode; } +sal_uInt32 SwDoc::getRsid() const +{ + return nRsid; +} + +void SwDoc::setRsid( sal_uInt32 nVal ) +{ + // Increase the rsid with a random number smaller than 2^17. This way we + // expect to be able to edit a document 2^12 times before rsid overflows. + sal_uInt32 nIncrease = 0; + static rtlRandomPool aPool = rtl_random_createPool(); + rtl_random_getBytes( aPool, &nIncrease, sizeof ( nIncrease ) ); + nIncrease &= ( 1<<17 ) - 1; + nIncrease++; // make sure the new rsid is not the same + nRsid = nVal + nIncrease; +} + +sal_uInt32 SwDoc::getRsidRoot() const +{ + return nRsidRoot; +} + +void SwDoc::setRsidRoot( sal_uInt32 nVal ) +{ + nRsidRoot = nVal; +} + SwFldUpdateFlags SwDoc::getFieldUpdateFlags( /*[in]*/bool bGlobalSettings ) const { SwFldUpdateFlags eRet = eFldUpdMode; @@ -731,6 +761,15 @@ bool SwDoc::SplitNode( const SwPosition &rPos, bool bChkTableStart ) } } + // Update the rsid of the old and the new node unless + // the old node is split at the beginning or at the end + SwTxtNode *pTxtNode = rPos.nNode.GetNode().GetTxtNode(); + xub_StrLen nPos = rPos.nContent.GetIndex(); + if( pTxtNode && nPos && nPos != pTxtNode->Len() ) + { + UpdateParRsid( pTxtNode ); + } + //JP 28.01.97: Special case for SplitNode at table start: // If it is at the beginning of a Doc/Fly/Footer/... or right at after a table // then insert a paragraph before it. @@ -1066,6 +1105,41 @@ SwFieldType *SwDoc::GetSysFldType( const sal_uInt16 eWhich ) const return 0; } +// Set the rsid from nStt to nEnd of pTxtNode to the current session number +bool SwDoc::UpdateRsid( SwTxtNode *pTxtNode, xub_StrLen nStt, xub_StrLen nEnd ) +{ + if ( !pTxtNode ) + { + return false; + } + + SvxRsidItem aRsid( nRsid, RES_CHRATR_RSID ); + SwTxtAttr* pAttr = MakeTxtAttr( *this, aRsid, nStt, nEnd ); + return pTxtNode->InsertHint( pAttr, INS_DEFAULT ); +} + +// Set the rsid of the next nLen symbols of rRg to the current session number +bool SwDoc::UpdateRsid( const SwPaM &rRg, const xub_StrLen nLen ) +{ + const SwPosition* pPos = rRg.GetPoint(); + SwTxtNode *pTxtNode = pPos->nNode.GetNode().GetTxtNode(); + xub_StrLen nInsPos = pPos->nContent.GetIndex(); + + return UpdateRsid( pTxtNode, nInsPos - nLen, nInsPos ); +} + +bool SwDoc::UpdateParRsid( SwTxtNode *pTxtNode, sal_uInt32 nVal ) +{ + if ( !pTxtNode ) + { + return false; + } + + SvxRsidItem aRsid( nVal ? nVal : nRsid, RES_PARATR_RSID ); + return pTxtNode->SetAttr( aRsid ); +} + + /************************************************************************* * void SetDocStat( const SwDocStat& rStat ); *************************************************************************/ diff --git a/sw/source/core/doc/doccomp.cxx b/sw/source/core/doc/doccomp.cxx index bd3ee2cdc3dd..1da77046d5cf 100644 --- a/sw/source/core/doc/doccomp.cxx +++ b/sw/source/core/doc/doccomp.cxx @@ -32,7 +32,9 @@ #include <editeng/crsditem.hxx> #include <editeng/colritem.hxx> #include <editeng/boxitem.hxx> +#include <editeng/svxenum.hxx> #include <editeng/udlnitem.hxx> +#include <swmodule.hxx> #include <doc.hxx> #include <IDocumentUndoRedo.hxx> #include <docary.hxx> @@ -49,6 +51,9 @@ #include <vector> +#include <set> +#include <cctype> + using namespace ::com::sun::star; using ::std::vector; @@ -189,6 +194,147 @@ public: Compare( sal_uLong nDiff, CompareData& rData1, CompareData& rData2 ); }; +class ArrayComparator +{ +public: + virtual bool Compare( int nIdx1, int nIdx2 ) const = 0; + virtual int GetLen1() const = 0; + virtual int GetLen2() const = 0; +}; + +// Consider two lines equal if similar enough (e.g. look like different +// versions of the same paragraph) +class LineArrayComparator : public ArrayComparator +{ +private: + int nLen1, nLen2; + const CompareData &rData1, &rData2; + int nFirst1, nFirst2; + +public: + LineArrayComparator( const CompareData &rD1, const CompareData &rD2, + int nStt1, int nEnd1, int nStt2, int nEnd2 ); + + virtual bool Compare( int nIdx1, int nIdx2 ) const; + virtual int GetLen1() const { return nLen1; } + virtual int GetLen2() const { return nLen2; } +}; + +class WordArrayComparator : public ArrayComparator +{ +private: + const SwTxtNode *pTxtNd1, *pTxtNd2; + int *pPos1, *pPos2; + int nCnt1, nCnt2; // number of words + const unsigned nMul; + + void CalcPositions( int *pPos, const SwTxtNode *pTxtNd, int &nCnt ); + +public: + WordArrayComparator( const SwTxtNode *pNode1, const SwTxtNode *pNode2 ); + ~WordArrayComparator(); + + virtual bool Compare( int nIdx1, int nIdx2 ) const; + virtual int GetLen1() const { return nCnt1; } + virtual int GetLen2() const { return nCnt2; } + int GetCharSequence( const int *pWordLcs1, const int *pWordLcs2, + int *pSubseq1, int *pSubseq2, int nLcsLen ); +}; + +class CharArrayComparator : public ArrayComparator +{ +private: + const SwTxtNode *pTxtNd1, *pTxtNd2; + +public: + CharArrayComparator( const SwTxtNode *pNode1, const SwTxtNode *pNode2 ) + : pTxtNd1( pNode1 ), pTxtNd2( pNode2 ) + { + } + + virtual bool Compare( int nIdx1, int nIdx2 ) const; + virtual int GetLen1() const { return pTxtNd1->GetTxt().Len(); } + virtual int GetLen2() const { return pTxtNd2->GetTxt().Len(); } +}; + +// Options set in Tools->Options->Writer->Comparison +struct CmpOptionsContainer +{ + SvxCompareMode eCmpMode; + int nIgnoreLen; + bool bUseRsid; +} CmpOptions; + +class CommonSubseq +{ +private: + int *pData; + int nSize; + +protected: + ArrayComparator &rCmp; + + CommonSubseq( ArrayComparator &rComparator, int nMaxSize ) + : nSize( nMaxSize ), rCmp( rComparator ) + { + pData = new int[ nSize ]; + } + + ~CommonSubseq() + { + delete[] pData; + } + + int FindLCS( int *pLcs1 = 0, int *pLcs2 = 0, int nStt1 = 0, + int nEnd1 = 0, int nStt2 = 0, int nEnd2 = 0 ); + +public: + int IgnoreIsolatedPieces( int *pLcs1, int *pLcs2, int nLen1, int nLen2, + int nLcsLen, int nPieceLen ); +}; + +// Use Hirschberg's algrithm to find LCS in linear space +class LgstCommonSubseq: public CommonSubseq +{ +private: + static const int CUTOFF = 1<<20; // Stop recursion at this value + + int *pL1, *pL2; + int *pBuff1, *pBuff2; + + void FindL( int *pL, int nStt1, int nEnd1, int nStt2, int nEnd2 ); + int HirschbergLCS( int *pLcs1, int *pLcs2, int nStt1, int nEnd1, + int nStt2, int nEnd2 ); + +public: + LgstCommonSubseq( ArrayComparator &rComparator ); + ~LgstCommonSubseq(); + + int Find( int *pSubseq1, int *pSubseq2 ); +}; + +// Find a common subsequence in linear time +class FastCommonSubseq: private CommonSubseq +{ +private: + static const int CUTOFF = 2056; + + int FindFastCS( int *pSeq1, int *pSeq2, int nStt1, int nEnd1, + int nStt2, int nEnd2 ); + +public: + FastCommonSubseq( ArrayComparator &rComparator ) + : CommonSubseq( rComparator, CUTOFF ) + { + } + + int Find( int *pSubseq1, int *pSubseq2 ) + { + return FindFastCS( pSubseq1, pSubseq2, 0, rCmp.GetLen1(), + 0, rCmp.GetLen2() ); + } +}; + CompareLine::~CompareLine() {} CompareData::CompareData() @@ -250,20 +396,16 @@ sal_uLong CompareData::ShowDiffs( const CompareData& rData ) { if( rData.GetChanged( nStt1 ) || GetChanged( nStt2 ) ) { + // Find a region of different lines between two pairs of identical + // lines. sal_uLong nSav1 = nStt1, nSav2 = nStt2; while( nStt1 < nLen1 && rData.GetChanged( nStt1 )) ++nStt1; while( nStt2 < nLen2 && GetChanged( nStt2 )) ++nStt2; - // rData is the original, - // "this" recieves the changes - if( nSav2 != nStt2 && nSav1 != nStt1 ) - CheckForChangesInLine( rData, nSav1, nStt1, nSav2, nStt2 ); + // Check if there are changed lines (only slightly different) and + // compare them in detail. + CheckForChangesInLine( rData, nSav1, nStt1, nSav2, nStt2 ); - if( nSav2 != nStt2 ) - ShowInsert( nSav2, nStt2 ); - - if( nSav1 != nStt1 ) - ShowDelete( rData, nSav1, nStt1, nStt2 ); ++nCnt; } ++nStt1, ++nStt2; @@ -968,7 +1110,8 @@ sal_Bool SwCompareLine::CompareNode( const SwNode& rDstNd, const SwNode& rSrcNd switch( rDstNd.GetNodeType() ) { case ND_TEXTNODE: - bRet = CompareTxtNd( (SwTxtNode&)rDstNd, (SwTxtNode&)rSrcNd ); + bRet = CompareTxtNd( (SwTxtNode&)rDstNd, (SwTxtNode&)rSrcNd ) + && ( !CmpOptions.bUseRsid || ((SwTxtNode&)rDstNd).CompareParRsid( (SwTxtNode&)rSrcNd ) ); break; case ND_TABLENODE: @@ -1136,66 +1279,126 @@ sal_Bool SwCompareLine::ChangesInLine( const SwCompareLine& rLine, SwPaM *& rpInsRing, SwPaM*& rpDelRing ) const { sal_Bool bRet = sal_False; + + // Only compare textnodes if( ND_TEXTNODE == rNode.GetNodeType() && ND_TEXTNODE == rLine.GetNode().GetNodeType() ) { - SwTxtNode& rDestNd = *(SwTxtNode*)rNode.GetTxtNode(); + SwTxtNode& rDstNd = *(SwTxtNode*)rNode.GetTxtNode(); const SwTxtNode& rSrcNd = *rLine.GetNode().GetTxtNode(); + SwDoc* pDstDoc = rDstNd.GetDoc(); - xub_StrLen nDEnd = rDestNd.GetTxt().Len(), nSEnd = rSrcNd.GetTxt().Len(); - xub_StrLen nStt; - xub_StrLen nEnd; + int nLcsLen = 0; - for( nStt = 0, nEnd = Min( nDEnd, nSEnd ); nStt < nEnd; ++nStt ) - if( rDestNd.GetTxt().GetChar( nStt ) != - rSrcNd.GetTxt().GetChar( nStt ) ) - break; + int nDstLen = rDstNd.GetTxt().Len(); + int nSrcLen = rSrcNd.GetTxt().Len(); - while( nStt < nDEnd && nStt < nSEnd ) + int nMinLen = std::min( nDstLen , nSrcLen ); + int nAvgLen = ( nDstLen + nSrcLen )/2; + + int *pLcsDst = new int[ nMinLen + 1 ]; + int *pLcsSrc = new int[ nMinLen + 1 ]; + + if( CmpOptions.eCmpMode == SVX_CMP_BY_WORD ) { - --nDEnd, --nSEnd; - if( rDestNd.GetTxt().GetChar( nDEnd ) != - rSrcNd.GetTxt().GetChar( nSEnd ) ) + int *pTmpLcsDst = new int[ nMinLen + 1 ]; + int *pTmpLcsSrc = new int[ nMinLen + 1 ]; + + WordArrayComparator aCmp( &rDstNd, &rSrcNd ); + + LgstCommonSubseq aSeq( aCmp ); + + nLcsLen = aSeq.Find( pTmpLcsDst, pTmpLcsSrc ); + + if( CmpOptions.nIgnoreLen ) { - ++nDEnd, ++nSEnd; - break; + nLcsLen = aSeq.IgnoreIsolatedPieces( pTmpLcsDst, pTmpLcsSrc, + aCmp.GetLen1(), aCmp.GetLen2(), + nLcsLen, CmpOptions.nIgnoreLen ); } + + nLcsLen = aCmp.GetCharSequence( pTmpLcsDst, pTmpLcsSrc, + pLcsDst, pLcsSrc, nLcsLen ); + + delete[] pTmpLcsDst; + delete[] pTmpLcsSrc; } + else + { + CharArrayComparator aCmp( &rDstNd, &rSrcNd ); + LgstCommonSubseq aSeq( aCmp ); + + nLcsLen = aSeq.Find( pLcsDst, pLcsSrc ); - if( nStt || !nDEnd || !nSEnd || nDEnd < rDestNd.GetTxt().Len() || - nSEnd < rSrcNd.GetTxt().Len() ) + if( CmpOptions.nIgnoreLen ) + { + nLcsLen = aSeq.IgnoreIsolatedPieces( pLcsDst, pLcsSrc, nDstLen, + nSrcLen, nLcsLen, + CmpOptions.nIgnoreLen ); + } + } + + // find the sum of the squares of the continuous substrings + int nSqSum = 0; + int nCnt = 1; + for( int i = 0; i < nLcsLen; i++ ) { - // The newly inserted is now between nStt and nDEnd - // and the deleted is between nStt and nSEnd - SwDoc* pDoc = rDestNd.GetDoc(); - SwPaM aPam( rDestNd, nDEnd ); - if( nStt != nDEnd ) + if( i != nLcsLen - 1 && pLcsDst[i] + 1 == pLcsDst[i + 1] + && pLcsSrc[i] + 1 == pLcsSrc[i + 1] ) + { + nCnt++; + } + else + { + nSqSum += nCnt*nCnt; + nCnt = 1; + } + } + + // Don't compare if there aren't enough similarities + if ( nAvgLen >= 8 && nSqSum*32 < nAvgLen*nAvgLen ) + { + return sal_False; + } + + // Show the differences + int nSkip = 0; + for( int i = 0; i <= nLcsLen; i++ ) + { + int nDstFrom = i ? (pLcsDst[i - 1] + 1) : 0; + int nDstTo = ( i == nLcsLen ) ? nDstLen : pLcsDst[i]; + int nSrcFrom = i ? (pLcsSrc[i - 1] + 1) : 0; + int nSrcTo = ( i == nLcsLen ) ? nSrcLen : pLcsSrc[i]; + + SwPaM aPam( rDstNd, nDstTo + nSkip ); + + if ( nDstFrom < nDstTo ) { SwPaM* pTmp = new SwPaM( *aPam.GetPoint(), rpInsRing ); if( !rpInsRing ) rpInsRing = pTmp; - pTmp->SetMark(); - pTmp->GetMark()->nContent = nStt; + pTmp->GetMark()->nContent = nDstFrom + nSkip; } - if( nStt != nSEnd ) + if ( nSrcFrom < nSrcTo ) { - { - ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo()); - SwPaM aCpyPam( rSrcNd, nStt ); - aCpyPam.SetMark(); - aCpyPam.GetPoint()->nContent = nSEnd; - aCpyPam.GetDoc()->CopyRange( aCpyPam, *aPam.GetPoint(), - false ); - } + sal_Bool bUndo = pDstDoc->GetIDocumentUndoRedo().DoesUndo(); + pDstDoc->GetIDocumentUndoRedo().DoUndo( sal_False ); + SwPaM aCpyPam( rSrcNd, nSrcFrom ); + aCpyPam.SetMark(); + aCpyPam.GetPoint()->nContent = nSrcTo; + aCpyPam.GetDoc()->CopyRange( aCpyPam, *aPam.GetPoint(), + false ); + pDstDoc->GetIDocumentUndoRedo().DoUndo( bUndo ); SwPaM* pTmp = new SwPaM( *aPam.GetPoint(), rpDelRing ); if( !rpDelRing ) rpDelRing = pTmp; pTmp->SetMark(); - pTmp->GetMark()->nContent = nDEnd; + pTmp->GetMark()->nContent = nDstTo + nSkip; + nSkip += nSrcTo - nSrcFrom; if( rpInsRing ) { @@ -1204,9 +1407,14 @@ sal_Bool SwCompareLine::ChangesInLine( const SwCompareLine& rLine, *pCorr->GetPoint() = *pTmp->GetMark(); } } - bRet = sal_True; } + + delete[] pLcsDst; + delete[] pLcsSrc; + + bRet = sal_True; } + return bRet; } @@ -1381,15 +1589,52 @@ void SwCompareData::CheckForChangesInLine( const CompareData& rData, sal_uLong& rStt, sal_uLong& rEnd, sal_uLong& rThisStt, sal_uLong& rThisEnd ) { - while( rStt < rEnd && rThisStt < rThisEnd ) + LineArrayComparator aCmp( (CompareData&)*this, rData, rThisStt, rThisEnd, + rStt, rEnd ); + + int nMinLen = std::min( aCmp.GetLen1(), aCmp.GetLen2() ); + int *pLcsDst = new int[ nMinLen ]; + int *pLcsSrc = new int[ nMinLen ]; + + FastCommonSubseq subseq( aCmp ); + int nLcsLen = subseq.Find( pLcsDst, pLcsSrc ); + for (int i = 0; i <= nLcsLen; i++) { - SwCompareLine* pDstLn = (SwCompareLine*)GetLine( rThisStt ); - SwCompareLine* pSrcLn = (SwCompareLine*)rData.GetLine( rStt ); - if( !pDstLn->ChangesInLine( *pSrcLn, pInsRing, pDelRing ) ) - break; + // Beginning of inserted lines (inclusive) + int nDstFrom = i ? pLcsDst[i - 1] + 1 : 0; + // End of inserted lines (exclusive) + int nDstTo = ( i == nLcsLen ) ? aCmp.GetLen1() : pLcsDst[i]; + // Begining of deleted lines (inclusive) + int nSrcFrom = i ? pLcsSrc[i - 1] + 1 : 0; + // End of deleted lines (exclusive) + int nSrcTo = ( i == nLcsLen ) ? aCmp.GetLen2() : pLcsSrc[i]; + + if( i ) + { + SwCompareLine* pDstLn = (SwCompareLine*)GetLine( rThisStt + nDstFrom - 1 ); + SwCompareLine* pSrcLn = (SwCompareLine*)rData.GetLine( rStt + nSrcFrom - 1 ); + + // Show differences in detail for lines that + // were matched as only slightly different + if( !pDstLn->ChangesInLine( *pSrcLn, pInsRing, pDelRing ) ) + { + ShowInsert( rThisStt + nDstFrom - 1, rThisStt + nDstFrom ); + ShowDelete( rData, rStt + nSrcFrom - 1, rStt + nSrcFrom, + rThisStt + nDstFrom ); + } + } + + // Lines missing from source are inserted + if( nDstFrom != nDstTo ) + { + ShowInsert( rThisStt + nDstFrom, rThisStt + nDstTo ); + } - ++rStt; - ++rThisStt; + // Lines missing from destination are deleted + if( nSrcFrom != nSrcTo ) + { + ShowDelete( rData, rStt + nSrcFrom, rStt + nSrcTo, rThisStt + nDstTo ); + } } } @@ -1537,6 +1782,29 @@ long SwDoc::CompareDoc( const SwDoc& rDoc ) long nRet = 0; + // Get comparison options + CmpOptions.eCmpMode = SW_MOD()->GetCompareMode(); + if( CmpOptions.eCmpMode == SVX_CMP_AUTO ) + { + if( getRsidRoot() == rDoc.getRsidRoot() ) + { + CmpOptions.eCmpMode = SVX_CMP_BY_CHAR; + CmpOptions.bUseRsid = true; + CmpOptions.nIgnoreLen = 2; + } + else + { + CmpOptions.eCmpMode = SVX_CMP_BY_WORD; + CmpOptions.bUseRsid = false; + CmpOptions.nIgnoreLen = 3; + } + } + else + { + CmpOptions.bUseRsid = getRsidRoot() == rDoc.getRsidRoot() && SW_MOD()->IsUseRsid(); + CmpOptions.nIgnoreLen = SW_MOD()->IsIgnorePieces() ? SW_MOD()->GetPieceLen() : 0; + } + GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL); sal_Bool bDocWasModified = IsModified(); SwDoc& rSrcDoc = (SwDoc&)rDoc; @@ -1831,4 +2099,566 @@ long SwDoc::MergeDoc( const SwDoc& rDoc ) return nRet; } +LineArrayComparator::LineArrayComparator( const CompareData &rD1, + const CompareData &rD2, int nStt1, + int nEnd1, int nStt2, int nEnd2 ) + : rData1( rD1 ), rData2( rD2 ), nFirst1( nStt1 ), nFirst2( nStt2 ) +{ + nLen1 = nEnd1 - nStt1; + nLen2 = nEnd2 - nStt2; +} + +bool LineArrayComparator::Compare( int nIdx1, int nIdx2 ) const +{ + if( nIdx1 < 0 || nIdx2 < 0 || nIdx1 >= nLen1 || nIdx2 >= nLen2 ) + { + OSL_ENSURE( 0, "Index out of range!" ); + return false; + } + + const SwTxtNode *pTxtNd1 = ( ( SwCompareLine* )rData1.GetLine( nFirst1 + nIdx1 ) )->GetNode().GetTxtNode(); + const SwTxtNode *pTxtNd2 = ( ( SwCompareLine* )rData2.GetLine( nFirst2 + nIdx2 ) )->GetNode().GetTxtNode(); + + if( !pTxtNd1 || !pTxtNd2 + || ( CmpOptions.bUseRsid && !pTxtNd1->CompareParRsid( *pTxtNd2 ) ) ) + { + return false; + } + + int nPar1Len = pTxtNd1->Len(); + int nPar2Len = pTxtNd2->Len(); + + if( std::min( nPar1Len, nPar2Len ) * 3 < std::max( nPar1Len, nPar2Len ) ) + { + return false; + } + + int nBorderLen = ( nPar1Len + nPar2Len )/16; + + if( nBorderLen < 3 ) + { + nBorderLen = std::min( 3, std::min( nPar1Len, nPar2Len ) ); + } + + std::set<unsigned> aHashes; + unsigned nHash = 0; + unsigned nMul = 251; + unsigned nPow = 1; + int i; + + for( i = 0; i < nBorderLen - 1; i++ ) + { + nPow *= nMul; + } + for( i = 0; i < nBorderLen; i++ ) + { + nHash = nHash*nMul + pTxtNd1->GetTxt().GetChar( i ); + } + aHashes.insert( nHash ); + for( ; i < nPar1Len; i++ ) + { + nHash = nHash - nPow*pTxtNd1->GetTxt().GetChar( i - nBorderLen ); + nHash = nHash*nMul + pTxtNd1->GetTxt().GetChar( i ); + + aHashes.insert( nHash ); + } + + nHash = 0; + for( i = 0; i < nBorderLen; i++ ) + { + nHash = nHash*nMul + pTxtNd2->GetTxt().GetChar( i ); + } + + if( aHashes.find( nHash ) != aHashes.end() ) + { + return true; + } + + for( ; i < nPar2Len; i++ ) + { + nHash = nHash - nPow*pTxtNd2->GetTxt().GetChar( i - nBorderLen ); + nHash = nHash*nMul + pTxtNd2->GetTxt().GetChar( i ); + if( aHashes.find( nHash ) != aHashes.end() ) + { + return true; + } + } + return false; +} + +bool CharArrayComparator::Compare( int nIdx1, int nIdx2 ) const +{ + if( nIdx1 < 0 || nIdx2 < 0 || nIdx1 >= GetLen1() || nIdx2 >= GetLen2() ) + { + OSL_ENSURE( 0, "Index out of range!" ); + return false; + } + + return ( !CmpOptions.bUseRsid + || pTxtNd1->CompareRsid( *pTxtNd2, nIdx1 + 1, nIdx2 + 1 ) ) + && pTxtNd1->GetTxt().GetChar( nIdx1 ) + == pTxtNd2->GetTxt().GetChar( nIdx2 ); +} + +WordArrayComparator::WordArrayComparator( const SwTxtNode *pNode1, + const SwTxtNode *pNode2 ) + : pTxtNd1( pNode1 ), pTxtNd2( pNode2 ), nMul( 251 ) +{ + pPos1 = new int[ pTxtNd1->GetTxt().Len() + 1 ]; + pPos2 = new int[ pTxtNd2->GetTxt().Len() + 1 ]; + + CalcPositions( pPos1, pTxtNd1, nCnt1 ); + CalcPositions( pPos2, pTxtNd2, nCnt2 ); +} + +WordArrayComparator::~WordArrayComparator() +{ + delete[] pPos1; + delete[] pPos2; +} + +bool WordArrayComparator::Compare( int nIdx1, int nIdx2 ) const +{ + int nLen = pPos1[ nIdx1 + 1 ] - pPos1[ nIdx1 ]; + if( nLen != pPos2[ nIdx2 + 1 ] - pPos2[ nIdx2 ] ) + { + return false; + } + for( int i = 0; i < nLen; i++) + { + if( pTxtNd1->GetTxt().GetChar( pPos1[ nIdx1 ] + i ) + != pTxtNd2->GetTxt().GetChar( pPos2[ nIdx2 ] + i ) + || ( CmpOptions.bUseRsid && !pTxtNd1->CompareRsid( *pTxtNd2, + pPos1[ nIdx1 ] + i, pPos2[ nIdx2 ] + i ) ) ) + { + return false; + } + } + return true; +} + +int WordArrayComparator::GetCharSequence( const int *pWordLcs1, + const int *pWordLcs2, int *pSubseq1, int *pSubseq2, int nLcsLen ) +{ + int nLen = 0; + for( int i = 0; i < nLcsLen; i++ ) + { + // Check for hash collisions + if( pPos1[ pWordLcs1[i] + 1 ] - pPos1[ pWordLcs1[i] ] + != pPos2[ pWordLcs2[i] + 1 ] - pPos2[ pWordLcs2[i] ] ) + { + continue; + } + for( int j = 0; j < pPos1[pWordLcs1[i]+1] - pPos1[pWordLcs1[i]]; j++) + { + pSubseq1[ nLen ] = pPos1[ pWordLcs1[i] ] + j; + pSubseq2[ nLen ] = pPos2[ pWordLcs2[i] ] + j; + + if( pTxtNd1->GetTxt().GetChar( pPos1[ pWordLcs1[i] ] + j ) + != pTxtNd2->GetTxt().GetChar( pPos2[ pWordLcs2[i] ] + j ) ) + { + nLen -= j; + break; + } + + nLen++; + } + } + return nLen; +} + +void WordArrayComparator::CalcPositions( int *pPos, const SwTxtNode *pTxtNd, + int &nCnt ) +{ + nCnt = -1; + for( int i = 0; i <= pTxtNd->GetTxt().Len(); i++ ) + { + if( i == 0 || i == pTxtNd->GetTxt().Len() + || !isalnum( pTxtNd->GetTxt().GetChar( i - 1 ) ) + || !isalnum( pTxtNd->GetTxt().GetChar( i ) ) ) + { // Begin new word + nCnt++; + pPos[ nCnt ] = i; + } + } +} + + +int CommonSubseq::FindLCS( int *pLcs1, int *pLcs2, int nStt1, int nEnd1, + int nStt2, int nEnd2 ) +{ + int nLen1 = nEnd1 ? nEnd1 - nStt1 : rCmp.GetLen1(); + int nLen2 = nEnd2 ? nEnd2 - nStt2 : rCmp.GetLen2(); + + OSL_ASSERT( nLen1 >= 0 ); + OSL_ASSERT( nLen2 >= 0 ); + + int **pLcs = new int*[ nLen1 + 1 ]; + pLcs[ 0 ] = pData; + + for( int i = 1; i < nLen1 + 1; i++ ) + pLcs[ i ] = pLcs[ i - 1 ] + nLen2 + 1; + + for( int i = 0; i <= nLen1; i++ ) + pLcs[i][0] = 0; + + for( int j = 0; j <= nLen2; j++ ) + pLcs[0][j] = 0; + + // Find lcs + for( int i = 1; i <= nLen1; i++ ) + { + for( int j = 1; j <= nLen2; j++ ) + { + if( rCmp.Compare( nStt1 + i - 1, nStt2 + j - 1 ) ) + pLcs[i][j] = pLcs[i - 1][j - 1] + 1; + else + pLcs[i][j] = std::max( pLcs[i][j - 1], pLcs[i - 1][j] ); + } + } + + int nLcsLen = pLcs[ nLen1 ][ nLen2 ]; + + // Recover the lcs in the two sequences + if( pLcs1 && pLcs2 ) + { + int nIdx1 = nLen1; + int nIdx2 = nLen2; + int nIdx = nLcsLen - 1; + + while( nIdx1 > 0 && nIdx2 > 0 ) + { + if( pLcs[ nIdx1 ][ nIdx2 ] == pLcs[ nIdx1 - 1 ][ nIdx2 ] ) + nIdx1--; + else if( pLcs[ nIdx1 ][ nIdx2 ] == pLcs[ nIdx1 ][ nIdx2 - 1 ] ) + nIdx2--; + else + { + nIdx1--, nIdx2--; + pLcs1[ nIdx ] = nIdx1 + nStt1; + pLcs2[ nIdx ] = nIdx2 + nStt2; + nIdx--; + } + } + } + + delete[] pLcs; + + return nLcsLen; +} + +int CommonSubseq::IgnoreIsolatedPieces( int *pLcs1, int *pLcs2, int nLen1, + int nLen2, int nLcsLen, int nPieceLen ) +{ + if( !nLcsLen ) + { + return 0; + } + + int nNext = 0; + + // Don't ignore text at the beginning of the paragraphs + if( pLcs1[ 0 ] == 0 && pLcs2[ 0 ] == 0 ) + { + while( nNext < nLcsLen - 1 && pLcs1[ nNext ] + 1 == pLcs1[ nNext + 1 ] + && pLcs2[ nNext ] + 1 == pLcs2[ nNext + 1 ] ) + { + nNext++; + } + nNext++; + } + + int nCnt = 1; + + for( int i = nNext; i < nLcsLen; i++ ) + { + if( i != nLcsLen - 1 && pLcs1[ i ] + 1 == pLcs1[ i + 1 ] + && pLcs2[ i ] + 1 == pLcs2[ i + 1 ] ) + { + nCnt++; + } + else + { + if( nCnt > nPieceLen + // Don't ignore text at the end of the paragraphs + || ( i == nLcsLen - 1 + && pLcs1[i] == nLen1 - 1 && pLcs2[i] == nLen2 - 1 )) + { + for( int j = i + 1 - nCnt; j <= i; j++ ) + { + pLcs2[ nNext ] = pLcs2[ j ]; + pLcs1[ nNext ] = pLcs1[ j ]; + nNext++; + } + } + nCnt = 1; + } + } + + return nNext; +} + +LgstCommonSubseq::LgstCommonSubseq( ArrayComparator &rComparator ) + : CommonSubseq( rComparator, CUTOFF ) +{ + pBuff1 = new int[ rComparator.GetLen2() + 1 ]; + pBuff2 = new int[ rComparator.GetLen2() + 1 ]; + + pL1 = new int[ rComparator.GetLen2() + 1 ]; + pL2 = new int[ rComparator.GetLen2() + 1 ]; +} + +LgstCommonSubseq::~LgstCommonSubseq() +{ + delete[] pBuff1; + delete[] pBuff2; + + delete[] pL1; + delete[] pL2; +} + +void LgstCommonSubseq::FindL( int *pL, int nStt1, int nEnd1, + int nStt2, int nEnd2 ) +{ + int nLen1 = nEnd1 ? nEnd1 - nStt1 : rCmp.GetLen1(); + int nLen2 = nEnd2 ? nEnd2 - nStt2 : rCmp.GetLen2(); + + int *currL = pBuff1; + int *prevL = pBuff2; + + // Avoid memory corruption + if( nLen2 > rCmp.GetLen2() ) + { + assert( false ); + return; + } + + memset( pBuff1, 0, sizeof( *pBuff1 ) * ( nLen2 + 1 ) ); + memset( pBuff2, 0, sizeof( *pBuff2 ) * ( nLen2 + 1 ) ); + + // Find lcs + for( int i = 1; i <= nLen1; i++ ) + { + for( int j = 1; j <= nLen2; j++ ) + { + if( rCmp.Compare( nStt1 + i - 1, nStt2 + j - 1 ) ) + currL[j] = prevL[j - 1] + 1; + else + currL[j] = std::max( currL[j - 1], prevL[j] ); + } + int *tmp = currL; + currL = prevL; + prevL = tmp; + } + memcpy( pL, prevL, ( nLen2 + 1 ) * sizeof( *prevL ) ); +} + +int LgstCommonSubseq::HirschbergLCS( int *pLcs1, int *pLcs2, int nStt1, + int nEnd1, int nStt2, int nEnd2 ) +{ + static int nLen1; + static int nLen2; + nLen1 = nEnd1 - nStt1; + nLen2 = nEnd2 - nStt2; + + if( ( nLen1 + 1 ) * ( nLen2 + 1 ) <= CUTOFF ) + { + if( !nLen1 || !nLen2 ) + { + return 0; + } + return FindLCS(pLcs1, pLcs2, nStt1, nEnd1, nStt2, nEnd2); + } + + int nMid = nLen1/2; + + FindL( pL1, nStt1, nStt1 + nMid, nStt2, nEnd2 ); + FindL( pL2, nStt1 + nMid, nEnd1, nStt2, nEnd2 ); + + int nMaxPos = 0; + static int nMaxVal; + nMaxVal = -1; + + static int i; + for( i = 0; i <= nLen2; i++ ) + { + if( pL1[i] + ( pL2[nLen2] - pL2[i] ) > nMaxVal ) + { + nMaxPos = i; + nMaxVal = pL1[i]+( pL2[nLen2] - pL2[i] ); + } + } + + int nRet = HirschbergLCS( pLcs1, pLcs2, nStt1, nStt1 + nMid, + nStt2, nStt2 + nMaxPos ); + nRet += HirschbergLCS( pLcs1 + nRet, pLcs2 + nRet, nStt1 + nMid, nEnd1, + nStt2 + nMaxPos, nEnd2 ); + + return nRet; +} + +int LgstCommonSubseq::Find( int *pSubseq1, int *pSubseq2 ) +{ + int nStt = 0; + int nCutEnd = 0; + int nEnd1 = rCmp.GetLen1(); + int nEnd2 = rCmp.GetLen2(); + + // Check for corresponding lines in the beginning of the sequences + while( nStt < nEnd1 && nStt < nEnd2 && rCmp.Compare( nStt, nStt ) ) + { + pSubseq1[ nStt ] = nStt; + pSubseq2[ nStt ] = nStt; + nStt++; + } + + pSubseq1 += nStt; + pSubseq2 += nStt; + + // Check for corresponding lines in the end of the sequences + while( nStt < nEnd1 && nStt < nEnd2 + && rCmp.Compare( nEnd1 - 1, nEnd2 - 1 ) ) + { + nCutEnd++; + nEnd1--; + nEnd2--; + } + + int nLen = HirschbergLCS( pSubseq1, pSubseq2, nStt, nEnd1, nStt, nEnd2 ); + + for( int i = 0; i < nCutEnd; i++ ) + { + pSubseq1[ nLen + i ] = nEnd1 + i; + pSubseq2[ nLen + i ] = nEnd2 + i; + } + + return nStt + nLen + nCutEnd; +} + +int FastCommonSubseq::FindFastCS( int *pSeq1, int *pSeq2, int nStt1, + int nEnd1, int nStt2, int nEnd2 ) +{ + int nCutBeg = 0; + int nCutEnd = 0; + + // Check for corresponding lines in the beginning of the sequences + while( nStt1 < nEnd1 && nStt2 < nEnd2 && rCmp.Compare( nStt1, nStt2 ) ) + { + pSeq1[ nCutBeg ] = nStt1++; + pSeq2[ nCutBeg ] = nStt2++; + nCutBeg++; + } + + pSeq1 += nCutBeg; + pSeq2 += nCutBeg; + + // Check for corresponding lines in the end of the sequences + while( nStt1 < nEnd1 && nStt2 < nEnd2 + && rCmp.Compare( nEnd1 - 1, nEnd2 - 1 ) ) + { + nCutEnd++; + nEnd1--; + nEnd2--; + } + + int nLen1 = nEnd1 - nStt1; + int nLen2 = nEnd2 - nStt2; + + // Return if a sequence is empty + if( nLen1 <= 0 || nLen2 <= 0 ) + { + for( int i = 0; i < nCutEnd; i++ ) + { + pSeq1[ i ] = nEnd1 + i; + pSeq2[ i ] = nEnd2 + i; + } + return nCutBeg + nCutEnd; + } + + // Cut to LCS for small values + if( nLen1 < 3 || nLen2 < 3 || ( nLen1 + 1 ) * ( nLen2 + 1 ) <= CUTOFF ) + { + int nLcsLen = FindLCS( pSeq1, pSeq2, nStt1, nEnd1, nStt2, nEnd2); + + for( int i = 0; i < nCutEnd; i++ ) + { + pSeq1[ nLcsLen + i ] = nEnd1 + i; + pSeq2[ nLcsLen + i ] = nEnd2 + i; + } + return nCutBeg + nLcsLen + nCutEnd; + } + + int nMid1 = nLen1/2; + int nMid2 = nLen2/2; + + int nRad; + int nPos1 = -1, nPos2 = -1; + + // Find a point of correspondence in the middle of the sequences + for( nRad = 0; nRad*nRad < std::min( nMid1, nMid2 ); nRad++ ) + { + // Search to the left and to the right of the middle of the first sequence + for( int i = nMid1 - nRad; i <= nMid1 + nRad; i++ ) + { + if( rCmp.Compare( nStt1 + i, nStt2 + nMid2 - nRad ) ) + { + nPos1 = nStt1 + i; + nPos2 = nStt2 + nMid2 - nRad; + break; + } + if( rCmp.Compare( nStt1 + i, nStt2 + nMid2 + nRad ) ) + { + nPos1 = nStt1 + i; + nPos2 = nStt2 + nMid2 - nRad; + break; + } + } + // Search to the left and to the right of the middle of the second sequence + for( int i = nMid2 - nRad; i <= nMid2 + nRad; i++ ) + { + if( rCmp.Compare( nStt2 + nMid2 - nRad, nStt2 + i ) ) + { + nPos2 = nStt2 + i; + nPos1 = nStt1 + nMid1 - nRad; + break; + } + if( rCmp.Compare( nStt2 + nMid2 - nRad, nStt2 + i ) ) + { + nPos2 = nStt2 + i; + nPos1 = nStt1 + nMid1 - nRad; + break; + } + } + } + + // return if no point of correspondence found + if( nPos1 == -1 ) + { + for( int i = 0; i < nCutEnd; i++ ) + { + pSeq1[ i ] = nEnd1 + i; + pSeq2[ i ] = nEnd2 + i; + } + return nCutBeg + nCutEnd; + } + + // Run the same on the sequences to the left of the correspondence point + int nLen = FindFastCS( pSeq1, pSeq2, nStt1, nPos1, nStt2, nPos2 ); + + pSeq1[ nLen ] = nPos1; + pSeq2[ nLen ] = nPos2; + + // Run the same on the sequences to the right of the correspondence point + nLen += FindFastCS( pSeq1 + nLen + 1, pSeq2 + nLen + 1, + nPos1 + 1, nEnd1, nPos2 + 1, nEnd2 ) + 1; + + for( int i = 0; i < nCutEnd; i++ ) + { + pSeq1[ nLen + i ] = nEnd1 + i; + pSeq2[ nLen + i ] = nEnd2 + i; + } + + return nLen + nCutBeg + nCutEnd; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx index cba769405977..294a4d49ae74 100644 --- a/sw/source/core/doc/docnew.cxx +++ b/sw/source/core/doc/docnew.cxx @@ -39,6 +39,7 @@ #include <vcl/svapp.hxx> #include <vcl/virdev.hxx> #include <rtl/logfile.hxx> +#include <rtl/random.h> #include <sfx2/printer.hxx> #include <sfx2/docfile.hxx> #include <sfx2/frame.hxx> @@ -431,6 +432,14 @@ SwDoc::SwDoc() pStyleAccess = createStyleManager( &aIgnorableParagraphItems ); } + // Initialize the session id of the current document to a random number + // smaller than 2^21. + static rtlRandomPool aPool = rtl_random_createPool(); + rtl_random_getBytes( aPool, &nRsid, sizeof ( nRsid ) ); + nRsid &= ( 1<<21 ) - 1; + nRsid++; + nRsidRoot = nRsid; + ResetModified(); } diff --git a/sw/source/core/edit/editsh.cxx b/sw/source/core/edit/editsh.cxx index f6e3da27c6dd..de33e7e86d13 100644 --- a/sw/source/core/edit/editsh.cxx +++ b/sw/source/core/edit/editsh.cxx @@ -122,6 +122,13 @@ void SwEditShell::Insert2(const String &rStr, const bool bForceExpandHints ) OSL_ENSURE( bSuccess, "Doc->Insert() failed." ); (void) bSuccess; + GetDoc()->UpdateRsid( *_pStartCrsr, rStr.Len() ); + + // Set paragraph rsid if beginning of paragraph + SwTxtNode *pTxtNode = _pStartCrsr->GetPoint()->nNode.GetNode().GetTxtNode(); + if( pTxtNode && pTxtNode->Len() == 1) + GetDoc()->UpdateParRsid( pTxtNode ); + SaveTblBoxCntnt( _pStartCrsr->GetPoint() ); } while( (_pStartCrsr=(SwPaM *)_pStartCrsr->GetNext()) != __pStartCrsr ); diff --git a/sw/source/core/frmedt/fecopy.cxx b/sw/source/core/frmedt/fecopy.cxx index e3056be2415e..0a2ed741e53f 100644 --- a/sw/source/core/frmedt/fecopy.cxx +++ b/sw/source/core/frmedt/fecopy.cxx @@ -1043,6 +1043,7 @@ sal_Bool SwFEShell::Paste( SwDoc* pClpDoc, sal_Bool bIncludingPageFrames ) // muessen die BoxAttribute aber entfernt werden. GetDoc()->ClearBoxNumAttrs( rInsPos.nNode ); } + //find out if the clipboard document starts with a table bool bStartWithTable = 0 != aCpyPam.Start()->nNode.GetNode().FindTableNode(); SwPosition aInsertPosition( rInsPos ); @@ -1063,6 +1064,22 @@ sal_Bool SwFEShell::Paste( SwDoc* pClpDoc, sal_Bool bIncludingPageFrames ) } } + // Update the rsid of each pasted text node. + { + xub_StrLen nNodesCnt = aCpyPam.End()->nNode.GetIndex() - aCpyPam.Start()->nNode.GetIndex(); + SwNodes &rDestNodes = GetDoc()->GetNodes(); + xub_StrLen nDestStart = PCURCRSR->GetPoint()->nNode.GetIndex() - nNodesCnt; + + for ( sal_uInt64 nIdx = 0; nIdx <= nNodesCnt; nIdx++ ) + { + SwTxtNode *pTxtNode = rDestNodes[ nDestStart + nIdx ]->GetTxtNode(); + if ( pTxtNode ) + { + GetDoc()->UpdateParRsid( pTxtNode ); + } + } + } + SaveTblBoxCntnt( &rInsPos ); if(bIncludingPageFrames && bStartWithTable) { diff --git a/sw/source/core/inc/UndoSplitMove.hxx b/sw/source/core/inc/UndoSplitMove.hxx index c1a690bdbc72..f85c65cfd9ac 100644 --- a/sw/source/core/inc/UndoSplitMove.hxx +++ b/sw/source/core/inc/UndoSplitMove.hxx @@ -40,6 +40,7 @@ class SwUndoSplitNode: public SwUndo xub_StrLen nCntnt; sal_Bool bTblFlag : 1; sal_Bool bChkTblStt : 1; + sal_uInt32 nParRsid; public: SwUndoSplitNode( SwDoc* pDoc, const SwPosition& rPos, sal_Bool bChkTbl ); diff --git a/sw/source/core/text/atrstck.cxx b/sw/source/core/text/atrstck.cxx index 4f0824cb7f53..b120ca8a3162 100644 --- a/sw/source/core/text/atrstck.cxx +++ b/sw/source/core/text/atrstck.cxx @@ -121,8 +121,8 @@ const sal_uInt8 StackPos[ static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) - 33, // RES_CHRATR_RELIEF, // 36 34, // RES_CHRATR_HIDDEN, // 37 35, // RES_CHRATR_OVERLINE, // 38 - 0, // RES_CHRATR_DUMMY1, // 39 - 0, // RES_CHRATR_DUMMY2, // 40 + 0, // RES_CHRATR_RSID, // 39 + 0, // RES_DUMMY1, // 40 36, // RES_TXTATR_REFMARK, // 41 37, // RES_TXTATR_TOXMARK, // 42 38, // RES_TXTATR_META, // 43 diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx index 46f9c2409fc9..19a968d77321 100644 --- a/sw/source/core/txtnode/ndtxt.cxx +++ b/sw/source/core/txtnode/ndtxt.cxx @@ -33,6 +33,7 @@ #include <editeng/brkitem.hxx> #include <editeng/escpitem.hxx> #include <editeng/lrspitem.hxx> +#include <editeng/rsiditem.hxx> #include <editeng/tstpitem.hxx> #include <svl/urihelper.hxx> #ifndef _SVSTDARR_HXX @@ -4742,6 +4743,45 @@ sal_uInt16 SwTxtNode::ResetAllAttr() return nRet; } + +sal_uInt32 SwTxtNode::GetRsid( xub_StrLen nStt, xub_StrLen nEnd ) const +{ + SfxItemSet aSet( (SfxItemPool&) (GetDoc()->GetAttrPool()), RES_CHRATR_RSID, RES_CHRATR_RSID ); + if ( GetAttr(aSet, nStt, nEnd) ) + { + SvxRsidItem* pRsid = (SvxRsidItem*)aSet.GetItem(RES_CHRATR_RSID); + if( pRsid ) + return pRsid->GetValue(); + } + + return 0; +} + +sal_uInt32 SwTxtNode::GetParRsid() const +{ + SvxRsidItem &rItem = ( SvxRsidItem& ) GetAttr( RES_PARATR_RSID ); + + return rItem.GetValue(); +} + +bool SwTxtNode::CompareParRsid( const SwTxtNode &rTxtNode ) const +{ + sal_uInt32 nThisRsid = GetParRsid(); + sal_uInt32 nRsid = rTxtNode.GetParRsid(); + + return nThisRsid == nRsid; +} + +bool SwTxtNode::CompareRsid( const SwTxtNode &rTxtNode, xub_StrLen nStt1, xub_StrLen nStt2, + xub_StrLen nEnd1, xub_StrLen nEnd2 ) const + +{ + sal_uInt32 nThisRsid = GetRsid( nStt1, nEnd1 ? nEnd1 : nStt1 ); + sal_uInt32 nRsid = rTxtNode.GetRsid( nStt2, nEnd2 ? nEnd2 : nStt2 ); + + return nThisRsid == nRsid; +} + // sw::Metadatable ::sfx2::IXmlIdRegistry& SwTxtNode::GetRegistry() { diff --git a/sw/source/core/undo/unspnd.cxx b/sw/source/core/undo/unspnd.cxx index 0fef0790c99a..787aed4ea48a 100644 --- a/sw/source/core/undo/unspnd.cxx +++ b/sw/source/core/undo/unspnd.cxx @@ -71,6 +71,8 @@ SwUndoSplitNode::SwUndoSplitNode( SwDoc* pDoc, const SwPosition& rPos, pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_INSERT, pDoc->GetRedlineAuthor() ); SetRedlineMode( pDoc->GetRedlineMode() ); } + + nParRsid = pTxtNd->GetParRsid(); } SwUndoSplitNode::~SwUndoSplitNode() @@ -147,6 +149,8 @@ void SwUndoSplitNode::UndoImpl(::sw::UndoRedoContext & rContext) pDoc->RstTxtAttrs( rPam, sal_True ); pHistory->TmpRollback( pDoc, 0, false ); } + + pDoc->UpdateParRsid( pTNd, nParRsid ); } } diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx index 1554fdc54016..4e6a17c0a80e 100644 --- a/sw/source/core/unocore/unomap.cxx +++ b/sw/source/core/unocore/unomap.cxx @@ -84,6 +84,7 @@ SwUnoPropertyMapProvider::~SwUnoPropertyMapProvider() { SW_PROP_NMID(UNO_NAME_CHAR_FONT_CHAR_SET), RES_CHRATR_FONT, CPPU_E2T(CPPUTYPE_INT16), PropertyAttribute::MAYBEVOID, MID_FONT_CHAR_SET }, \ { SW_PROP_NMID(UNO_NAME_CHAR_FONT_PITCH), RES_CHRATR_FONT, CPPU_E2T(CPPUTYPE_INT16), PropertyAttribute::MAYBEVOID, MID_FONT_PITCH }, \ { SW_PROP_NMID(UNO_NAME_CHAR_POSTURE), RES_CHRATR_POSTURE , CPPU_E2T(CPPUTYPE_FONTSLANT), PropertyAttribute::MAYBEVOID, MID_POSTURE}, \ + { SW_PROP_NMID(UNO_NAME_RSID), RES_CHRATR_RSID, CPPU_E2T(CPPUTYPE_INT32), PropertyAttribute::MAYBEVOID, 0 }, \ { SW_PROP_NMID(UNO_NAME_CHAR_LOCALE), RES_CHRATR_LANGUAGE , CPPU_E2T(CPPUTYPE_LOCALE) , PropertyAttribute::MAYBEVOID, MID_LANG_LOCALE }, #define _CJK_FONT_PROPERTIES \ @@ -154,6 +155,7 @@ SwUnoPropertyMapProvider::~SwUnoPropertyMapProvider() // UNO_NAME_BREAK_TYPE and UNO_NAME_PAGE_DESC_NAME which can not be used // by the SwXTextTableCursor #define COMMON_CRSR_PARA_PROPERTIES_WITHOUT_FN_01 \ + { SW_PROP_NMID(UNO_NAME_PARRSID), RES_PARATR_RSID, CPPU_E2T(CPPUTYPE_INT32), PropertyAttribute::MAYBEVOID, 0 }, \ { SW_PROP_NMID(UNO_NAME_PARA_IS_HYPHENATION), RES_PARATR_HYPHENZONE, CPPU_E2T(CPPUTYPE_BOOLEAN), PropertyAttribute::MAYBEVOID, MID_IS_HYPHEN }, \ { SW_PROP_NMID(UNO_NAME_PARA_HYPHENATION_MAX_LEADING_CHARS), RES_PARATR_HYPHENZONE, CPPU_E2T(CPPUTYPE_INT16), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MIN_LEAD }, \ { SW_PROP_NMID(UNO_NAME_PARA_HYPHENATION_MAX_TRAILING_CHARS), RES_PARATR_HYPHENZONE, CPPU_E2T(CPPUTYPE_INT16), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MIN_TRAIL }, \ diff --git a/sw/source/core/unocore/unoprnms.cxx b/sw/source/core/unocore/unoprnms.cxx index 28e9d48c31fd..0c0479c8c797 100644 --- a/sw/source/core/unocore/unoprnms.cxx +++ b/sw/source/core/unocore/unoprnms.cxx @@ -781,6 +781,8 @@ const SwPropNameTab aPropNameTab = { /* 0742 UNO_NAME_SEPARATOR_LINE_STYLE */ {MAP_CHAR_LEN("SeparatorLineStyle")}, /* 0743 UNO_NAME_FOOTNOTE_LINE_STYLE */ {MAP_CHAR_LEN("FootnoteLineStyle")}, /* 0744 UNO_NAME_EMBEDDED_OBJECT */ {MAP_CHAR_LEN("EmbeddedObject")}, +/* 0745 UNO_NAME_RSID */ {MAP_CHAR_LEN("Rsid")}, +/* 0746 UNO_NAME_PARRSID */ {MAP_CHAR_LEN("ParRsid")}, // new items in this array must match enum SwPropNameIds }; diff --git a/sw/source/filter/ascii/parasc.cxx b/sw/source/filter/ascii/parasc.cxx index d7f210a91dec..807f78b40477 100644 --- a/sw/source/filter/ascii/parasc.cxx +++ b/sw/source/filter/ascii/parasc.cxx @@ -503,6 +503,9 @@ sal_uLong SwASCIIParser::ReadChars() void SwASCIIParser::InsertText( const String& rStr ) { pDoc->InsertString( *pPam, rStr ); + pDoc->UpdateRsid( *pPam, rStr.Len() ); + pDoc->UpdateParRsid( pPam->GetPoint()->nNode.GetNode().GetTxtNode() ); + if( pItemSet && pBreakIt && nScript != ( SCRIPTTYPE_LATIN | SCRIPTTYPE_ASIAN | SCRIPTTYPE_COMPLEX ) ) diff --git a/sw/source/filter/html/css1atr.cxx b/sw/source/filter/html/css1atr.cxx index 97414c2e53ad..dcd24dafd02d 100644 --- a/sw/source/filter/html/css1atr.cxx +++ b/sw/source/filter/html/css1atr.cxx @@ -3747,8 +3747,8 @@ SwAttrFnTab aCSS1AttrFnTab = { /* RES_CHRATR_RELIEF */ 0, /* RES_CHRATR_HIDDEN */ 0, /* RES_CHRATR_OVERLINE */ OutCSS1_SvxOverline, +/* RES_CHRATR_RSID */ 0, /* RES_CHRATR_DUMMY1 */ 0, -/* RES_CHRATR_DUMMY2 */ 0, /* RES_TXTATR_REFMARK */ 0, /* RES_TXTATR_TOXMARK */ 0, @@ -3786,6 +3786,7 @@ SwAttrFnTab aCSS1AttrFnTab = { /* RES_PARATR_SNAPTOGRID*/ 0, // new /* RES_PARATR_CONNECT_TO_BORDER */ 0, // new /* RES_PARATR_OUTLINELEVEL */ 0, // new since cws outlinelevel +/* RES_PARATR_RSID */ 0, // new /* RES_PARATR_LIST_ID */ 0, // new /* RES_PARATR_LIST_LEVEL */ 0, // new diff --git a/sw/source/filter/html/htmlatr.cxx b/sw/source/filter/html/htmlatr.cxx index 7803c04c829f..08d8e9c586cb 100644 --- a/sw/source/filter/html/htmlatr.cxx +++ b/sw/source/filter/html/htmlatr.cxx @@ -3365,8 +3365,8 @@ SwAttrFnTab aHTMLAttrFnTab = { /* RES_CHRATR_RELIEF */ 0, /* RES_CHRATR_HIDDEN */ 0, /* RES_CHRATR_OVERLINE */ OutHTML_CSS1Attr, +/* RES_CHRATR_RSID */ 0, /* RES_CHRATR_DUMMY1 */ 0, -/* RES_CHRATR_DUMMY2 */ 0, /* RES_TXTATR_REFMARK */ 0, /* RES_TXTATR_TOXMARK */ 0, diff --git a/sw/source/filter/xml/xmlexp.cxx b/sw/source/filter/xml/xmlexp.cxx index ed058af26056..7d6d0e954126 100644 --- a/sw/source/filter/xml/xmlexp.cxx +++ b/sw/source/filter/xml/xmlexp.cxx @@ -156,6 +156,14 @@ sal_uInt32 SwXMLExport::exportDoc( enum XMLTokenEnum eClass ) if( (getExportFlags() & (EXPORT_FONTDECLS|EXPORT_STYLES| EXPORT_MASTERSTYLES|EXPORT_CONTENT)) != 0 ) { + if( getDefaultVersion() == SvtSaveOptions::ODFVER_LATEST ) + { + _GetNamespaceMap().Add( + GetXMLToken(XML_NP_OFFICE_EXT), + GetXMLToken(XML_N_OFFICE_EXT), + XML_NAMESPACE_OFFICE_EXT); + } + GetTextParagraphExport()->SetBlockMode( bBlock ); const SfxPoolItem* pItem; diff --git a/sw/source/ui/app/appopt.cxx b/sw/source/ui/app/appopt.cxx index d9afcb37c408..db0f26d9dbf4 100644 --- a/sw/source/ui/app/appopt.cxx +++ b/sw/source/ui/app/appopt.cxx @@ -504,6 +504,7 @@ SfxTabPage* SwModule::CreateTabPage( sal_uInt16 nId, Window* pParent, const SfxI case RID_SW_TP_OPTSHDWCRSR: case RID_SW_TP_HTML_OPTSHDWCRSR: case RID_SW_TP_REDLINE_OPT: + case RID_SW_TP_COMPARISON_OPT: case RID_SW_TP_OPTLOAD_PAGE: case RID_SW_TP_OPTCOMPATIBILITY_PAGE: case RID_SW_TP_MAILCONFIG: diff --git a/sw/source/ui/app/docsh.cxx b/sw/source/ui/app/docsh.cxx index 6f5a9028e4e2..bf2487dd6d5b 100644 --- a/sw/source/ui/app/docsh.cxx +++ b/sw/source/ui/app/docsh.cxx @@ -507,6 +507,9 @@ sal_Bool SwDocShell::SaveAs( SfxMedium& rMedium ) pDoc->SetOle2Link( aOldOLELnk ); SW_MOD()->SetEmbeddedLoadSave( sal_False ); + + // Increase RSID + pDoc->setRsid( pDoc->getRsid() ); } SetError( nErr ? nErr : nVBWarning, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); diff --git a/sw/source/ui/app/swmodul1.cxx b/sw/source/ui/app/swmodul1.cxx index ff2d3a8e4d64..ccd38e170456 100644 --- a/sw/source/ui/app/swmodul1.cxx +++ b/sw/source/ui/app/swmodul1.cxx @@ -655,4 +655,44 @@ void SwModule::ApplyDefaultPageMode(sal_Bool bIsSquaredPageMode) pUsrPref->SetDefaultPageMode(bIsSquaredPageMode); } +SvxCompareMode SwModule::GetCompareMode() const +{ + return pModuleConfig->GetCompareMode(); +} + +void SwModule::SetCompareMode( SvxCompareMode eMode ) +{ + pModuleConfig->SetCompareMode( eMode ); +} + +sal_Bool SwModule::IsUseRsid() const +{ + return pModuleConfig->IsUseRsid(); +} + +void SwModule::SetUseRsid( sal_Bool b ) +{ + pModuleConfig->SetUseRsid( b ); +} + +sal_Bool SwModule::IsIgnorePieces() const +{ + return pModuleConfig->IsIgnorePieces(); +} + +void SwModule::SetIgnorePieces( sal_Bool b ) +{ + pModuleConfig->SetIgnorePieces( b ); +} + +sal_uInt16 SwModule::GetPieceLen() const +{ + return pModuleConfig->GetPieceLen(); +} + +void SwModule::SetPieceLen( sal_uInt16 nLen ) +{ + pModuleConfig->SetPieceLen( nLen ); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/config/modcfg.cxx b/sw/source/ui/config/modcfg.cxx index bb23c61401fe..af6d32842c3e 100644 --- a/sw/source/ui/config/modcfg.cxx +++ b/sw/source/ui/config/modcfg.cxx @@ -1332,4 +1332,84 @@ void SwMiscConfig::Load() } } +const Sequence<OUString>& SwCompareConfig::GetPropertyNames() +{ + static Sequence<OUString> aNames; + if(!aNames.getLength()) + { + const int nCount = 4; + aNames.realloc(nCount); + static const char* aPropNames[] = + { + "Mode", // 0 + "UseRSID", // 1 + "IgnorePieces", // 2 + "IgnoreLength" // 3 + }; + OUString* pNames = aNames.getArray(); + for(int i = 0; i < nCount; i++) + pNames[i] = OUString::createFromAscii(aPropNames[i]); + } + return aNames; +} + +SwCompareConfig::SwCompareConfig() : + ConfigItem(C2U("Office.Writer/Comparison"), + CONFIG_MODE_DELAYED_UPDATE|CONFIG_MODE_RELEASE_TREE) +{ + eCmpMode = SVX_CMP_AUTO; + bUseRsid = 0; + bIgnorePieces = 0; + nPieceLen = 1; + + Load(); +} + +SwCompareConfig::~SwCompareConfig() +{ +} + +void SwCompareConfig::Commit() +{ + const Sequence<OUString>& aNames = GetPropertyNames(); + Sequence<Any> aValues(aNames.getLength()); + Any* pValues = aValues.getArray(); + + const Type& rType = ::getBooleanCppuType(); + + pValues[0] <<= (sal_Int32) eCmpMode; + pValues[1].setValue(&bUseRsid, rType); + pValues[2].setValue(&bIgnorePieces, rType); + pValues[3] <<= (sal_Int32) nPieceLen; + + PutProperties(aNames, aValues); +} + +void SwCompareConfig::Load() +{ + const Sequence<OUString>& aNames = GetPropertyNames(); + Sequence<Any> aValues = GetProperties(aNames); + const Any* pValues = aValues.getConstArray(); + DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed"); + if(aValues.getLength() == aNames.getLength()) + { + for(int nProp = 0; nProp < aNames.getLength(); nProp++) + { + if(pValues[nProp].hasValue()) + { + sal_Int32 nVal = 0; + pValues[nProp] >>= nVal; + + switch(nProp) + { + case 0 : eCmpMode = (SvxCompareMode) nVal; break;; + case 1 : bUseRsid = *(sal_Bool*)pValues[nProp].getValue(); break; + case 2 : bIgnorePieces = *(sal_Bool*)pValues[nProp].getValue(); break; + case 3 : nPieceLen = nVal; break; + } + } + } + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/config/optdlg.hrc b/sw/source/ui/config/optdlg.hrc index 8c19a5f8b72c..9906d5c3f5b8 100644 --- a/sw/source/ui/config/optdlg.hrc +++ b/sw/source/ui/config/optdlg.hrc @@ -180,3 +180,11 @@ #define CB_MATH_BASELINE_ALIGNMENT 16 +#define FL_CMP 141 +#define RB_AUTO 142 +#define RB_WORD 143 +#define RB_CHAR 144 +#define FL_SET 145 +#define CB_RSID 146 +#define CB_IGNORE 147 +#define NF_LEN 148 diff --git a/sw/source/ui/config/optdlg.src b/sw/source/ui/config/optdlg.src index c47594865747..1fd1ae215450 100644..100755 --- a/sw/source/ui/config/optdlg.src +++ b/sw/source/ui/config/optdlg.src @@ -882,3 +882,77 @@ StringArray STR_PRINTOPTUI }; }; + +/**************************************************************************/ +/* */ +/* TabPage Comparison */ +/* */ +/**************************************************************************/ +TabPage TP_COMPARISON_OPT +{ + HelpID = HID_COMPARISON_OPT; + SVLook = TRUE ; + Hide = TRUE; + Size = MAP_APPFONT ( 260 , 185 ); + FixedLine FL_CMP + { + Pos = MAP_APPFONT ( 6 , 3 ) ; + Size = MAP_APPFONT ( 248 , 8 ) ; + Text [ en-US ] = "Compare documents"; + }; + RadioButton RB_AUTO + { + Pos = MAP_APPFONT ( 12 , 14 ) ; + Size = MAP_APPFONT ( 70 , 10 ) ; + Text [ en-US ] = "~Auto"; + TabStop = TRUE ; + Group = TRUE ; + }; + RadioButton RB_WORD + { + Pos = MAP_APPFONT ( 12 , 27 ) ; + Size = MAP_APPFONT ( 70 , 10 ) ; + Text [ en-US ] = "By ~word"; + }; + RadioButton RB_CHAR + { + Pos = MAP_APPFONT ( 12 , 40 ) ; + Size = MAP_APPFONT ( 70 , 10 ) ; + Text [ en-US ] = "By ~character"; + }; + FixedLine FL_SET + { + Pos = MAP_APPFONT ( 6 , 56 ) ; + Size = MAP_APPFONT ( 248 , 8 ) ; + Text [ en-US ] = "Settings"; + }; + CheckBox CB_RSID + { + Pos = MAP_APPFONT ( 12 , 69 ) ; + Size = MAP_APPFONT ( 70 , 10 ) ; + Text [ en-US ] = "Use ~RSID"; + TabStop = TRUE ; + Group = TRUE ; + }; + CheckBox CB_IGNORE + { + Pos = MAP_APPFONT ( 12 , 82 ) ; + Size = MAP_APPFONT ( 70 , 10 ) ; + Text [ en-US ] = "Ignore ~pieces of length"; + }; + NumericField NF_LEN + { + Pos = MAP_APPFONT ( 100 , 80 ) ; + Size = MAP_APPFONT ( 25 , 12 ) ; + Border = TRUE ; + Left = TRUE ; + First = 1 ; + Minimum = 1 ; + Maximum = 99; + Repeat = TRUE ; + Spin = TRUE ; + SpinSize = 1 ; + StrictFormat = TRUE ; + TabStop = TRUE ; + }; +}; diff --git a/sw/source/ui/config/optpage.cxx b/sw/source/ui/config/optpage.cxx index c8be2e244780..37f03bcd5c38 100644..100755 --- a/sw/source/ui/config/optpage.cxx +++ b/sw/source/ui/config/optpage.cxx @@ -68,6 +68,7 @@ #include <editeng/fhgtitem.hxx> #include <editeng/fontitem.hxx> #include <editeng/langitem.hxx> +#include <editeng/svxenum.hxx> #include <sfx2/request.hxx> #include <sfx2/printer.hxx> #include <sfx2/bindings.hxx> @@ -1729,6 +1730,139 @@ void SwRedlineOptionsTabPage::InitFontStyle(SvxFontPrevWindow& rExampleWin) } +//---------------------------------------------------------- +SwCompareOptionsTabPage::SwCompareOptionsTabPage( Window* pParent, const SfxItemSet& rSet ) + : SfxTabPage( pParent, SW_RES( TP_COMPARISON_OPT ), rSet ), + + aComparisonFL( this, SW_RES( FL_CMP ) ), + aAutoRB( this, SW_RES( RB_AUTO ) ), + aWordRB( this, SW_RES( RB_WORD ) ), + aCharRB( this, SW_RES( RB_CHAR ) ), + aSettingsFL( this, SW_RES( FL_SET ) ), + aRsidCB( this, SW_RES( CB_RSID) ), + aIgnoreCB( this, SW_RES( CB_IGNORE ) ), + aLenNF( this, SW_RES( NF_LEN ) ) +{ + FreeResource(); + Link aLnk( LINK( this, SwCompareOptionsTabPage, ComparisonHdl ) ); + aAutoRB.SetClickHdl( aLnk ); + aWordRB.SetClickHdl( aLnk ); + aCharRB.SetClickHdl( aLnk ); + + aIgnoreCB.SetClickHdl( LINK( this, SwCompareOptionsTabPage, IgnoreHdl) ); +} + +SwCompareOptionsTabPage::~SwCompareOptionsTabPage() +{ +} + +SfxTabPage* SwCompareOptionsTabPage::Create( Window* pParent, const SfxItemSet& rAttrSet ) +{ + return new SwCompareOptionsTabPage( pParent, rAttrSet ); +} + +sal_Bool SwCompareOptionsTabPage::FillItemSet( SfxItemSet& ) +{ + sal_Bool bRet = sal_False; + SwModuleOptions *pOpt = SW_MOD()->GetModuleConfig(); + + if( aAutoRB.IsChecked() != aAutoRB.GetSavedValue() || + aWordRB.IsChecked() != aWordRB.GetSavedValue() || + aCharRB.IsChecked() != aCharRB.GetSavedValue() ) + { + SvxCompareMode eCmpMode; + + if ( aAutoRB.IsChecked() ) eCmpMode = SVX_CMP_AUTO; + if ( aWordRB.IsChecked() ) eCmpMode = SVX_CMP_BY_WORD; + if ( aCharRB.IsChecked() ) eCmpMode = SVX_CMP_BY_CHAR; + + pOpt->SetCompareMode( eCmpMode ); + bRet = sal_True; + } + + if( aRsidCB.IsChecked() != aRsidCB.GetSavedValue() ) + { + pOpt->SetUseRsid( aRsidCB.IsChecked() ); + bRet = sal_True; + } + + if( aIgnoreCB.IsChecked() != aIgnoreCB.GetSavedValue() ) + { + pOpt->SetIgnorePieces( aIgnoreCB.IsChecked() ); + bRet = sal_True; + } + + if( aLenNF.IsModified() ) + { + pOpt->SetPieceLen( aLenNF.GetValue() ); + bRet = sal_True; + } + + return bRet; +} + +void SwCompareOptionsTabPage::Reset( const SfxItemSet& ) +{ + SwModuleOptions *pOpt = SW_MOD()->GetModuleConfig(); + + SvxCompareMode eCmpMode = pOpt->GetCompareMode(); + if( eCmpMode == SVX_CMP_AUTO ) + { + aAutoRB.Check(); + aSettingsFL.Disable(); + aRsidCB.Disable(); + aIgnoreCB.Disable(); + aLenNF.Disable(); + } + else if( eCmpMode == SVX_CMP_BY_WORD ) + { + aWordRB.Check(); + aSettingsFL.Enable(); + aRsidCB.Enable(); + aIgnoreCB.Enable(); + aLenNF.Enable(); + } + else if( eCmpMode == SVX_CMP_BY_CHAR) + { + aCharRB.Check(); + aSettingsFL.Enable(); + aRsidCB.Enable(); + aIgnoreCB.Enable(); + aLenNF.Enable(); + } + aAutoRB.SaveValue(); + aWordRB.SaveValue(); + aCharRB.SaveValue(); + + aRsidCB.Check( pOpt->IsUseRsid() ); + aRsidCB.SaveValue(); + + aIgnoreCB.Check( pOpt->IsIgnorePieces() ); + aIgnoreCB.SaveValue(); + + aLenNF.Enable( aIgnoreCB.IsChecked() && eCmpMode ); + + aLenNF.SetValue( pOpt->GetPieceLen() ); + aLenNF.SaveValue(); +} + +IMPL_LINK( SwCompareOptionsTabPage, ComparisonHdl, RadioButton*, EMPTYARG ) +{ + bool bChecked = !aAutoRB.IsChecked(); + aSettingsFL.Enable( bChecked ); + aRsidCB.Enable( bChecked ); + aIgnoreCB.Enable( bChecked ); + aLenNF.Enable( bChecked && aIgnoreCB.IsChecked() ); + + return 0; +} + +IMPL_LINK( SwCompareOptionsTabPage, IgnoreHdl, CheckBox*, EMPTYARG ) +{ + aLenNF.Enable( aIgnoreCB.IsChecked() ); + return 0; +} + #ifdef DBG_UTIL void lcl_SetPosSize(Window& rWin, Point aPos, Size aSize) @@ -1863,6 +1997,8 @@ IMPL_LINK_INLINE_START( SwTestTabPage, AutoClickHdl, CheckBox *, EMPTYARG ) return 0; } IMPL_LINK_INLINE_END( SwTestTabPage, AutoClickHdl, CheckBox *, EMPTYARG ) + + #endif diff --git a/sw/source/ui/dialog/swdlgfact.cxx b/sw/source/ui/dialog/swdlgfact.cxx index a31db0d97390..0edd38c4a2ad 100644 --- a/sw/source/ui/dialog/swdlgfact.cxx +++ b/sw/source/ui/dialog/swdlgfact.cxx @@ -1612,6 +1612,7 @@ GlossarySetActGroup SwAbstractDialogFactory_Impl::SetGlossaryActGroupFunc( sal_u return 0; } + //------------------ Factories for TabPages CreateTabPage SwAbstractDialogFactory_Impl::GetTabPageCreatorFunc( sal_uInt16 nId ) { @@ -1665,6 +1666,10 @@ CreateTabPage SwAbstractDialogFactory_Impl::GetTabPageCreatorFunc( sal_uInt16 nI case RID_SW_TP_MAILCONFIG: pRet = SwMailConfigPage::Create; break; + case RID_SW_TP_COMPARISON_OPT : + case TP_COMPARISON_OPT : + pRet = SwCompareOptionsTabPage::Create; + break; } return pRet; diff --git a/sw/source/ui/inc/optpage.hxx b/sw/source/ui/inc/optpage.hxx index 382441962599..fd66d0331f1b 100644 --- a/sw/source/ui/inc/optpage.hxx +++ b/sw/source/ui/inc/optpage.hxx @@ -45,6 +45,7 @@ class SvStringsDtor; class SfxPrinter; class SwWrtShell; class FontList; +class SwCompareConfig; class SwContentOptPage : public SfxTabPage { @@ -396,5 +397,31 @@ private: }; #endif // DBG_UTIL +class SwCompareOptionsTabPage : public SfxTabPage +{ + FixedLine aComparisonFL; + RadioButton aAutoRB; + RadioButton aWordRB; + RadioButton aCharRB; + + FixedLine aSettingsFL; + CheckBox aRsidCB; + CheckBox aIgnoreCB; + NumericField aLenNF; + + SwCompareOptionsTabPage( Window* pParent, const SfxItemSet& rSet ); + ~SwCompareOptionsTabPage(); + + DECL_LINK( ComparisonHdl, RadioButton *pRB); + DECL_LINK( IgnoreHdl, CheckBox *pCB); + +public: + + static SfxTabPage* Create( Window* pParent, const SfxItemSet& rAttrSet ); + + virtual sal_Bool FillItemSet( SfxItemSet& rSet ); + virtual void Reset( const SfxItemSet& rSet ); +}; + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/uno/SwXDocumentSettings.cxx b/sw/source/ui/uno/SwXDocumentSettings.cxx index a56f5841f5b7..2711275c4b4a 100644 --- a/sw/source/ui/uno/SwXDocumentSettings.cxx +++ b/sw/source/ui/uno/SwXDocumentSettings.cxx @@ -115,6 +115,8 @@ enum SwDocumentSettingsPropertyHandles HANDLE_USE_OLD_PRINTER_METRICS, HANDLE_PROTECT_FORM, HANDLE_TABS_RELATIVE_TO_INDENT, + HANDLE_RSID, + HANDLE_RSID_ROOT, // #i89181# HANDLE_TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST, HANDLE_MODIFYPASSWORDINFO, @@ -174,6 +176,8 @@ MasterPropertySetInfo * lcl_createSettingsInfo() { RTL_CONSTASCII_STRINGPARAM("UnxForceZeroExtLeading"), HANDLE_UNIX_FORCE_ZERO_EXT_LEADING, CPPUTYPE_BOOLEAN, 0, 0}, { RTL_CONSTASCII_STRINGPARAM("UseOldPrinterMetrics"), HANDLE_USE_OLD_PRINTER_METRICS, CPPUTYPE_BOOLEAN, 0, 0}, { RTL_CONSTASCII_STRINGPARAM("TabsRelativeToIndent"), HANDLE_TABS_RELATIVE_TO_INDENT, CPPUTYPE_BOOLEAN, 0, 0}, + { RTL_CONSTASCII_STRINGPARAM("Rsid"), HANDLE_RSID, CPPUTYPE_INT32, 0, 0}, + { RTL_CONSTASCII_STRINGPARAM("RsidRoot"), HANDLE_RSID_ROOT, CPPUTYPE_INT32, 0, 0}, { RTL_CONSTASCII_STRINGPARAM("ProtectForm"), HANDLE_PROTECT_FORM, CPPUTYPE_BOOLEAN, 0, 0}, // #i89181# { RTL_CONSTASCII_STRINGPARAM("TabAtLeftIndentForParagraphsInList"), HANDLE_TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST, CPPUTYPE_BOOLEAN, 0, 0}, @@ -657,6 +661,20 @@ void SwXDocumentSettings::_setSingleValue( const comphelper::PropertyInfo & rInf mpDoc->set(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT, bTmp); } break; + case HANDLE_RSID: + { + sal_uInt32 nTmp = 0; + rValue >>= nTmp; + mpDoc->setRsid( nTmp ); + } + break; + case HANDLE_RSID_ROOT: + { + sal_uInt32 nTmp = 0; + rValue >>= nTmp; + mpDoc->setRsidRoot( nTmp ); + } + break; case HANDLE_PROTECT_FORM: { sal_Bool bTmp = *(sal_Bool*)rValue.getValue(); @@ -1029,6 +1047,16 @@ void SwXDocumentSettings::_getSingleValue( const comphelper::PropertyInfo & rInf rValue.setValue( &bTmp, ::getBooleanCppuType() ); } break; + case HANDLE_RSID: + { + rValue <<= static_cast < sal_Int32 > ( mpDoc->getRsid() ); + } + break; + case HANDLE_RSID_ROOT: + { + rValue <<= static_cast < sal_Int32 > ( mpDoc->getRsidRoot() ); + } + break; case HANDLE_PROTECT_FORM: { sal_Bool bTmp = mpDoc->get(IDocumentSettingAccess::PROTECT_FORM); diff --git a/xmloff/inc/xmloff/xmltoken.hxx b/xmloff/inc/xmloff/xmltoken.hxx index b609dad06faa..3a07e309c999 100644 --- a/xmloff/inc/xmloff/xmltoken.hxx +++ b/xmloff/inc/xmloff/xmltoken.hxx @@ -1498,6 +1498,8 @@ namespace xmloff { namespace token { XML_ROW_HEIGHT, XML_ROW_NUMBER, XML_ROWS, + XML_RSID, + XML_PARRSID, XML_RUBY, XML_RUBY_ALIGN, XML_RUBY_BASE, diff --git a/xmloff/inc/xmloff/xmltypes.hxx b/xmloff/inc/xmloff/xmltypes.hxx index 922ad3f340d0..9aee08b6fc59 100644 --- a/xmloff/inc/xmloff/xmltypes.hxx +++ b/xmloff/inc/xmloff/xmltypes.hxx @@ -152,6 +152,7 @@ #define XML_TYPE_NEG_PERCENT8 0x00002022 // (100-x)% #define XML_TYPE_NEG_PERCENT16 0x00002023 // (100-x) #define XML_TYPE_DOUBLE_PERCENT 0x00002024 // 50% (source is a double from 0.0 to 1.0) +#define XML_TYPE_HEX 0x00002025 // 00544F1B // special basic types #define XML_TYPE_RECTANGLE_LEFT 0x00000100 // the Left member of a awt::Rectangle as a measure diff --git a/xmloff/inc/xmloff/xmluconv.hxx b/xmloff/inc/xmloff/xmluconv.hxx index 003fe8c8e021..7e9a460be64c 100644 --- a/xmloff/inc/xmloff/xmluconv.hxx +++ b/xmloff/inc/xmloff/xmluconv.hxx @@ -247,6 +247,13 @@ public: ::rtl::OUString encodeStyleName( const ::rtl::OUString& rName, sal_Bool *pEncoded=0 ) const; + /** convert string (hex) to number (sal_uInt32) */ + static sal_Bool convertHex( sal_uInt32& nVal, + const ::rtl::OUString& rValue ); + + /** convert number (sal_uInt32) to string (hex) */ + static void convertHex( ::rtl::OUStringBuffer& rBuffer, + sal_uInt32 nVal ); }; diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 02970ebf02cc..9ccc67fe94ae 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -1503,6 +1503,8 @@ namespace xmloff { namespace token { TOKEN( "row-height", XML_ROW_HEIGHT ), TOKEN( "row-number", XML_ROW_NUMBER ), TOKEN( "rows", XML_ROWS ), + TOKEN( "rsid", XML_RSID ), + TOKEN( "paragraph-rsid", XML_PARRSID ), TOKEN( "ruby", XML_RUBY ), TOKEN( "ruby-align", XML_RUBY_ALIGN ), TOKEN( "ruby-base", XML_RUBY_BASE ), diff --git a/xmloff/source/core/xmluconv.cxx b/xmloff/source/core/xmluconv.cxx index 6ceb8850b014..3ec1a49febeb 100644 --- a/xmloff/source/core/xmluconv.cxx +++ b/xmloff/source/core/xmluconv.cxx @@ -931,4 +931,32 @@ OUString SvXMLUnitConverter::encodeStyleName( return aBuffer.makeStringAndClear(); } +/** convert string (hex) to number (sal_uInt32) */ +sal_Bool SvXMLUnitConverter::convertHex( sal_uInt32& nVal, + const OUString& rValue ) +{ + if( rValue.getLength() != 8 ) + return sal_False; + + nVal = 0; + for ( int i = 0; i < 8; i++ ) + { + nVal = ( nVal << 4 ) + | sal::static_int_cast< sal_uInt32 >( lcl_gethex( rValue[i] ) ); + } + + return sal_True; +} + +/** convert number (sal_uInt32) to string (hex) */ +void SvXMLUnitConverter::convertHex( OUStringBuffer& rBuffer, + sal_uInt32 nVal ) +{ + for ( int i = 0; i < 8; i++ ) + { + rBuffer.append( sal_Unicode( aHexTab[ nVal >> 28 ] ) ); + nVal <<= 4; + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/prhdlfac.cxx b/xmloff/source/style/prhdlfac.cxx index 9e258e8b88d9..a2d2ea18762c 100644 --- a/xmloff/source/style/prhdlfac.cxx +++ b/xmloff/source/style/prhdlfac.cxx @@ -210,6 +210,9 @@ const XMLPropertyHandler* XMLPropertyHandlerFactory::CreatePropertyHandler( sal_ case XML_TYPE_COLOR : pPropHdl = new XMLColorPropHdl; break; + case XML_TYPE_HEX : + pPropHdl = new XMLHexPropHdl; + break; case XML_TYPE_NUMBER : pPropHdl = new XMLNumberPropHdl( 4 ); break; diff --git a/xmloff/source/style/xmlbahdl.cxx b/xmloff/source/style/xmlbahdl.cxx index a9f8b147c7f9..b34b37a166fd 100644 --- a/xmloff/source/style/xmlbahdl.cxx +++ b/xmloff/source/style/xmlbahdl.cxx @@ -545,6 +545,48 @@ sal_Bool XMLColorPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, /////////////////////////////////////////////////////////////////////////////// // +// class XMLHexPropHdl +// + +XMLHexPropHdl::~XMLHexPropHdl() +{ + // Nothing to do +} + +sal_Bool XMLHexPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Bool bRet = sal_False; + sal_uInt32 nRsid; + + bRet = SvXMLUnitConverter::convertHex( nRsid, rStrImpValue ); + rValue <<= nRsid; + + return bRet; +} + +sal_Bool XMLHexPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Bool bRet = sal_False; + sal_uInt32 nRsid = 0; + + OUStringBuffer aOut; + if( rValue >>= nRsid ) + { + SvXMLUnitConverter::convertHex( aOut, nRsid ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = sal_True; + } + else + { + bRet = sal_False; + } + + return bRet; +} + +/////////////////////////////////////////////////////////////////////////////// +// // class XMLStringPropHdl // diff --git a/xmloff/source/style/xmlbahdl.hxx b/xmloff/source/style/xmlbahdl.hxx index 80f75b0159c7..83b7741b5758 100644 --- a/xmloff/source/style/xmlbahdl.hxx +++ b/xmloff/source/style/xmlbahdl.hxx @@ -156,6 +156,18 @@ public: }; /** + PropertyHandler for the XML-data-type: XML_TYPE_HEX +*/ +class XMLHexPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLHexPropHdl(); + + virtual sal_Bool importXML( const ::rtl::OUString& rStrImpValue, ::com::sun::star::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const; + virtual sal_Bool exportXML( ::rtl::OUString& rStrExpValue, const ::com::sun::star::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const; +}; + +/** PropertyHandler for the XML-data-type: XML_TYPE_STRING */ class XMLStringPropHdl : public XMLPropertyHandler diff --git a/xmloff/source/text/txtprmap.cxx b/xmloff/source/text/txtprmap.cxx index 6a2582c755b2..29559a6db7dc 100644 --- a/xmloff/source/text/txtprmap.cxx +++ b/xmloff/source/text/txtprmap.cxx @@ -147,6 +147,10 @@ XMLPropertyMapEntry aXMLParaPropMap[] = MT_E( "CharUnderlineHasColor", STYLE, TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE, CTF_UNDERLINE_HASCOLOR ), // RES_CHRATR_WEIGHT MT_E( "CharWeight", FO, FONT_WEIGHT, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_RSID + { "Rsid", sizeof("Rsid")-1, XML_NAMESPACE_OFFICE_EXT, XML_RSID, XML_TYPE_HEX|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFVER_LATEST }, + // RES_PARATR_RSID + { "ParRsid", sizeof("ParRsid")-1, XML_NAMESPACE_OFFICE_EXT, XML_PARRSID, XML_TYPE_HEX|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFVER_LATEST }, // RES_CHRATR_WORDLINEMODE MT_E( "CharWordMode", STYLE, TEXT_UNDERLINE_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), MT_E( "CharWordMode", STYLE, TEXT_OVERLINE_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), @@ -442,6 +446,10 @@ XMLPropertyMapEntry aXMLTextPropMap[] = MT_E( "CharUnderlineHasColor", STYLE, TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE, CTF_UNDERLINE_HASCOLOR ), // RES_CHRATR_WEIGHT MT_E( "CharWeight", FO, FONT_WEIGHT, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_RSID + { "Rsid", sizeof("Rsid")-1, XML_NAMESPACE_OFFICE_EXT, XML_RSID, XML_TYPE_HEX|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFVER_LATEST }, + // RES_PARATR_RSID + { "ParRsid", sizeof("ParRsid")-1, XML_NAMESPACE_OFFICE_EXT, XML_PARRSID, XML_TYPE_HEX|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFVER_LATEST }, // RES_CHRATR_WORDLINEMODE MT_E( "CharWordMode", STYLE, TEXT_UNDERLINE_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), MT_E( "CharWordMode", STYLE, TEXT_OVERLINE_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), |