Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "XMLRedlineImportHelper.hxx"
30 : : #include <unotextcursor.hxx>
31 : : #include <unotextrange.hxx>
32 : : #include <unocrsr.hxx>
33 : : #include "doc.hxx"
34 : : #include <tools/datetime.hxx>
35 : : #include "poolfmt.hxx"
36 : : #include "unoredline.hxx"
37 : : #include <xmloff/xmltoken.hxx>
38 : : #include <com/sun/star/frame/XModel.hpp>
39 : :
40 : : // for locking SolarMutex: svapp + mutex
41 : : #include <vcl/svapp.hxx>
42 : : #include <osl/mutex.hxx>
43 : :
44 : :
45 : :
46 : : using namespace ::com::sun::star;
47 : : using namespace ::com::sun::star::uno;
48 : : using namespace ::xmloff::token;
49 : :
50 : : using ::rtl::OUString;
51 : : using ::com::sun::star::frame::XModel;
52 : : using ::com::sun::star::text::XTextCursor;
53 : : using ::com::sun::star::text::XTextRange;
54 : : using ::com::sun::star::text::XText;
55 : : using ::com::sun::star::text::XWordCursor;
56 : : using ::com::sun::star::lang::XUnoTunnel;
57 : : using ::com::sun::star::beans::XPropertySet;
58 : : using ::com::sun::star::beans::XPropertySetInfo;
59 : : // collision with tools/DateTime: use UNO DateTime as util::DateTime
60 : : // using util::DateTime;
61 : :
62 : :
63 : : //
64 : : // a few helper functions
65 : : //
66 : :
67 : 0 : SwDoc* lcl_GetDocViaTunnel( Reference<XTextCursor> & rCursor )
68 : : {
69 [ # # ]: 0 : Reference<XUnoTunnel> xTunnel( rCursor, UNO_QUERY);
70 : : OSL_ENSURE(xTunnel.is(), "missing XUnoTunnel for XTextCursor");
71 : : OTextCursorHelper *const pXCursor =
72 [ # # ]: 0 : ::sw::UnoTunnelGetImplementation<OTextCursorHelper>(xTunnel);
73 : : OSL_ENSURE( pXCursor, "OTextCursorHelper missing" );
74 [ # # ][ # # ]: 0 : return (pXCursor) ? pXCursor->GetDoc() : 0;
75 : : }
76 : :
77 : 0 : SwDoc* lcl_GetDocViaTunnel( Reference<XTextRange> & rRange )
78 : : {
79 [ # # ]: 0 : Reference<XUnoTunnel> xTunnel(rRange, UNO_QUERY);
80 : : OSL_ENSURE(xTunnel.is(), "missing XUnoTunnel for XTextRange");
81 : : SwXTextRange *const pXRange =
82 [ # # ]: 0 : ::sw::UnoTunnelGetImplementation<SwXTextRange>(xTunnel);
83 : : // #i115174#: this may be a SvxUnoTextRange
84 : : // OSL_ENSURE( pXRange, "SwXTextRange missing" );
85 [ # # ][ # # ]: 0 : return (pXRange) ? pXRange->GetDoc() : 0;
86 : : }
87 : :
88 : :
89 : : //
90 : : // XTextRangeOrNodeIndexPosition: store a position into the text
91 : : // *either* as an XTextRange or as an SwNodeIndex. The reason is that
92 : : // we must store either pointers to StartNodes (because redlines may
93 : : // start on start nodes) or to a text position, and there appears to
94 : : // be no existing type that could do both. Things are complicated by
95 : : // the matter that (e.g in section import) we delete a few characters,
96 : : // which may cause bookmarks (as used by XTextRange) to be deleted.
97 : : //
98 : :
99 : : class XTextRangeOrNodeIndexPosition
100 : : {
101 : : Reference<XTextRange> xRange;
102 : : SwNodeIndex* pIndex; /// pIndex will point to the *previous* node
103 : :
104 : : public:
105 : : XTextRangeOrNodeIndexPosition();
106 : : ~XTextRangeOrNodeIndexPosition();
107 : :
108 : : void Set( Reference<XTextRange> & rRange );
109 : : void Set( SwNodeIndex& rIndex );
110 : : void SetAsNodeIndex( Reference<XTextRange> & rRange );
111 : :
112 : : void CopyPositionInto(SwPosition& rPos, SwDoc & rDoc);
113 : : SwDoc* GetDoc();
114 : :
115 : : sal_Bool IsValid();
116 : : };
117 : :
118 : 0 : XTextRangeOrNodeIndexPosition::XTextRangeOrNodeIndexPosition() :
119 : : xRange(NULL),
120 : 0 : pIndex(NULL)
121 : : {
122 : 0 : }
123 : :
124 : 0 : XTextRangeOrNodeIndexPosition::~XTextRangeOrNodeIndexPosition()
125 : : {
126 [ # # ][ # # ]: 0 : delete pIndex;
127 : 0 : }
128 : :
129 : 0 : void XTextRangeOrNodeIndexPosition::Set( Reference<XTextRange> & rRange )
130 : : {
131 [ # # ]: 0 : xRange = rRange->getStart(); // set bookmark
132 [ # # ]: 0 : if (NULL != pIndex)
133 : : {
134 [ # # ]: 0 : delete pIndex;
135 : 0 : pIndex = NULL;
136 : : }
137 : 0 : }
138 : :
139 : 0 : void XTextRangeOrNodeIndexPosition::Set( SwNodeIndex& rIndex )
140 : : {
141 [ # # ]: 0 : if (NULL != pIndex)
142 [ # # ]: 0 : delete pIndex;
143 : :
144 [ # # ]: 0 : pIndex = new SwNodeIndex(rIndex);
145 : 0 : (*pIndex)-- ; // previous node!!!
146 : 0 : xRange = NULL;
147 : 0 : }
148 : :
149 : 0 : void XTextRangeOrNodeIndexPosition::SetAsNodeIndex(
150 : : Reference<XTextRange> & rRange )
151 : : {
152 : : // XTextRange -> XTunnel -> SwXTextRange
153 [ # # ]: 0 : SwDoc* pDoc = lcl_GetDocViaTunnel(rRange);
154 : :
155 [ # # ]: 0 : if (!pDoc)
156 : : {
157 : : OSL_TRACE("SetAsNodeIndex: no SwDoc");
158 : 0 : return;
159 : : }
160 : :
161 : : // SwXTextRange -> PaM
162 [ # # ]: 0 : SwUnoInternalPaM aPaM(*pDoc);
163 : : #if OSL_DEBUG_LEVEL > 0
164 : : sal_Bool bSuccess =
165 : : #endif
166 [ # # ]: 0 : ::sw::XTextRangeToSwPaM(aPaM, rRange);
167 : : OSL_ENSURE(bSuccess, "illegal range");
168 : :
169 : : // PaM -> Index
170 [ # # ][ # # ]: 0 : Set(aPaM.GetPoint()->nNode);
171 : : }
172 : :
173 : : void
174 : 0 : XTextRangeOrNodeIndexPosition::CopyPositionInto(SwPosition& rPos, SwDoc & rDoc)
175 : : {
176 : : OSL_ENSURE(IsValid(), "Can't get Position");
177 : :
178 : : // create PAM from start cursor (if no node index is present)
179 [ # # ]: 0 : if (NULL == pIndex)
180 : : {
181 [ # # ]: 0 : SwUnoInternalPaM aUnoPaM(rDoc);
182 : : #if OSL_DEBUG_LEVEL > 0
183 : : sal_Bool bSuccess =
184 : : #endif
185 [ # # ]: 0 : ::sw::XTextRangeToSwPaM(aUnoPaM, xRange);
186 : : OSL_ENSURE(bSuccess, "illegal range");
187 : :
188 [ # # ][ # # ]: 0 : rPos = *aUnoPaM.GetPoint();
189 : : }
190 : : else
191 : : {
192 : 0 : rPos.nNode = *pIndex;
193 : 0 : rPos.nNode++; // pIndex points to previous index !!!
194 [ # # ]: 0 : rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), 0 );
195 : : }
196 : 0 : }
197 : :
198 : 0 : SwDoc* XTextRangeOrNodeIndexPosition::GetDoc()
199 : : {
200 : : OSL_ENSURE(IsValid(), "Can't get Doc");
201 : :
202 [ # # ]: 0 : return (NULL != pIndex) ? pIndex->GetNodes().GetDoc() : lcl_GetDocViaTunnel(xRange);
203 : : }
204 : :
205 : 0 : sal_Bool XTextRangeOrNodeIndexPosition::IsValid()
206 : : {
207 [ # # ][ # # ]: 0 : return ( xRange.is() || (pIndex != NULL) );
208 : : }
209 : :
210 : :
211 : : //
212 : : // RedlineInfo: temporary storage for redline data
213 : : //
214 : :
215 : : class RedlineInfo
216 : : {
217 : : public:
218 : : RedlineInfo();
219 : : ~RedlineInfo();
220 : :
221 : : /// redline type (insert, delete, ...)
222 : : RedlineType_t eType;
223 : :
224 : : // info fields:
225 : : OUString sAuthor; /// change author string
226 : : OUString sComment; /// change comment string
227 : : util::DateTime aDateTime; /// change DateTime
228 : : sal_Bool bMergeLastParagraph; /// the SwRedline::IsDelLastPara flag
229 : :
230 : : // each position can may be either empty, an XTextRange, or an SwNodeIndex
231 : :
232 : : // start pos of anchor (may be empty)
233 : : XTextRangeOrNodeIndexPosition aAnchorStart;
234 : :
235 : : // end pos of anchor (may be empty)
236 : : XTextRangeOrNodeIndexPosition aAnchorEnd;
237 : :
238 : : /// index of content node (maybe NULL)
239 : : SwNodeIndex* pContentIndex;
240 : :
241 : : /// next redline info (for hierarchical redlines)
242 : : RedlineInfo* pNextRedline;
243 : :
244 : : /// store whether we expect an adjustment for this redline
245 : : sal_Bool bNeedsAdjustment;
246 : : };
247 : :
248 : 0 : RedlineInfo::RedlineInfo() :
249 : : eType(nsRedlineType_t::REDLINE_INSERT),
250 : : sAuthor(),
251 : : sComment(),
252 : : aDateTime(),
253 : : bMergeLastParagraph( sal_False ),
254 : : aAnchorStart(),
255 : : aAnchorEnd(),
256 : : pContentIndex(NULL),
257 : : pNextRedline(NULL),
258 [ # # ][ # # ]: 0 : bNeedsAdjustment( sal_False )
259 : : {
260 : 0 : }
261 : :
262 [ # # ][ # # ]: 0 : RedlineInfo::~RedlineInfo()
263 : : {
264 [ # # ][ # # ]: 0 : delete pContentIndex;
265 [ # # ][ # # ]: 0 : delete pNextRedline;
266 : 0 : }
267 : :
268 : :
269 : : //
270 : : // XMLRedlineImportHelper
271 : : //
272 : :
273 : 254 : XMLRedlineImportHelper::XMLRedlineImportHelper(
274 : : sal_Bool bNoRedlinesPlease,
275 : : const Reference<XPropertySet> & rModel,
276 : : const Reference<XPropertySet> & rImportInfo ) :
277 : : sEmpty(),
278 [ + - ]: 254 : sInsertion( GetXMLToken( XML_INSERTION )),
279 [ + - ]: 254 : sDeletion( GetXMLToken( XML_DELETION )),
280 [ + - ]: 254 : sFormatChange( GetXMLToken( XML_FORMAT_CHANGE )),
281 : : sShowChanges(RTL_CONSTASCII_USTRINGPARAM("ShowChanges")),
282 : : sRecordChanges(RTL_CONSTASCII_USTRINGPARAM("RecordChanges")),
283 : : sRedlineProtectionKey(RTL_CONSTASCII_USTRINGPARAM("RedlineProtectionKey")),
284 : : aRedlineMap(),
285 : : bIgnoreRedlines(bNoRedlinesPlease),
286 : : xModelPropertySet(rModel),
287 [ + - ][ + - ]: 1016 : xImportInfoPropertySet(rImportInfo)
[ + - ][ + - ]
[ + - ]
288 : : {
289 : : // check to see if redline mode is handled outside of component
290 : 254 : sal_Bool bHandleShowChanges = sal_True;
291 : 254 : sal_Bool bHandleRecordChanges = sal_True;
292 : 254 : sal_Bool bHandleProtectionKey = sal_True;
293 [ + + ]: 254 : if ( xImportInfoPropertySet.is() )
294 : : {
295 : : Reference<XPropertySetInfo> xInfo =
296 [ + - ][ + - ]: 252 : xImportInfoPropertySet->getPropertySetInfo();
297 : :
298 [ + - ][ + - ]: 252 : bHandleShowChanges = ! xInfo->hasPropertyByName( sShowChanges );
299 [ + - ][ + - ]: 252 : bHandleRecordChanges = ! xInfo->hasPropertyByName( sRecordChanges );
300 [ + - ][ + - ]: 252 : bHandleProtectionKey = ! xInfo->hasPropertyByName( sRedlineProtectionKey );
301 : : }
302 : :
303 : : // get redline mode
304 : : bShowChanges = *(sal_Bool*)
305 : : ( bHandleShowChanges ? xModelPropertySet : xImportInfoPropertySet )
306 [ + + ][ + - ]: 254 : ->getPropertyValue( sShowChanges ).getValue();
[ + - ]
307 : : bRecordChanges = *(sal_Bool*)
308 : : ( bHandleRecordChanges ? xModelPropertySet : xImportInfoPropertySet )
309 [ + - ][ + - ]: 254 : ->getPropertyValue( sRecordChanges ).getValue();
[ + + ]
310 : : {
311 : : Any aAny = (bHandleProtectionKey ? xModelPropertySet
312 : : : xImportInfoPropertySet )
313 [ + - ][ + - ]: 254 : ->getPropertyValue( sRedlineProtectionKey );
[ + + ]
314 [ + - ]: 254 : aAny >>= aProtectionKey;
315 : : }
316 : :
317 : : // set redline mode to "don't record changes"
318 [ + + ]: 254 : if( bHandleRecordChanges )
319 : : {
320 : 2 : Any aAny;
321 : 2 : sal_Bool bTmp = sal_False;
322 [ + - ]: 2 : aAny.setValue( &bTmp, ::getBooleanCppuType() );
323 [ + - ][ + - ]: 2 : xModelPropertySet->setPropertyValue( sRecordChanges, aAny );
324 : : }
325 : 254 : }
326 : :
327 [ + - ]: 254 : XMLRedlineImportHelper::~XMLRedlineImportHelper()
328 : : {
329 : : // delete all left over (and obviously incomplete) RedlineInfos (and map)
330 : 254 : RedlineMapType::iterator aFind = aRedlineMap.begin();
331 [ - + ]: 254 : for( ; aRedlineMap.end() != aFind; ++aFind )
332 : : {
333 : 0 : RedlineInfo* pInfo = aFind->second;
334 : :
335 : : // left-over redlines. Insert them if possible (but assert),
336 : : // and delete the incomplete ones. Finally, delete it.
337 [ # # ]: 0 : if( IsReady(pInfo) )
338 : : {
339 : : OSL_FAIL("forgotten RedlineInfo; now inserted");
340 [ # # ]: 0 : InsertIntoDocument( pInfo );
341 : : }
342 : : else
343 : : {
344 : : // try if only the adjustment was missing
345 : 0 : pInfo->bNeedsAdjustment = sal_False;
346 [ # # ]: 0 : if( IsReady(pInfo) )
347 : : {
348 : : OSL_FAIL("RedlineInfo without adjustment; now inserted");
349 [ # # ]: 0 : InsertIntoDocument( pInfo );
350 : : }
351 : : else
352 : : {
353 : : // this situation occurs if redlines aren't closed
354 : : // (i.e. end without start, or start without
355 : : // end). This may well be a problem in the file,
356 : : // rather than the code.
357 : : OSL_FAIL("incomplete redline (maybe file was corrupt); "
358 : : "now deleted");
359 : : }
360 : : }
361 [ # # ][ # # ]: 0 : delete pInfo;
362 : : }
363 : 254 : aRedlineMap.clear();
364 : :
365 : : // set redline mode, either to info property set, or directly to
366 : : // the document
367 : 254 : sal_Bool bHandleShowChanges = sal_True;
368 : 254 : sal_Bool bHandleRecordChanges = sal_True;
369 : 254 : sal_Bool bHandleProtectionKey = sal_True;
370 [ + + ]: 254 : if ( xImportInfoPropertySet.is() )
371 : : {
372 : : Reference<XPropertySetInfo> xInfo =
373 [ + - ][ + - ]: 252 : xImportInfoPropertySet->getPropertySetInfo();
374 : :
375 [ + - ][ + - ]: 252 : bHandleShowChanges = ! xInfo->hasPropertyByName( sShowChanges );
376 [ + - ][ + - ]: 252 : bHandleRecordChanges = ! xInfo->hasPropertyByName( sRecordChanges );
377 [ + - ][ + - ]: 252 : bHandleProtectionKey = ! xInfo->hasPropertyByName( sRedlineProtectionKey );
378 : : }
379 : :
380 : : // set redline mode & key
381 : 254 : Any aAny;
382 : :
383 [ + - ]: 254 : aAny.setValue( &bShowChanges, ::getBooleanCppuType() );
384 [ + + ]: 254 : if ( bHandleShowChanges )
385 [ + - ][ - + ]: 2 : xModelPropertySet->setPropertyValue( sShowChanges, aAny );
386 : : else
387 [ + - ][ + - ]: 252 : xImportInfoPropertySet->setPropertyValue( sShowChanges, aAny );
388 : :
389 [ + - ]: 252 : aAny.setValue( &bRecordChanges, ::getBooleanCppuType() );
390 [ - + ]: 252 : if ( bHandleRecordChanges )
391 [ # # ][ # # ]: 0 : xModelPropertySet->setPropertyValue( sRecordChanges, aAny );
392 : : else
393 [ + - ][ + - ]: 252 : xImportInfoPropertySet->setPropertyValue( sRecordChanges, aAny );
394 : :
395 [ + - ]: 252 : aAny <<= aProtectionKey;
396 [ - + ]: 252 : if ( bHandleProtectionKey )
397 [ # # ][ # # ]: 0 : xModelPropertySet->setPropertyValue( sRedlineProtectionKey, aAny );
398 : : else
399 [ + - ][ + - ]: 254 : xImportInfoPropertySet->setPropertyValue( sRedlineProtectionKey, aAny);
400 [ - + ]: 506 : }
401 : :
402 : 0 : void XMLRedlineImportHelper::Add(
403 : : const OUString& rType,
404 : : const OUString& rId,
405 : : const OUString& rAuthor,
406 : : const OUString& rComment,
407 : : const util::DateTime& rDateTime,
408 : : sal_Bool bMergeLastPara)
409 : : {
410 : : // we need to do the following:
411 : : // 1) parse type string
412 : : // 2) create RedlineInfo and fill it with data
413 : : // 3) check for existing redline with same ID
414 : : // 3a) insert redline into map
415 : : // 3b) attach to existing redline
416 : :
417 : : // ad 1)
418 : : RedlineType_t eType;
419 [ # # ]: 0 : if (rType.equals(sInsertion))
420 : : {
421 : 0 : eType = nsRedlineType_t::REDLINE_INSERT;
422 : : }
423 [ # # ]: 0 : else if (rType.equals(sDeletion))
424 : : {
425 : 0 : eType = nsRedlineType_t::REDLINE_DELETE;
426 : : }
427 [ # # ]: 0 : else if (rType.equals(sFormatChange))
428 : : {
429 : 0 : eType = nsRedlineType_t::REDLINE_FORMAT;
430 : : }
431 : : else
432 : : {
433 : : // no proper type found: early out!
434 : 0 : return;
435 : : }
436 : :
437 : : // ad 2) create a new RedlineInfo
438 [ # # ]: 0 : RedlineInfo* pInfo = new RedlineInfo();
439 : :
440 : : // fill entries
441 : 0 : pInfo->eType = eType;
442 : 0 : pInfo->sAuthor = rAuthor;
443 : 0 : pInfo->sComment = rComment;
444 : 0 : pInfo->aDateTime = rDateTime;
445 : 0 : pInfo->bMergeLastParagraph = bMergeLastPara;
446 : :
447 : :
448 : : // ad 3)
449 [ # # ]: 0 : if (aRedlineMap.end() == aRedlineMap.find(rId))
450 : : {
451 : : // 3a) insert into map
452 : 0 : aRedlineMap[rId] = pInfo;
453 : : }
454 : : else
455 : : {
456 : : // 3b) we already have a redline with this name: hierarchical redlines
457 : : // insert pInfo as last element in the chain.
458 : : // (hierarchy sanity checking happens on insertino into the document)
459 : :
460 : : // find last element
461 : : RedlineInfo* pInfoChain;
462 [ # # ]: 0 : for( pInfoChain = aRedlineMap[rId];
463 : : NULL != pInfoChain->pNextRedline;
464 : : pInfoChain = pInfoChain->pNextRedline) ; // empty loop
465 : :
466 : : // insert as last element
467 : 0 : pInfoChain->pNextRedline = pInfo;
468 : : }
469 : : }
470 : :
471 : 0 : Reference<XTextCursor> XMLRedlineImportHelper::CreateRedlineTextSection(
472 : : Reference<XTextCursor> xOldCursor,
473 : : const OUString& rId)
474 : : {
475 : 0 : Reference<XTextCursor> xReturn;
476 : :
477 : : // this method will modify the document directly -> lock SolarMutex
478 [ # # ]: 0 : SolarMutexGuard aGuard;
479 : :
480 : : // get RedlineInfo
481 [ # # ]: 0 : RedlineMapType::iterator aFind = aRedlineMap.find(rId);
482 [ # # ]: 0 : if (aRedlineMap.end() != aFind)
483 : : {
484 : : // get document from old cursor (via tunnel)
485 [ # # ]: 0 : SwDoc* pDoc = lcl_GetDocViaTunnel(xOldCursor);
486 : :
487 [ # # ]: 0 : if (!pDoc)
488 : : {
489 : : OSL_TRACE("XMLRedlineImportHelper::CreateRedlineTextSection: "
490 : : "no SwDoc => cannot create section.");
491 [ # # ]: 0 : return 0;
492 : : }
493 : :
494 : : // create text section for redline
495 : : SwTxtFmtColl *pColl = pDoc->GetTxtCollFromPool
496 [ # # ]: 0 : (RES_POOLCOLL_STANDARD, false );
497 [ # # ]: 0 : SwStartNode* pRedlineNode = pDoc->GetNodes().MakeTextSection(
498 [ # # ]: 0 : pDoc->GetNodes().GetEndOfRedlines(),
499 : : SwNormalStartNode,
500 [ # # ][ # # ]: 0 : pColl);
[ # # ]
501 : :
502 : : // remember node-index in RedlineInfo
503 [ # # ]: 0 : SwNodeIndex aIndex(*pRedlineNode);
504 [ # # ][ # # ]: 0 : aFind->second->pContentIndex = new SwNodeIndex(aIndex);
505 : :
506 : : // create XText for document
507 [ # # ][ # # ]: 0 : SwXText* pXText = new SwXRedlineText(pDoc, aIndex);
[ # # ]
508 [ # # ][ # # ]: 0 : Reference<XText> xText = pXText; // keep Reference until end of method
509 : :
510 : : // create (UNO-) cursor
511 [ # # ]: 0 : SwPosition aPos(*pRedlineNode);
512 : : SwXTextCursor *const pXCursor =
513 [ # # ][ # # ]: 0 : new SwXTextCursor(*pDoc, pXText, CURSOR_REDLINE, aPos);
[ # # ]
514 [ # # ][ # # ]: 0 : pXCursor->GetCursor()->Move(fnMoveForward, fnGoNode);
515 : : // cast to avoid ambiguity
516 [ # # ][ # # ]: 0 : xReturn = static_cast<text::XWordCursor*>(pXCursor);
[ # # ][ # # ]
517 : : }
518 : : // else: unknown redline -> Ignore
519 : :
520 [ # # ]: 0 : return xReturn;
521 : : }
522 : :
523 : 0 : void XMLRedlineImportHelper::SetCursor(
524 : : const OUString& rId,
525 : : sal_Bool bStart,
526 : : Reference<XTextRange> & rRange,
527 : : sal_Bool bIsOutsideOfParagraph)
528 : : {
529 [ # # ]: 0 : RedlineMapType::iterator aFind = aRedlineMap.find(rId);
530 [ # # ]: 0 : if (aRedlineMap.end() != aFind)
531 : : {
532 : : // RedlineInfo found; now set Cursor
533 : 0 : RedlineInfo* pInfo = aFind->second;
534 [ # # ]: 0 : if (bIsOutsideOfParagraph)
535 : : {
536 : : // outside of paragraph: remember SwNodeIndex
537 [ # # ]: 0 : if (bStart)
538 : : {
539 [ # # ]: 0 : pInfo->aAnchorStart.SetAsNodeIndex(rRange);
540 : : }
541 : : else
542 : : {
543 [ # # ]: 0 : pInfo->aAnchorEnd.SetAsNodeIndex(rRange);
544 : : }
545 : :
546 : : // also remember that we expect an adjustment for this redline
547 : 0 : pInfo->bNeedsAdjustment = sal_True;
548 : : }
549 : : else
550 : : {
551 : : // inside of a paragraph: use regular XTextRanges (bookmarks)
552 [ # # ]: 0 : if (bStart)
553 [ # # ]: 0 : pInfo->aAnchorStart.Set(rRange);
554 : : else
555 [ # # ]: 0 : pInfo->aAnchorEnd.Set(rRange);
556 : : }
557 : :
558 : : // if this Cursor was the last missing info, we insert the
559 : : // node into the document
560 : : // then we can remove the entry from the map and destroy the object
561 [ # # ]: 0 : if (IsReady(pInfo))
562 : : {
563 [ # # ]: 0 : InsertIntoDocument(pInfo);
564 [ # # ]: 0 : aRedlineMap.erase(rId);
565 [ # # ][ # # ]: 0 : delete pInfo;
566 : : }
567 : : }
568 : : // else: unknown Id -> ignore
569 : 0 : }
570 : :
571 : 0 : void XMLRedlineImportHelper::AdjustStartNodeCursor(
572 : : const OUString& rId, /// ID used in RedlineAdd() call
573 : : sal_Bool /*bStart*/,
574 : : Reference<XTextRange> & /*rRange*/)
575 : : {
576 : : // this method will modify the document directly -> lock SolarMutex
577 [ # # ]: 0 : SolarMutexGuard aGuard;
578 : :
579 : : // start + end nodes are treated the same. For either it's
580 : : // necessary that the target node already exists.
581 : :
582 [ # # ]: 0 : RedlineMapType::iterator aFind = aRedlineMap.find(rId);
583 [ # # ]: 0 : if (aRedlineMap.end() != aFind)
584 : : {
585 : : // RedlineInfo found; now set Cursor
586 : 0 : RedlineInfo* pInfo = aFind->second;
587 : :
588 : 0 : pInfo->bNeedsAdjustment = sal_False;
589 : :
590 : : // if now ready, insert into document
591 [ # # ]: 0 : if( IsReady(pInfo) )
592 : : {
593 [ # # ]: 0 : InsertIntoDocument(pInfo);
594 [ # # ]: 0 : aRedlineMap.erase(rId);
595 [ # # ][ # # ]: 0 : delete pInfo;
596 : : }
597 [ # # ]: 0 : }
598 : : // else: can't find redline -> ignore
599 : 0 : }
600 : :
601 : :
602 : 0 : inline sal_Bool XMLRedlineImportHelper::IsReady(RedlineInfo* pRedline)
603 : : {
604 : : // we can insert a redline if we have start & end, and we don't
605 : : // expect adjustments for either of these
606 : 0 : return ( pRedline->aAnchorEnd.IsValid() &&
607 : 0 : pRedline->aAnchorStart.IsValid() &&
608 [ # # ]: 0 : !pRedline->bNeedsAdjustment );
[ # # # # ]
609 : : }
610 : :
611 : 0 : void XMLRedlineImportHelper::InsertIntoDocument(RedlineInfo* pRedlineInfo)
612 : : {
613 : : OSL_ENSURE(NULL != pRedlineInfo, "need redline info");
614 : : OSL_ENSURE(IsReady(pRedlineInfo), "redline info not complete yet!");
615 : :
616 : : // this method will modify the document directly -> lock SolarMutex
617 [ # # ]: 0 : SolarMutexGuard aGuard;
618 : :
619 : : // Insert the Redline as described by pRedlineInfo into the
620 : : // document. If we are in insert mode, don't insert any redlines
621 : : // (and delete 'deleted' inline redlines)
622 : :
623 : : // get the document (from one of the positions)
624 [ # # ]: 0 : SwDoc* pDoc = pRedlineInfo->aAnchorStart.GetDoc();
625 : :
626 [ # # ]: 0 : if (!pDoc)
627 : : {
628 : : OSL_TRACE("XMLRedlineImportHelper::InsertIntoDocument: "
629 : : "no SwDoc => cannot insert redline.");
630 : 0 : return;
631 : : }
632 : :
633 : : // now create the PaM for the redline
634 [ # # ][ # # ]: 0 : SwPaM aPaM(pDoc->GetNodes().GetEndOfContent());
635 [ # # ]: 0 : pRedlineInfo->aAnchorStart.CopyPositionInto(*aPaM.GetPoint(), *pDoc);
636 [ # # ]: 0 : aPaM.SetMark();
637 [ # # ]: 0 : pRedlineInfo->aAnchorEnd.CopyPositionInto(*aPaM.GetPoint(), *pDoc);
638 : :
639 : : // collapse PaM if (start == end)
640 [ # # ][ # # ]: 0 : if (*aPaM.GetPoint() == *aPaM.GetMark())
641 : : {
642 [ # # ]: 0 : aPaM.DeleteMark();
643 : : }
644 : :
645 : :
646 : : // cover three cases:
647 : : // 1) empty redlines (no range, no content)
648 : : // 2) check for:
649 : : // a) bIgnoreRedline (e.g. insert mode)
650 : : // b) illegal PaM range (CheckNodesRange())
651 : : // 3) normal case: insert redline
652 [ # # ][ # # ]: 0 : if( !aPaM.HasMark() && (pRedlineInfo->pContentIndex == NULL) )
[ # # ]
653 : : {
654 : : // these redlines have no function, and will thus be ignored (just as
655 : : // in sw3io), so no action here
656 : : }
657 [ # # ][ # # ]: 0 : else if ( bIgnoreRedlines ||
[ # # ]
658 : 0 : !CheckNodesRange( aPaM.GetPoint()->nNode,
659 : 0 : aPaM.GetMark()->nNode,
660 [ # # ]: 0 : sal_True ) )
661 : : {
662 : : // ignore redline (e.g. file loaded in insert mode):
663 : : // delete 'deleted' redlines and forget about the whole thing
664 [ # # ]: 0 : if (nsRedlineType_t::REDLINE_DELETE == pRedlineInfo->eType)
665 : : {
666 [ # # ]: 0 : pDoc->DeleteRange(aPaM);
667 : : // And what about the "deleted nodes"?
668 : : // They have to be deleted as well (#i80689)!
669 [ # # ][ # # ]: 0 : if( bIgnoreRedlines && pRedlineInfo->pContentIndex != NULL )
670 : : {
671 [ # # ]: 0 : SwNodeIndex aIdx( *pRedlineInfo->pContentIndex );
672 : 0 : const SwNode* pEnd = aIdx.GetNode().EndOfSectionNode();
673 [ # # ]: 0 : if( pEnd )
674 : : {
675 [ # # ]: 0 : SwNodeIndex aEnd( *pEnd, 1 );
676 [ # # ]: 0 : SwPaM aDel( aIdx, aEnd );
677 [ # # ][ # # ]: 0 : pDoc->DeleteRange(aDel);
[ # # ]
678 [ # # ]: 0 : }
679 : : }
680 : : }
681 : : }
682 : : else
683 : : {
684 : : // regular file loading: insert redline
685 : :
686 : : // create redline (using pRedlineData which gets copied in SwRedline())
687 [ # # ]: 0 : SwRedlineData* pRedlineData = ConvertRedline(pRedlineInfo, pDoc);
688 : : SwRedline* pRedline =
689 : : new SwRedline( pRedlineData, *aPaM.GetPoint(), sal_True,
690 [ # # ][ # # ]: 0 : !pRedlineInfo->bMergeLastParagraph, sal_False );
691 : :
692 : : // set mark
693 [ # # ]: 0 : if( aPaM.HasMark() )
694 : : {
695 [ # # ]: 0 : pRedline->SetMark();
696 [ # # ]: 0 : *(pRedline->GetMark()) = *aPaM.GetMark();
697 : : }
698 : :
699 : : // set content node (if necessary)
700 [ # # ]: 0 : if (NULL != pRedlineInfo->pContentIndex)
701 : : {
702 : 0 : sal_uLong nPoint = aPaM.GetPoint()->nNode.GetIndex();
703 [ # # ]: 0 : if( nPoint < pRedlineInfo->pContentIndex->GetIndex() ||
[ # # # # ]
704 : 0 : nPoint > pRedlineInfo->pContentIndex->GetNode().EndOfSectionIndex() )
705 [ # # ]: 0 : pRedline->SetContentIdx(pRedlineInfo->pContentIndex);
706 : : #if OSL_DEBUG_LEVEL > 1
707 : : else
708 : : OSL_FAIL( "Recursive change tracking" );
709 : : #endif
710 : : }
711 : :
712 : : // set redline mode (without doing the associated book-keeping)
713 [ # # ]: 0 : pDoc->SetRedlineMode_intern(nsRedlineMode_t::REDLINE_ON);
714 [ # # ]: 0 : pDoc->AppendRedline(pRedline, false);
715 [ # # ]: 0 : pDoc->SetRedlineMode_intern(nsRedlineMode_t::REDLINE_NONE);
716 [ # # ][ # # ]: 0 : }
[ # # ]
717 : : }
718 : :
719 : 0 : SwRedlineData* XMLRedlineImportHelper::ConvertRedline(
720 : : RedlineInfo* pRedlineInfo,
721 : : SwDoc* pDoc)
722 : : {
723 : : // convert info:
724 : : // 1) Author String -> Author ID (default to zero)
725 : : sal_uInt16 nAuthorId = (NULL == pDoc) ? 0 :
726 [ # # ][ # # ]: 0 : pDoc->InsertRedlineAuthor( pRedlineInfo->sAuthor );
[ # # ][ # # ]
[ # # ][ # # ]
727 : :
728 : : // 2) util::DateTime -> DateTime
729 : 0 : DateTime aDT( DateTime::EMPTY );
730 [ # # ]: 0 : aDT.SetYear( pRedlineInfo->aDateTime.Year );
731 [ # # ]: 0 : aDT.SetMonth( pRedlineInfo->aDateTime.Month );
732 [ # # ]: 0 : aDT.SetDay( pRedlineInfo->aDateTime.Day );
733 [ # # ]: 0 : aDT.SetHour( pRedlineInfo->aDateTime.Hours );
734 [ # # ]: 0 : aDT.SetMin( pRedlineInfo->aDateTime.Minutes );
735 [ # # ]: 0 : aDT.SetSec( pRedlineInfo->aDateTime.Seconds );
736 [ # # ]: 0 : aDT.Set100Sec( pRedlineInfo->aDateTime.HundredthSeconds );
737 : :
738 : : // 3) recursively convert next redline
739 : : // ( check presence and sanity of hierarchical redline info )
740 : 0 : SwRedlineData* pNext = NULL;
741 [ # # ][ # # ]: 0 : if ( (NULL != pRedlineInfo->pNextRedline) &&
[ # # ]
742 : : (nsRedlineType_t::REDLINE_DELETE == pRedlineInfo->eType) &&
743 : : (nsRedlineType_t::REDLINE_INSERT == pRedlineInfo->pNextRedline->eType) )
744 : : {
745 [ # # ]: 0 : pNext = ConvertRedline(pRedlineInfo->pNextRedline, pDoc);
746 : : }
747 : :
748 : : // create redline data
749 : : SwRedlineData* pData = new SwRedlineData(pRedlineInfo->eType,
750 : : nAuthorId, aDT,
751 : : pRedlineInfo->sComment,
752 : : pNext, // next data (if available)
753 [ # # ][ # # ]: 0 : NULL); // no extra data
[ # # ][ # # ]
754 : :
755 : 0 : return pData;
756 : : }
757 : :
758 : :
759 : 63 : void XMLRedlineImportHelper::SetShowChanges( sal_Bool bShow )
760 : : {
761 : 63 : bShowChanges = bShow;
762 : 63 : }
763 : :
764 : 0 : void XMLRedlineImportHelper::SetRecordChanges( sal_Bool bRecord )
765 : : {
766 : 0 : bRecordChanges = bRecord;
767 : 0 : }
768 : :
769 : 63 : void XMLRedlineImportHelper::SetProtectionKey(
770 : : const Sequence<sal_Int8> & rKey )
771 : : {
772 : 63 : aProtectionKey = rKey;
773 : 63 : }
774 : :
775 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|