1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
21 #include <com/sun/star/document/XDocumentProperties.hpp>
24 #include <IDocumentFieldsAccess.hxx>
25 #include <svtools/htmltokn.h>
26 #include <svl/zformat.hxx>
27 #include <unotools/useroptions.hxx>
32 #include <docufld.hxx>
34 #include <htmlfld.hxx>
37 using namespace nsSwDocInfoSubType
;
38 using namespace ::com::sun::star
;
40 struct HTMLNumFormatTableEntry
42 const sal_Char
*pName
;
43 NfIndexTableOffset eFormat
;
46 static HTMLOptionEnum aHTMLFieldTypeTable
[] =
48 { OOO_STRING_SW_HTML_FT_author
, RES_AUTHORFLD
},
49 { OOO_STRING_SW_HTML_FT_sender
, RES_EXTUSERFLD
},
50 { "DATE", RES_DATEFLD
},
51 { "TIME", RES_TIMEFLD
},
52 { OOO_STRING_SW_HTML_FT_datetime
,RES_DATETIMEFLD
},
53 { OOO_STRING_SW_HTML_FT_page
, RES_PAGENUMBERFLD
},
54 { OOO_STRING_SW_HTML_FT_docinfo
, RES_DOCINFOFLD
},
55 { OOO_STRING_SW_HTML_FT_docstat
, RES_DOCSTATFLD
},
56 { OOO_STRING_SW_HTML_FT_filename
,RES_FILENAMEFLD
},
60 static HTMLNumFormatTableEntry aHTMLDateFieldFormatTable
[] =
62 { "SSYS", NF_DATE_SYSTEM_SHORT
},
63 { "LSYS", NF_DATE_SYSTEM_LONG
},
64 { "DMY", NF_DATE_SYS_DDMMYY
, },
65 { "DMYY", NF_DATE_SYS_DDMMYYYY
, },
66 { "DMMY", NF_DATE_SYS_DMMMYY
, },
67 { "DMMYY", NF_DATE_SYS_DMMMYYYY
, },
68 { "DMMMY", NF_DATE_DIN_DMMMMYYYY
},
69 { "DMMMYY", NF_DATE_DIN_DMMMMYYYY
},
70 { "DDMMY", NF_DATE_SYS_NNDMMMYY
},
71 { "DDMMMY", NF_DATE_SYS_NNDMMMMYYYY
},
72 { "DDMMMYY", NF_DATE_SYS_NNDMMMMYYYY
},
73 { "DDDMMMY", NF_DATE_SYS_NNNNDMMMMYYYY
},
74 { "DDDMMMYY", NF_DATE_SYS_NNNNDMMMMYYYY
},
75 { "MY", NF_DATE_SYS_MMYY
},
76 { "MD", NF_DATE_DIN_MMDD
},
77 { "YMD", NF_DATE_DIN_YYMMDD
},
78 { "YYMD", NF_DATE_DIN_YYYYMMDD
},
79 { nullptr, NF_NUMERIC_START
}
82 static HTMLNumFormatTableEntry aHTMLTimeFieldFormatTable
[] =
84 { "SYS", NF_TIME_HHMMSS
},
85 { "SSMM24", NF_TIME_HHMM
},
86 { "SSMM12", NF_TIME_HHMMAMPM
},
87 { nullptr, NF_NUMERIC_START
}
90 static HTMLOptionEnum aHTMLPageNumFieldFormatTable
[] =
92 { OOO_STRING_SW_HTML_FF_uletter
, SVX_NUM_CHARS_UPPER_LETTER
},
93 { OOO_STRING_SW_HTML_FF_lletter
, SVX_NUM_CHARS_LOWER_LETTER
},
94 { OOO_STRING_SW_HTML_FF_uroman
, SVX_NUM_ROMAN_UPPER
},
95 { OOO_STRING_SW_HTML_FF_lroman
, SVX_NUM_ROMAN_LOWER
},
96 { OOO_STRING_SW_HTML_FF_arabic
, SVX_NUM_ARABIC
},
97 { OOO_STRING_SW_HTML_FF_none
, SVX_NUM_NUMBER_NONE
},
98 { OOO_STRING_SW_HTML_FF_char
, SVX_NUM_CHAR_SPECIAL
},
99 { OOO_STRING_SW_HTML_FF_page
, SVX_NUM_PAGEDESC
},
100 { OOO_STRING_SW_HTML_FF_ulettern
, SVX_NUM_CHARS_UPPER_LETTER_N
},
101 { OOO_STRING_SW_HTML_FF_llettern
, SVX_NUM_CHARS_LOWER_LETTER_N
},
105 static HTMLOptionEnum aHTMLExtUsrFieldSubTable
[] =
107 { OOO_STRING_SW_HTML_FS_company
, EU_COMPANY
},
108 { OOO_STRING_SW_HTML_FS_firstname
, EU_FIRSTNAME
},
109 { OOO_STRING_SW_HTML_FS_name
, EU_NAME
},
110 { OOO_STRING_SW_HTML_FS_shortcut
, EU_SHORTCUT
},
111 { OOO_STRING_SW_HTML_FS_street
, EU_STREET
},
112 { OOO_STRING_SW_HTML_FS_country
, EU_COUNTRY
},
113 { OOO_STRING_SW_HTML_FS_zip
, EU_ZIP
},
114 { OOO_STRING_SW_HTML_FS_city
, EU_CITY
},
115 { OOO_STRING_SW_HTML_FS_title
, EU_TITLE
},
116 { OOO_STRING_SW_HTML_FS_position
, EU_POSITION
},
117 { OOO_STRING_SW_HTML_FS_pphone
, EU_PHONE_PRIVATE
},
118 { OOO_STRING_SW_HTML_FS_cphone
, EU_PHONE_COMPANY
},
119 { OOO_STRING_SW_HTML_FS_fax
, EU_FAX
},
120 { OOO_STRING_SW_HTML_FS_email
, EU_EMAIL
},
121 { OOO_STRING_SW_HTML_FS_state
, EU_STATE
},
125 static HTMLOptionEnum aHTMLAuthorFieldFormatTable
[] =
127 { OOO_STRING_SW_HTML_FF_name
, AF_NAME
},
128 { OOO_STRING_SW_HTML_FF_shortcut
, AF_SHORTCUT
},
132 static HTMLOptionEnum aHTMLPageNumFieldSubTable
[] =
134 { OOO_STRING_SW_HTML_FS_random
, PG_RANDOM
},
135 { OOO_STRING_SW_HTML_FS_next
, PG_NEXT
},
136 { OOO_STRING_SW_HTML_FS_prev
, PG_PREV
},
140 // UGLY: these are extensions of nsSwDocInfoSubType (in inc/docufld.hxx)
141 // these are necessary for importing document info fields written by
142 // older versions of OOo (< 3.0) which did not have DI_CUSTOM fields
143 const SwDocInfoSubType DI_INFO1
= DI_SUBTYPE_END
+ 1;
144 const SwDocInfoSubType DI_INFO2
= DI_SUBTYPE_END
+ 2;
145 const SwDocInfoSubType DI_INFO3
= DI_SUBTYPE_END
+ 3;
146 const SwDocInfoSubType DI_INFO4
= DI_SUBTYPE_END
+ 4;
148 static HTMLOptionEnum aHTMLDocInfoFieldSubTable
[] =
150 { OOO_STRING_SW_HTML_FS_title
, DI_TITEL
},
151 { OOO_STRING_SW_HTML_FS_theme
, DI_THEMA
},
152 { OOO_STRING_SW_HTML_FS_keys
, DI_KEYS
},
153 { OOO_STRING_SW_HTML_FS_comment
, DI_COMMENT
},
154 { "INFO1", DI_INFO1
},
155 { "INFO2", DI_INFO2
},
156 { "INFO3", DI_INFO3
},
157 { "INFO4", DI_INFO4
},
158 { OOO_STRING_SW_HTML_FS_custom
, DI_CUSTOM
},
159 { OOO_STRING_SW_HTML_FS_create
, DI_CREATE
},
160 { OOO_STRING_SW_HTML_FS_change
, DI_CHANGE
},
164 static HTMLOptionEnum aHTMLDocInfoFieldFormatTable
[] =
166 { OOO_STRING_SW_HTML_FF_author
, DI_SUB_AUTHOR
},
167 { OOO_STRING_SW_HTML_FF_time
, DI_SUB_TIME
},
168 { OOO_STRING_SW_HTML_FF_date
, DI_SUB_DATE
},
172 static HTMLOptionEnum aHTMLDocStatFieldSubTable
[] =
174 { OOO_STRING_SW_HTML_FS_page
, DS_PAGE
},
175 { OOO_STRING_SW_HTML_FS_para
, DS_PARA
},
176 { OOO_STRING_SW_HTML_FS_word
, DS_WORD
},
177 { OOO_STRING_SW_HTML_FS_char
, DS_CHAR
},
178 { OOO_STRING_SW_HTML_FS_tbl
, DS_TBL
},
179 { OOO_STRING_SW_HTML_FS_grf
, DS_GRF
},
180 { OOO_STRING_SW_HTML_FS_ole
, DS_OLE
},
184 static HTMLOptionEnum aHTMLFileNameFieldFormatTable
[] =
186 { OOO_STRING_SW_HTML_FF_name
, FF_NAME
},
187 { OOO_STRING_SW_HTML_FF_pathname
, FF_PATHNAME
},
188 { OOO_STRING_SW_HTML_FF_path
, FF_PATH
},
189 { OOO_STRING_SW_HTML_FF_name_noext
, FF_NAME_NOEXT
},
193 sal_uInt16
SwHTMLParser::GetNumType( const OUString
& rStr
, sal_uInt16 nDfltType
)
195 sal_uInt16 nType
= nDfltType
;
196 const HTMLOptionEnum
*pOptEnums
= aHTMLPageNumFieldFormatTable
;
197 while( pOptEnums
->pName
)
198 if( !rStr
.equalsIgnoreAsciiCaseAscii( pOptEnums
->pName
) )
203 if( pOptEnums
->pName
)
204 nType
= pOptEnums
->nValue
;
209 void SwHTMLParser::NewField()
211 bool bKnownType
= false, bFixed
= false,
212 bHasNumFormat
= false, bHasNumValue
= false;
213 sal_uInt16 nType
= 0;
214 OUString aValue
, aNumFormat
, aNumValue
, aName
;
215 const HTMLOption
*pSubOption
=nullptr, *pFormatOption
=nullptr;
217 const HTMLOptions
& rHTMLOptions
= GetOptions();
220 for ( i
= rHTMLOptions
.size(); i
; )
222 const HTMLOption
& rOption
= rHTMLOptions
[--i
];
223 switch( rOption
.GetToken() )
226 bKnownType
= rOption
.GetEnum( nType
, aHTMLFieldTypeTable
);
229 pSubOption
= &rOption
;
232 pFormatOption
= &rOption
;
235 aName
= rOption
.GetString();
238 aValue
= rOption
.GetString();
241 aNumFormat
= rOption
.GetString();
242 bHasNumFormat
= true;
245 aNumValue
= rOption
.GetString();
257 // Autor und Absender werden nur als als variables Feld eingefuegt,
258 // wenn man das Dok selbst als letztes geaendert hat oder es noch
259 // niemend geandert hat und man das Dok erstellt hat. Sonst
260 // wird ein Fixed-Feld daraus gemacht.
262 (RES_EXTUSERFLD
== (RES_FIELDS
)nType
||
263 RES_AUTHORFLD
== (RES_FIELDS
)nType
) )
266 const OUString
& rUser
= aOpt
.GetFullName();
267 SwDocShell
*pDocShell(m_pDoc
->GetDocShell());
268 OSL_ENSURE(pDocShell
, "no SwDocShell");
270 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
271 pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
272 uno::Reference
<document::XDocumentProperties
> xDocProps(
273 xDPS
->getDocumentProperties());
274 OSL_ENSURE(xDocProps
.is(), "Doc has no DocumentProperties");
275 const OUString
& rChanged
= xDocProps
->getModifiedBy();
276 const OUString
& rCreated
= xDocProps
->getAuthor();
277 if( rUser
.isEmpty() ||
278 (!rChanged
.isEmpty() ? rUser
!= rChanged
: rUser
!= rCreated
) )
283 sal_uInt16 nWhich
= nType
;
284 if( RES_DATEFLD
==nType
|| RES_TIMEFLD
==nType
)
285 nWhich
= RES_DATETIMEFLD
;
287 SwFieldType
* pType
= m_pDoc
->getIDocumentFieldsAccess().GetSysFieldType( nWhich
);
288 SwField
*pNewField
= nullptr;
289 bool bInsOnEndTag
= false;
291 switch( (RES_FIELDS
)nType
)
297 sal_uLong nFormat
= 0;
303 if( pSubOption
->GetEnum( nSub
, aHTMLExtUsrFieldSubTable
) )
304 pNewField
= new SwExtUserField(static_cast<SwExtUserFieldType
*>(pType
), nSub
, nFormat
);
310 sal_uInt16 nFormat
= AF_NAME
;
312 pFormatOption
->GetEnum( nFormat
, aHTMLAuthorFieldFormatTable
);
319 pNewField
= new SwAuthorField(static_cast<SwAuthorFieldType
*>(pType
), nFormat
);
326 sal_uInt32 nNumFormat
= 0;
327 sal_Int64 nTime
= tools::Time( tools::Time::SYSTEM
).GetTime();
328 sal_Int32 nDate
= Date( Date::SYSTEM
).GetDate();
330 bool bValidFormat
= false;
331 HTMLNumFormatTableEntry
* pFormatTable
;
333 if( RES_DATEFLD
==nType
)
336 pFormatTable
= aHTMLDateFieldFormatTable
;
337 if( !aValue
.isEmpty() )
338 nDate
= aValue
.toInt32();
343 pFormatTable
= aHTMLTimeFieldFormatTable
;
344 if( !aValue
.isEmpty() )
345 nTime
= (sal_uLong
)aValue
.toInt32();
347 if( !aValue
.isEmpty() )
350 SvNumberFormatter
*pFormatter
= m_pDoc
->GetNumberFormatter();
353 const OUString
& rFormat
= pFormatOption
->GetString();
354 for( int k
= 0; pFormatTable
[k
].pName
; ++k
)
356 if( rFormat
.equalsIgnoreAsciiCaseAscii( pFormatTable
[k
].pName
) )
358 nNumFormat
= pFormatter
->GetFormatIndex(
359 pFormatTable
[k
].eFormat
, LANGUAGE_SYSTEM
);
366 nNumFormat
= pFormatter
->GetFormatIndex( pFormatTable
[i
].eFormat
,
369 pNewField
= new SwDateTimeField(static_cast<SwDateTimeFieldType
*>(pType
), nSub
, nNumFormat
);
372 static_cast<SwDateTimeField
*>(pNewField
)->SetDateTime(DateTime(Date(nDate
), tools::Time(nTime
)));
376 case RES_DATETIMEFLD
:
381 SvNumberFormatter
*pFormatter
= m_pDoc
->GetNumberFormatter();
382 sal_uInt32 nNumFormat
;
384 double dValue
= GetTableDataOptionsValNum(
385 nNumFormat
, eLang
, aNumValue
, aNumFormat
,
386 *m_pDoc
->GetNumberFormatter() );
387 short nFormatType
= pFormatter
->GetType( nNumFormat
);
388 switch( nFormatType
)
390 case css::util::NumberFormat::DATE
: nSub
= DATEFLD
; break;
391 case css::util::NumberFormat::TIME
: nSub
= TIMEFLD
; break;
399 pNewField
= new SwDateTimeField(static_cast<SwDateTimeFieldType
*>(pType
), nSub
, nNumFormat
);
401 static_cast<SwDateTimeField
*>(pNewField
)->SetValue(dValue
);
406 case RES_PAGENUMBERFLD
:
410 if( pSubOption
->GetEnum( nSub
, aHTMLPageNumFieldSubTable
) )
412 sal_uInt16 nFormat
= SVX_NUM_PAGEDESC
;
414 pFormatOption
->GetEnum( nFormat
, aHTMLPageNumFieldFormatTable
);
418 if( (SvxExtNumType
)nFormat
!=SVX_NUM_CHAR_SPECIAL
&& !aValue
.isEmpty() )
419 nOff
= (short)aValue
.toInt32();
420 else if( (SwPageNumSubType
)nSub
== PG_NEXT
)
422 else if( (SwPageNumSubType
)nSub
== PG_PREV
)
425 if( (SvxExtNumType
)nFormat
==SVX_NUM_CHAR_SPECIAL
&&
426 (SwPageNumSubType
)nSub
==PG_RANDOM
)
427 nFormat
= SVX_NUM_PAGEDESC
;
429 pNewField
= new SwPageNumberField(static_cast<SwPageNumberFieldType
*>(pType
), nSub
, nFormat
, nOff
);
430 if ((SvxExtNumType
)nFormat
== SVX_NUM_CHAR_SPECIAL
)
431 static_cast<SwPageNumberField
*>(pNewField
)->SetUserString(aValue
);
440 if( pSubOption
->GetEnum( nSub
, aHTMLDocInfoFieldSubTable
) )
442 sal_uInt16 nExtSub
= 0;
443 if( DI_CREATE
==(SwDocInfoSubType
)nSub
||
444 DI_CHANGE
==(SwDocInfoSubType
)nSub
)
446 nExtSub
= DI_SUB_AUTHOR
;
448 pFormatOption
->GetEnum( nExtSub
, aHTMLDocInfoFieldFormatTable
);
452 sal_uInt32 nNumFormat
= 0;
454 if( bHasNumFormat
&& (DI_SUB_DATE
==nExtSub
|| DI_SUB_TIME
==nExtSub
) )
457 dValue
= GetTableDataOptionsValNum(
458 nNumFormat
, eLang
, aNumValue
, aNumFormat
,
459 *m_pDoc
->GetNumberFormatter() );
460 bFixed
&= bHasNumValue
;
463 bHasNumValue
= false;
465 if( nSub
>= DI_INFO1
&& nSub
<= DI_INFO4
&& aName
.isEmpty() )
467 // backward compatibility for OOo 2:
468 // map to names stored in AddMetaUserDefined
469 aName
= m_InfoNames
[nSub
- DI_INFO1
];
475 nSub
|= DI_SUB_FIXED
;
479 pNewField
= new SwDocInfoField(static_cast<SwDocInfoFieldType
*>(pType
), nSub
, aName
, nNumFormat
);
481 static_cast<SwDocInfoField
*>(pNewField
)->SetValue(dValue
);
490 if( pSubOption
->GetEnum( nSub
, aHTMLDocStatFieldSubTable
) )
492 sal_uInt16 nFormat
= SVX_NUM_ARABIC
;
494 pFormatOption
->GetEnum( nFormat
, aHTMLPageNumFieldFormatTable
);
495 pNewField
= new SwDocStatField(static_cast<SwDocStatFieldType
*>(pType
), nSub
, nFormat
);
496 m_bUpdateDocStat
|= (DS_PAGE
!= nFormat
);
501 case RES_FILENAMEFLD
:
503 sal_uInt16 nFormat
= FF_NAME
;
505 pFormatOption
->GetEnum( nFormat
, aHTMLFileNameFieldFormatTable
);
512 pNewField
= new SwFileNameField(static_cast<SwFileNameFieldType
*>(pType
), nFormat
);
523 m_pField
= pNewField
;
527 m_pDoc
->getIDocumentContentOperations().InsertPoolItem(*m_pPam
, SwFormatField(*pNewField
));
534 void SwHTMLParser::EndField()
538 switch( m_pField
->Which() )
541 OSL_ENSURE( static_cast<SwDocInfoField
*>(m_pField
)->IsFixed(),
542 "DokInfo-Feld haette nicht gemerkt werden muessen" );
543 static_cast<SwDocInfoField
*>(m_pField
)->SetExpansion( m_aContents
);
547 OSL_ENSURE( static_cast<SwExtUserField
*>(m_pField
)->IsFixed(),
548 "ExtUser-Feld haette nicht gemerkt werden muessen" );
549 static_cast<SwExtUserField
*>(m_pField
)->SetExpansion( m_aContents
);
553 OSL_ENSURE( static_cast<SwAuthorField
*>(m_pField
)->IsFixed(),
554 "Author-Feld haette nicht gemerkt werden muessen" );
555 static_cast<SwAuthorField
*>(m_pField
)->SetExpansion( m_aContents
);
558 case RES_FILENAMEFLD
:
559 OSL_ENSURE( static_cast<SwFileNameField
*>(m_pField
)->IsFixed(),
560 "FileName-Feld haette nicht gemerkt werden muessen" );
561 static_cast<SwFileNameField
*>(m_pField
)->SetExpansion( m_aContents
);
565 m_pDoc
->getIDocumentContentOperations().InsertPoolItem( *m_pPam
, SwFormatField(*m_pField
) );
574 void SwHTMLParser::InsertFieldText()
578 // das aktuelle Textstueck an den Text anhaengen
579 m_aContents
+= aToken
;
583 void SwHTMLParser::InsertCommentText( const sal_Char
*pTag
)
585 bool bEmpty
= m_aContents
.isEmpty();
589 m_aContents
+= aToken
;
592 OUString
aTmp( m_aContents
);
593 m_aContents
= "HTML: <" + OUString( *pTag
) + ">" + aTmp
;
597 void SwHTMLParser::InsertComment( const OUString
& rComment
, const sal_Char
*pTag
)
599 OUString
aComment( rComment
);
603 aComment
+= OUString::createFromAscii(pTag
);
607 // MIB 24.06.97: Wenn ein PostIt nach einen Space eingefuegt
608 // werden soll, fuegen wir es vor dem Space ein. Dann gibt es
609 // weniger Probleme beim Formatieren (bug #40483#)
610 const sal_Int32 nPos
= m_pPam
->GetPoint()->nContent
.GetIndex();
611 SwTextNode
*pTextNd
= m_pPam
->GetNode().GetTextNode();
612 bool bMoveFwd
= false;
613 if (nPos
>0 && pTextNd
&& (' ' == pTextNd
->GetText()[nPos
-1]))
617 sal_uLong nNodeIdx
= m_pPam
->GetPoint()->nNode
.GetIndex();
618 const sal_Int32 nIdx
= m_pPam
->GetPoint()->nContent
.GetIndex();
619 for( auto i
= m_aSetAttrTab
.size(); i
> 0; )
621 HTMLAttr
*pAttr
= m_aSetAttrTab
[--i
];
622 if( pAttr
->GetSttParaIdx() != nNodeIdx
||
623 pAttr
->GetSttCnt() != nIdx
)
626 if( RES_TXTATR_FIELD
== pAttr
->pItem
->Which() &&
627 RES_SCRIPTFLD
== static_cast<const SwFormatField
*>(pAttr
->pItem
)->GetField()->GetTyp()->Which() )
635 m_pPam
->Move( fnMoveBackward
);
638 SwPostItField
aPostItField(
639 static_cast<SwPostItFieldType
*>(m_pDoc
->getIDocumentFieldsAccess().GetSysFieldType( RES_POSTITFLD
)),
640 aEmptyOUStr
, aComment
, aEmptyOUStr
, aEmptyOUStr
, DateTime( DateTime::SYSTEM
) );
641 InsertAttr( SwFormatField( aPostItField
), false );
644 m_pPam
->Move( fnMoveForward
);
647 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */