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