1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2
3 /* AbiSource Application Framework
4 * Copyright (C) 1998,1999 AbiSource, Inc.
5 * Copyright (C) 2004 Tomas Frydrych <tomasfrydrych@yahoo.co.uk>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301 USA.
21 */
22
23 #include <stdlib.h>
24 #include <cstring>
25 #include "ut_assert.h"
26 #include "ut_debugmsg.h"
27 #include "ut_string.h"
28 #include "ut_hash.h"
29 #include "ut_vector.h"
30 #include "ut_uuid.h"
31 #include "ut_misc.h"
32 #include "ut_path.h"
33 #include "xap_DialogFactory.h"
34
35 #include "xad_Document.h"
36 #include "xav_View.h"
37 #include "xap_App.h"
38 #include "xap_Strings.h"
39 #include "xap_Dlg_History.h"
40 #include "xap_Dlg_MessageBox.h"
41 #include "xap_Frame.h"
42 #include "xap_Strings.h"
43 #include "xap_Dialog_Id.h"
44
45 #ifdef ENABLE_RESOURCE_MANAGER
46 #include "xap_ResourceManager.h"
47 #endif
48
AD_Document()49 AD_Document::AD_Document() :
50 #ifdef ENABLE_RESOURCE_MANAGER
51 m_pResourceManager(new XAP_ResourceManager),
52 #else
53 m_pResourceManager(0),
54 #endif
55 m_iRefCount(1),
56 m_szFilename(NULL),
57 m_szEncodingName(""), // Should this have a default? UTF-8, perhaps?
58 m_bPieceTableChanging(false),
59 m_lastSavedTime(0),
60 m_lastOpenedTime(time(NULL)),
61 m_iEditTime(0),
62 m_iVersion(0),
63 m_bHistoryWasSaved(false),
64 m_bMarkRevisions(false),
65 m_bShowRevisions(true),
66 m_iRevisionID(1),
67 m_iShowRevisionID(0), // show all
68 m_bAutoRevisioning(false),
69 m_bForcedDirty(false),
70 m_pUUID(NULL),
71 m_pOrigUUID(NULL),
72 m_pMyUUID(NULL),
73 m_bDoNotAdjustHistory(false),
74 m_bAfterFirstSave(false)
75 { // TODO: clear the ignore list
76
77
78 // create UUID for this doc
79 UT_return_if_fail(XAP_App::getApp() && XAP_App::getApp()->getUUIDGenerator());
80
81 m_pUUID = XAP_App::getApp()->getUUIDGenerator()->createUUID();
82 UT_return_if_fail(m_pUUID);
83 UT_return_if_fail(m_pUUID->isValid());
84 //
85 // Make a copy with the same value so we know when we're importing
86 // a remote CR
87 //
88 m_pMyUUID = XAP_App::getApp()->getUUIDGenerator()->createUUID();
89 UT_return_if_fail(m_pMyUUID);
90 UT_return_if_fail(m_pMyUUID->isValid());
91
92 m_pOrigUUID = XAP_App::getApp()->getUUIDGenerator()->createUUID();
93 UT_return_if_fail(m_pOrigUUID);
94 UT_return_if_fail(m_pOrigUUID->isValid());
95 UT_UTF8String s;
96 m_pUUID->toString(s);
97 m_pOrigUUID->setUUID(s);
98 m_pMyUUID->setUUID(s);
99 UT_UTF8String OrigS;
100 m_pOrigUUID->toString(OrigS);
101 m_pOrigUUID->toString(m_sOrigUUIDString);
102 m_pMyUUID->toString(m_sMyUUIDString);
103 UT_DEBUGMSG(("!!!!!!!!!!----------------- Created string %s \n",s.utf8_str()));
104 UT_DEBUGMSG(("!!!!!!!!!!----------------- Orig string %s \n",OrigS.utf8_str()));
105 }
106
~AD_Document()107 AD_Document::~AD_Document()
108 {
109 UT_ASSERT(m_iRefCount == 0);
110
111 // NOTE: let subclass clean up m_szFilename, so it matches the alloc mechanism
112
113 // & finally...
114 #ifdef ENABLE_RESOURCE_MANAGER
115 DELETEP(m_pResourceManager);
116 #endif
117
118 UT_VECTOR_PURGEALL(AD_VersionData*, m_vHistory);
119 UT_VECTOR_PURGEALL(AD_Revision*, m_vRevisions);
120
121 if (m_szFilename)
122 g_free(const_cast<void *>(static_cast<const void *>(m_szFilename)));
123
124 DELETEP(m_pUUID);
125 DELETEP(m_pOrigUUID);
126 DELETEP(m_pMyUUID);
127 }
128
getPrintFilename(void) const129 const std::string & AD_Document::getPrintFilename(void) const
130 {
131 return m_sPrintFilename;
132 }
133
setPrintFilename(const std::string & sFilename)134 void AD_Document::setPrintFilename(const std::string & sFilename)
135 {
136 m_sPrintFilename = sFilename;
137 }
138
isOrigUUID(void) const139 bool AD_Document::isOrigUUID(void) const
140 {
141 UT_UTF8String sDoc;
142 UT_UTF8String sOrig;
143 if((m_pMyUUID== NULL) || (m_pOrigUUID == NULL))
144 return false;
145 m_pMyUUID->toString(sDoc);
146 m_pOrigUUID->toString(sOrig);
147 bool b = (strcmp(sDoc.utf8_str(),sOrig.utf8_str()) == 0);
148 return b;
149 }
150
isPieceTableChanging(void) const151 bool AD_Document::isPieceTableChanging(void) const
152 {
153 return m_bPieceTableChanging;
154 }
155
156 /*!
157 Creates a new UUID; this uuid has the 'MAC' portion set to the
158 same value as the main doc uuid -- this guarantees that all id's
159 generated this way will be document unique even though withou
160 using MAC in the uuid we cannot absolutely guarantee universal
161 uniqueness.
162 */
getNewUUID() const163 UT_UUID * AD_Document::getNewUUID()const
164 {
165 // when new uuid is requested, we will generate it reusing the MAC
166 // part of the doc uuid. This will ensure that all uuid's in the
167 // present document are unique even though we no longer use MAC
168 // addrress in them
169 UT_return_val_if_fail(XAP_App::getApp() && XAP_App::getApp()->getUUIDGenerator(), NULL);
170 UT_return_val_if_fail(m_pUUID, NULL);
171 UT_UUID * pUUID = XAP_App::getApp()->getUUIDGenerator()->createUUID(*m_pUUID);
172
173 UT_return_val_if_fail(pUUID, NULL);
174 pUUID->resetTime();
175 UT_ASSERT(pUUID->isValid());
176 return pUUID;
177 }
178
179 /*!
180 see notes on getNewUUID()
181 */
getNewUUID32() const182 UT_uint32 AD_Document::getNewUUID32() const
183 {
184 #if 0
185 UT_return_val_if_fail(XAP_App::getApp() && XAP_App::getApp()->getUUIDGenerator(),0);
186 return XAP_App::getApp()->getUUIDGenerator()->getNewUUID32();
187 #else
188 UT_UUID *pUUID = getNewUUID();
189 UT_return_val_if_fail(pUUID, 0);
190 UT_uint32 iRet = pUUID->hash32();
191 delete pUUID;
192 return iRet;
193 #endif
194 }
195
196 /*!
197 see notes on getNewUUID()
198 */
getNewUUID64() const199 UT_uint64 AD_Document::getNewUUID64() const
200 {
201 #if 0
202 UT_return_val_if_fail(XAP_App::getApp() && XAP_App::getApp()->getUUIDGenerator(),0);
203 return XAP_App::getApp()->getUUIDGenerator()->getNewUUID64();
204 #else
205 UT_UUID *pUUID = getNewUUID();
206 UT_return_val_if_fail(pUUID, 0);
207 UT_uint32 iRet = pUUID->hash32();
208 delete pUUID;
209 return iRet;
210 #endif
211 }
212
213
ref(void)214 void AD_Document::ref(void)
215 {
216 UT_ASSERT(m_iRefCount > 0);
217
218 m_iRefCount++;
219 }
220
221
unref(void)222 void AD_Document::unref(void)
223 {
224 UT_ASSERT(m_iRefCount > 0);
225
226 if (--m_iRefCount == 0)
227 {
228 delete this;
229 }
230 }
231
getFilename(void) const232 const char * AD_Document::getFilename(void) const
233 {
234 return m_szFilename;
235 }
236
237 // Document-wide Encoding name used for some file formats (Text, RTF, HTML)
238
setEncodingName(const char * szEncodingName)239 void AD_Document::setEncodingName(const char *szEncodingName)
240 {
241 if (szEncodingName == NULL)
242 szEncodingName = "";
243
244 m_szEncodingName = szEncodingName;
245 }
246
getEncodingName(void) const247 const char * AD_Document::getEncodingName(void) const
248 {
249 return m_szEncodingName.size() ? m_szEncodingName.c_str() : 0;
250 }
251
purgeHistory()252 void AD_Document::purgeHistory()
253 {
254 UT_VECTOR_PURGEALL(AD_VersionData*, m_vHistory);
255 m_bHistoryWasSaved = false;
256 }
257
258
259 /*!
260 Add given version data to the document history.
261 */
addRecordToHistory(const AD_VersionData & vd)262 void AD_Document::addRecordToHistory(const AD_VersionData &vd)
263 {
264 AD_VersionData * v = new AD_VersionData(vd);
265 UT_return_if_fail(v);
266 m_vHistory.addItem((void*)v);
267 }
268
269 /*!
270 Get the version number for n-th record in version history
271 */
getHistoryNthId(UT_sint32 i) const272 UT_uint32 AD_Document::getHistoryNthId(UT_sint32 i)const
273 {
274 if(!m_vHistory.getItemCount())
275 return 0;
276
277 AD_VersionData * v = (AD_VersionData*)m_vHistory.getNthItem(i);
278
279 if(!v)
280 return 0;
281
282 return v->getId();
283 }
284
getHistoryNthTopXID(UT_sint32 i) const285 UT_uint32 AD_Document::getHistoryNthTopXID(UT_sint32 i)const
286 {
287 if(!m_vHistory.getItemCount())
288 return 0;
289
290 AD_VersionData * v = (AD_VersionData*)m_vHistory.getNthItem(i);
291
292 if(!v)
293 return 0;
294
295 return v->getTopXID();
296 }
297
298 /*!
299 Get time stamp for n-th record in version history
300 NB: the time stamp represents the last save time
301 */
getHistoryNthTime(UT_sint32 i) const302 time_t AD_Document::getHistoryNthTime(UT_sint32 i)const
303 {
304 if(!m_vHistory.getItemCount())
305 return 0;
306
307 AD_VersionData * v = (AD_VersionData*)m_vHistory.getNthItem(i);
308
309 if(!v)
310 return 0;
311
312 return v->getTime();
313 }
314
getHistoryNthTimeStarted(UT_sint32 i) const315 time_t AD_Document::getHistoryNthTimeStarted(UT_sint32 i)const
316 {
317 if(!m_vHistory.getItemCount())
318 return 0;
319
320 AD_VersionData * v = (AD_VersionData*)m_vHistory.getNthItem(i);
321
322 if(!v)
323 return 0;
324
325 return v->getStartTime();
326 }
327
getHistoryNthAutoRevisioned(UT_sint32 i) const328 bool AD_Document::getHistoryNthAutoRevisioned(UT_sint32 i)const
329 {
330 if(!m_vHistory.getItemCount())
331 return 0;
332
333 AD_VersionData * v = (AD_VersionData*)m_vHistory.getNthItem(i);
334
335 if(!v)
336 return false;
337
338 return v->isAutoRevisioned();
339 }
340
341
342 /*!
343 Get get cumulative edit time for n-th record in version history
344 */
getHistoryNthEditTime(UT_sint32 i) const345 time_t AD_Document::getHistoryNthEditTime(UT_sint32 i)const
346 {
347 if(!m_vHistory.getItemCount() || !m_pUUID)
348 return 0;
349
350 AD_VersionData * v = (AD_VersionData*)m_vHistory.getNthItem(i);
351
352 if(!v)
353 return 0;
354
355 time_t t0 = v->getStartTime();
356 time_t t1 = v->getTime();
357
358 UT_ASSERT( t1 >= t0 );
359 return t1-t0;
360 }
361
362 /*!
363 Get the UID for n-th record in version history
364 */
getHistoryNthUID(UT_sint32 i) const365 const UT_UUID & AD_Document::getHistoryNthUID(UT_sint32 i) const
366 {
367 if(!m_vHistory.getItemCount())
368 return UT_UUID::getNull();
369
370 AD_VersionData * v = (AD_VersionData*)m_vHistory.getNthItem(i);
371
372 if(!v)
373 return UT_UUID::getNull();
374
375 return v->getUID();
376 }
377
378
379 /*!
380 Returns true if both documents are based on the same root document
381 */
areDocumentsRelated(const AD_Document & d) const382 bool AD_Document::areDocumentsRelated(const AD_Document & d) const
383 {
384 if((!m_pUUID && d.getDocUUID()) || (m_pUUID && !d.getDocUUID()))
385 return false;
386
387 return (*m_pUUID == *(d.getDocUUID()));
388 }
389
390 /*!
391 Returns true if both documents are based on the same root document
392 and all version records have identical UID's
393 on return, the last identical version id is found in iVersion
394 */
areDocumentHistoriesEqual(const AD_Document & d,UT_uint32 & iVersion) const395 bool AD_Document::areDocumentHistoriesEqual(const AD_Document & d, UT_uint32 &iVersion) const
396 {
397 iVersion = 0;
398
399 if((!m_pUUID && d.getDocUUID()) || (m_pUUID && !d.getDocUUID()))
400 return false;
401
402 if(!(*m_pUUID == *(d.getDocUUID())))
403 return false;
404
405 UT_uint32 iCount = UT_MIN(getHistoryCount(), d.getHistoryCount());
406 UT_uint32 iMaxCount = UT_MAX(getHistoryCount(), d.getHistoryCount());
407
408 for(UT_uint32 i = 0; i < iCount; ++i)
409 {
410 AD_VersionData * v1 = (AD_VersionData*)m_vHistory.getNthItem(i);
411 AD_VersionData * v2 = (AD_VersionData*)d.m_vHistory.getNthItem(i);
412
413 if(!(*v1 == *v2))
414 return false;
415
416 iVersion = v1->getId();
417 }
418
419 if(iMaxCount != iCount)
420 return false;
421
422 return true;
423 }
424
425 /*!
426 Verifies to what extent we are able to restore given version of
427 the document
428
429 \return: return value indicates whether full/partial/no restore is possible
430
431 \param UT_uint32 & iVersion: on entry contains the version number
432 user wants to revert to; if return
433 value indicates partial restore
434 iVersion indicates which nearest
435 (greater) version can be restored
436 fully, or 0 if no such version exists
437 */
verifyHistoryState(UT_uint32 & iVersion) const438 AD_HISTORY_STATE AD_Document::verifyHistoryState(UT_uint32 &iVersion) const
439 {
440 if(!m_vHistory.getItemCount())
441 return ADHIST_NO_RESTORE;
442
443 AD_HISTORY_STATE eRet = ADHIST_FULL_RESTORE; // be optimistic
444
445 const AD_VersionData * v = NULL;
446 UT_sint32 i;
447 bool bFullRestore = false;
448 bool bFound = false;
449
450 // find the lowest autorevisioned record greater than iVersion and
451 // evaluate the state of history above iVersion
452 for(i = 0; i < getHistoryCount(); ++i)
453 {
454 v = (const AD_VersionData*)m_vHistory.getNthItem(i);
455
456 if(!v)
457 {
458 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
459 continue;
460 }
461
462 if(v->getId() < iVersion + 1)
463 continue;
464
465 if(!v->isAutoRevisioned())
466 continue;
467
468 // if we got so far, we have an autorevisioned record greater
469 // than iVersion
470
471 if(!bFound)
472 {
473 bFound = true;
474
475 if(v->getId() == iVersion + 1)
476 bFullRestore = true;
477
478 continue;
479 }
480
481 bFullRestore &= v->isAutoRevisioned();
482 }
483
484 if(!bFound)
485 {
486 // there are no autorevisioned records above our version
487 return ADHIST_NO_RESTORE;
488 }
489
490 if(!bFullRestore)
491 {
492 eRet = ADHIST_PARTIAL_RESTORE;
493
494 // we want to find out from which version would full restore
495 // be possible
496 UT_uint32 iMinVersion = 0; // assume nothing
497 for(i = getHistoryCount(); i > 0; --i)
498 {
499 v = (const AD_VersionData*)m_vHistory.getNthItem(i-1);
500
501 if(!v)
502 {
503 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
504 continue;
505 }
506
507 if(v->getId() <= iVersion) // too far down the table
508 break;
509
510 if(!v->isAutoRevisioned()) // break in the history
511 break;
512
513 iMinVersion = v->getId();
514 }
515
516 // iMinVersion now contains the lowest version with a full
517 // record above it, which we pass back to the caller
518 iVersion = iMinVersion;
519 }
520
521 return eRet;
522 }
523
findHistoryRecord(UT_uint32 iVersion) const524 const AD_VersionData * AD_Document::findHistoryRecord(UT_uint32 iVersion) const
525 {
526 for(UT_sint32 i = 0; i < getHistoryCount(); ++i)
527 {
528 const AD_VersionData * v = (const AD_VersionData*)m_vHistory.getNthItem(i);
529
530 if(v->getId() == iVersion)
531 return v;
532 }
533
534 return NULL;
535 }
536
537
538 /*!
539 Set UID for the present document
540 */
setDocUUID(const char * s)541 void AD_Document::setDocUUID(const char * s)
542 {
543 if(!m_pUUID)
544 {
545 UT_return_if_fail(0);
546 }
547
548 if(!m_pUUID->setUUID(s))
549 {
550 // string we were passed did not contain valid uuid
551 // if our original id was valid, we will keep it, otherwise
552 // make a new one
553 if(!m_pUUID->isValid())
554 m_pUUID->makeUUID();
555 }
556 }
557
558 /*!
559 Set Orig UID for the present document
560 */
setOrigUUID(const char * s)561 void AD_Document::setOrigUUID(const char * s)
562 {
563 if(!m_pOrigUUID)
564 {
565 UT_return_if_fail(0);
566 }
567
568 if(!m_pOrigUUID->setUUID(s))
569 {
570 // string we were passed did not contain valid uuid
571 // if our original id was valid, we will keep it, otherwise
572 // make a new one
573 if(!m_pOrigUUID->isValid())
574 m_pOrigUUID->makeUUID();
575 }
576 m_pOrigUUID->toString(m_sOrigUUIDString);
577 }
578
579
580 /*!
581 Set Orig UID for the present document
582 */
setMyUUID(const char * s)583 void AD_Document::setMyUUID(const char * s)
584 {
585 if(!m_pMyUUID)
586 {
587 UT_return_if_fail(0);
588 }
589
590 if(!m_pMyUUID->setUUID(s))
591 {
592 // string we were passed did not contain valid uuid
593 // if our original id was valid, we will keep it, otherwise
594 // make a new one
595 if(!m_pMyUUID->isValid())
596 m_pMyUUID->makeUUID();
597 }
598 m_pMyUUID->toString(m_sMyUUIDString);
599 }
600
601 /*!
602 Get the UID of this document represented as a string (this
603 function is primarily for exporters)
604 */
getDocUUIDString() const605 const char * AD_Document::getDocUUIDString() const
606 {
607 UT_return_val_if_fail(m_pUUID, NULL);
608 static UT_UTF8String s;
609 m_pUUID->toString(s);
610 return s.utf8_str();
611 }
612
613
614 /*!
615 Get the Original UID of this document represented as a string (this
616 function is primarily for exporters)
617 */
getOrigDocUUIDString() const618 const char * AD_Document::getOrigDocUUIDString() const
619 {
620 UT_return_val_if_fail(m_pOrigUUID, NULL);
621 return m_sOrigUUIDString.utf8_str();
622 }
623
624
625 /*!
626 Get the UID of the users of this document represented as a string (this
627 function is primarily for exporters)
628
629 NOTE: don't make this a static variable, as this value might change over
630 the life of the document
631 */
getMyUUIDString() const632 UT_UTF8String AD_Document::getMyUUIDString() const
633 {
634 UT_return_val_if_fail(m_pMyUUID, "");
635 return m_sMyUUIDString;
636 }
637
638 ///////////////////////////////////////////////////////////////////
639 ///////////////////////////////////////////////////////////////////
640
641 /*!
642 find revision with id iId and return its index in revision table
643 \param iId -- id of revision we are interested in
644 \return -- if found index into revision vector if not found < 0
645 */
getRevisionIndxFromId(UT_uint32 iId) const646 UT_sint32 AD_Document::getRevisionIndxFromId(UT_uint32 iId) const
647 {
648 for(UT_sint32 i = 0; i < m_vRevisions.getItemCount(); i++)
649 {
650 if(m_vRevisions.getNthItem(i)->getId() == iId)
651 return i;
652 }
653
654 return -1;
655 }
656
657 /**
658 * Should we pay attention to change tracking?
659 */
usingChangeTracking() const660 bool AD_Document::usingChangeTracking() const
661 {
662 bool ret = false;
663
664 ret |= isMarkRevisions();
665 ret |= ( getHighestRevisionId() > 1 );
666
667 return ret;
668 }
669
670
671
getHighestRevisionId() const672 UT_uint32 AD_Document::getHighestRevisionId() const
673 {
674 UT_uint32 iId = 0;
675
676 for(UT_sint32 i = 0; i < m_vRevisions.getItemCount(); i++)
677 {
678 iId = UT_MAX(iId, m_vRevisions.getNthItem(i)->getId());
679 }
680
681 return iId;
682 }
683
getHighestRevision() const684 const AD_Revision * AD_Document::getHighestRevision() const
685 {
686 UT_uint32 iId = 0;
687 const AD_Revision * r = NULL;
688
689 for(UT_sint32 i = 0; i < m_vRevisions.getItemCount(); i++)
690 {
691 const AD_Revision * t = m_vRevisions.getNthItem(i);
692 UT_uint32 t_id = t->getId();
693
694 if(t_id > iId)
695 {
696 iId = t_id;
697 r = t;
698 }
699 }
700
701 return r;
702 }
703
addRevision(UT_uint32 iId,UT_UCS4Char * pDesc,time_t tStart,UT_uint32 iVer,bool bGenCR)704 bool AD_Document::addRevision(UT_uint32 iId, UT_UCS4Char * pDesc, time_t tStart, UT_uint32 iVer, bool bGenCR)
705 {
706 for(UT_sint32 i = 0; i < m_vRevisions.getItemCount(); i++)
707 {
708 const AD_Revision * r = m_vRevisions.getNthItem(i);
709 if(r->getId() == iId)
710 return false;
711 }
712
713 AD_Revision * pRev = new AD_Revision(iId, pDesc, tStart, iVer);
714 addRevision(pRev, bGenCR);
715 m_iRevisionID = iId;
716 return true;
717 }
718
addRevision(UT_uint32 iId,const UT_UCS4Char * pDesc,UT_uint32 iLen,time_t tStart,UT_uint32 iVer,bool bGenCR)719 bool AD_Document::addRevision(UT_uint32 iId,
720 const UT_UCS4Char * pDesc, UT_uint32 iLen,
721 time_t tStart, UT_uint32 iVer,bool bGenCR)
722 {
723 for(UT_sint32 i = 0; i < m_vRevisions.getItemCount(); i++)
724 {
725 const AD_Revision * r = m_vRevisions.getNthItem(i);
726 if(r->getId() == iId)
727 return false;
728 }
729
730 UT_UCS4Char * pD = NULL;
731
732 if(pDesc)
733 {
734 pD = new UT_UCS4Char [iLen + 1];
735 UT_UCS4_strncpy(pD,pDesc,iLen);
736 pD[iLen] = 0;
737 }
738
739 AD_Revision * pRev = new AD_Revision(iId, pD, tStart, iVer);
740 addRevision(pRev,bGenCR);
741 m_iRevisionID = iId;
742 return true;
743 }
744
addRevision(AD_Revision * pRev,bool bGenCR)745 bool AD_Document::addRevision(AD_Revision * pRev, bool bGenCR)
746 {
747 m_vRevisions.addItem(pRev);
748 if(bGenCR)
749 {
750 const gchar * szAtts[11]={"docprop","revision",
751 "revision",NULL,
752 "revision-desc",NULL,
753 "revision-time",NULL,
754 "revision-ver",NULL,NULL};
755 UT_UTF8String sID,sTime,sVer;
756 UT_UTF8String_sprintf(sID,"%d",pRev->getId());
757 UT_UTF8String_sprintf(sTime,"%d",pRev->getStartTime());
758 UT_UTF8String_sprintf(sVer,"%d",pRev->getVersion());
759 UT_UTF8String sDesc(pRev->getDescription());
760 szAtts[3]= sID.utf8_str();
761 szAtts[5] = sDesc.utf8_str();
762 szAtts[7] = sTime.utf8_str();
763 szAtts[9] = sVer.utf8_str();
764 createAndSendDocPropCR(szAtts,NULL);
765 }
766 forceDirty();
767 return true;
768 }
769
_purgeRevisionTable()770 void AD_Document::_purgeRevisionTable()
771 {
772 UT_VECTOR_PURGEALL(AD_Revision*, m_vRevisions);
773 m_vRevisions.clear();
774 }
775
setMarkRevisions(bool bMark)776 void AD_Document::setMarkRevisions(bool bMark)
777 {
778 if(m_bMarkRevisions != bMark)
779 {
780 m_bMarkRevisions = bMark;
781 forceDirty();
782 }
783 }
784
toggleMarkRevisions()785 void AD_Document::toggleMarkRevisions()
786 {
787 setMarkRevisions(!m_bMarkRevisions);
788 }
789
setShowRevisions(bool bShow)790 void AD_Document::setShowRevisions(bool bShow)
791 {
792 if(m_bShowRevisions != bShow)
793 {
794 m_bShowRevisions = bShow;
795 forceDirty();
796 }
797 }
798
toggleShowRevisions()799 void AD_Document::toggleShowRevisions()
800 {
801 setShowRevisions(!m_bShowRevisions);
802 }
803
setShowRevisionId(UT_uint32 iId)804 void AD_Document::setShowRevisionId(UT_uint32 iId)
805 {
806 if(iId != m_iShowRevisionID)
807 {
808 m_iShowRevisionID = iId;
809 forceDirty();
810 }
811 }
812
setRevisionId(UT_uint32 iId)813 void AD_Document::setRevisionId(UT_uint32 iId)
814 {
815 if(iId != m_iRevisionID)
816 {
817 m_iRevisionID = iId;
818 // not in this case; this value is not persistent between sessions
819 //forceDirty();
820 }
821 }
822
setAutoRevisioning(bool b)823 void AD_Document::setAutoRevisioning(bool b)
824 {
825 if(b != m_bAutoRevisioning)
826 {
827 // First of all, we will increase the document version number;
828 // this will allow us to match autorevision id to a document
829 // version number. However, do not increase the version number,
830 // etc., if == 0 (we have a new, unsaved document)
831 time_t t = time(NULL);
832
833 if(m_bAfterFirstSave)
834 {
835 m_iVersion++;
836
837 AD_VersionData v(m_iVersion, t, b, getTopXID());
838 addRecordToHistory(v);
839 }
840
841 m_bAutoRevisioning = b;
842
843 if(b)
844 {
845 // now create new revision
846 // if we did not adjust version because we have just been
847 // loaded and not saved, we do not want to adjust the
848 // revision number either
849 if(m_bAfterFirstSave)
850 {
851 const XAP_StringSet * pSS = XAP_App::getApp()->getStringSet();
852 UT_return_if_fail(pSS);
853 UT_UCS4String ucs4(pSS->getValue(XAP_STRING_ID_MSG_AutoRevision));
854
855 UT_uint32 iId = getRevisionId() + 1;
856
857 setRevisionId(iId);
858 addRevision(iId, ucs4.ucs4_str(),ucs4.length(),t, m_iVersion);
859 }
860 else if(getHighestRevisionId() != getRevisionId())
861 {
862 // we have not saved yet, but the revision we are
863 // going to be using is not in the revision table, add it
864 const XAP_StringSet * pSS = XAP_App::getApp()->getStringSet();
865 UT_return_if_fail(pSS);
866 UT_UCS4String ucs4(pSS->getValue(XAP_STRING_ID_MSG_AutoRevision));
867
868 UT_uint32 iId = getRevisionId();
869 addRevision(iId, ucs4.ucs4_str(),ucs4.length(),t, m_iVersion);
870 }
871
872
873 // collapse all revisions ...
874 setShowRevisionId(PD_MAX_REVISION);
875 setShowRevisions(false);
876 }
877 else
878 {
879 // we have to wipe out all of the revision information
880 // from the document; this is because non-revisioned items
881 // are treated as revision level 0 and so any
882 // revisions in the document would overshadow any
883 // subsequent changes -- see bug 7183
884
885 // step out of revision mode ...
886 _setMarkRevisions(false);
887 m_bAutoRevisioning = false;
888
889 if(acceptAllRevisions())
890 {
891 // we succeeded in restoring the document, so now clear the
892 // history record
893 _purgeRevisionTable();
894
895 m_bDoNotAdjustHistory = true;
896 save();
897 m_bDoNotAdjustHistory = false;
898 }
899
900 // go back to revisioning mode so that the
901 // setMarkRevisions() below triggers rebuild ...
902 _setMarkRevisions(true);
903
904 }
905
906 setMarkRevisions(b);
907 }
908 }
909
910 /*!
911 Find revision id that corresponds to given document version
912 \return: id > 0 on success or 0 on failure
913 */
findAutoRevisionId(UT_uint32 iVersion) const914 UT_uint32 AD_Document::findAutoRevisionId(UT_uint32 iVersion) const
915 {
916 for(UT_sint32 i = 0; i < m_vRevisions.getItemCount(); i++)
917 {
918 const AD_Revision *pRev= m_vRevisions.getNthItem(i);
919 UT_return_val_if_fail(pRev, 0);
920
921 if(pRev->getVersion() == iVersion)
922 return pRev->getId();
923 }
924
925 UT_DEBUGMSG(("AD_Document::findAutoRevisionId: autorevision for version %d not found\n",
926 iVersion));
927
928 return 0;
929 }
930
931 /*!
932 Finds the nearest autorevision for the given document version
933 \param UT_uint32 iVersion: the document version
934 \param bool bLesser: indicates whether nearest lesser or nearest
935 greater autorevision is required
936 \return: id > 0 on success or 0 on failure
937 */
findNearestAutoRevisionId(UT_uint32 iVersion,bool bLesser) const938 UT_uint32 AD_Document::findNearestAutoRevisionId(UT_uint32 iVersion, bool bLesser) const
939 {
940 UT_uint32 iId = 0;
941
942 for(UT_sint32 i = 0; i < m_vRevisions.getItemCount(); i++)
943 {
944 const AD_Revision *pRev= m_vRevisions.getNthItem(i);
945 UT_return_val_if_fail(pRev, 0);
946
947 if(bLesser)
948 {
949 if(pRev->getVersion() < iVersion)
950 iId = pRev->getId();
951 else
952 break;
953 }
954 else
955 {
956 if(pRev->getVersion() > iVersion)
957 return pRev->getId();
958 }
959 }
960
961 #ifdef DEBUG
962 if(iId == 0)
963 {
964 UT_DEBUGMSG(("AD_Document::findNearestAutoRevisionId: not found [ver. %d, bLesser=%d]\n",
965 iVersion, bLesser));
966 }
967 #endif
968 return iId;
969 }
970
971
972 /*!
973 Update document history and version information; should only be
974 called inside save() and saveAs()
975 */
_adjustHistoryOnSave()976 void AD_Document::_adjustHistoryOnSave()
977 {
978 if(m_bDoNotAdjustHistory)
979 return;
980
981 // record this as the last time the document was saved + adjust
982 // the cumulative edit time
983 m_iVersion++;
984
985 if(!m_bHistoryWasSaved || m_bAutoRevisioning)
986 {
987 // if this is the first save, we will record the time the doc
988 // was opened as the start time, otherwise, we will use the
989 // current time
990 time_t t = !m_bHistoryWasSaved ? m_lastOpenedTime : time(NULL);
991
992 AD_VersionData v(m_iVersion,t,m_bAutoRevisioning,getTopXID());
993 m_lastSavedTime = v.getTime(); // store the time of this save
994 addRecordToHistory(v);
995
996 m_bHistoryWasSaved = true;
997 }
998 else
999 {
1000 UT_return_if_fail(m_vHistory.getItemCount() > 0);
1001
1002 // change the edit time of the last entry and create a new UID
1003 // for the record
1004 AD_VersionData * v = (AD_VersionData*)m_vHistory.getNthItem(m_vHistory.getItemCount()-1);
1005
1006 UT_return_if_fail(v);
1007 v->setId(m_iVersion);
1008 v->newUID();
1009 m_lastSavedTime = v->getTime();
1010 }
1011
1012 if(m_bAutoRevisioning)
1013 {
1014 // create new revision
1015 const XAP_StringSet * pSS = XAP_App::getApp()->getStringSet();
1016 UT_return_if_fail(pSS);
1017 UT_UCS4String ucs4(pSS->getValue(XAP_STRING_ID_MSG_AutoRevision));
1018
1019 UT_uint32 iId = getRevisionId()+1;
1020 setRevisionId(iId);
1021 addRevision(iId, ucs4.ucs4_str(),ucs4.length(),time(NULL), m_iVersion);
1022 }
1023 }
1024
_restoreVersion(XAP_Frame * pFrame,UT_uint32 iVersion)1025 bool AD_Document::_restoreVersion(XAP_Frame * pFrame, UT_uint32 iVersion)
1026 {
1027 UT_return_val_if_fail(pFrame, false);
1028
1029 if(isDirty())
1030 {
1031 if(pFrame->showMessageBox(XAP_STRING_ID_MSG_HistoryConfirmSave,
1032 XAP_Dialog_MessageBox::b_YN,
1033 XAP_Dialog_MessageBox::a_YES, getFilename())
1034 == XAP_Dialog_MessageBox::a_NO)
1035 {
1036 return false;
1037 }
1038
1039 save();
1040 }
1041
1042 // save the document under a different name ...
1043 // create unique new name
1044 UT_uint32 i = 0;
1045
1046 const char * pPath = g_strdup(getFilename());
1047 UT_return_val_if_fail(pPath, false);
1048
1049 char * pDot = (char *)strrchr(pPath,'.');
1050 if(pDot)
1051 {
1052 *pDot = 0;
1053 pDot++;
1054 }
1055
1056 UT_String s1, s2;
1057
1058 do
1059 {
1060 i++;
1061
1062 UT_String_sprintf(s2, "_version_%d-%d", iVersion, i);
1063
1064 s1 = pPath;
1065 s1 += s2;
1066
1067 if(pDot && *pDot)
1068 {
1069 s1 += ".";
1070 s1 += pDot;
1071 }
1072
1073 }
1074 while(UT_isRegularFile(s1.c_str()));
1075
1076 FREEP(pPath);
1077
1078 m_bDoNotAdjustHistory = true;
1079 saveAs(s1.c_str(), getLastSavedAsType());
1080 m_bDoNotAdjustHistory = false;
1081
1082 // step out of revision mode ...
1083 _setMarkRevisions(false);
1084 m_bAutoRevisioning = false;
1085
1086 UT_uint32 iRevisionId = findAutoRevisionId(iVersion);
1087
1088 // the revision id is the id of a revision that has been used to
1089 // modify version iVersion of the document. To restore iVersion,
1090 // we therefore have to reject all revisions >= iRevisionId
1091 UT_return_val_if_fail( iRevisionId > 0, false );
1092 iRevisionId--;
1093
1094 if(rejectAllHigherRevisions(iRevisionId))
1095 {
1096 // we succeeded in restoring the document, so now clear the
1097 // history record
1098 UT_sint32 iCount = getHistoryCount();
1099 const AD_VersionData * pVLast = NULL;
1100 time_t iEditTime = 0;
1101
1102 for(UT_sint32 j = 0; j < iCount; ++j)
1103 {
1104 AD_VersionData * v = (AD_VersionData *)m_vHistory.getNthItem(j);
1105 if(!v)
1106 {
1107 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1108 continue;
1109 }
1110
1111 if(v->getId() == iVersion)
1112 {
1113 pVLast = v;
1114 continue;
1115 }
1116
1117 if(v->getId() > iVersion)
1118 {
1119 // remember the lenth of the session
1120 iEditTime += (v->getTime() - v->getStartTime());
1121
1122 delete v;
1123 m_vHistory.deleteNthItem(j);
1124 iCount--;
1125 j--;
1126 }
1127 }
1128
1129 UT_return_val_if_fail(pVLast,false);
1130
1131 // set the document version correctly
1132 setDocVersion(iVersion);
1133 setLastSavedTime(pVLast->getTime());
1134 setLastOpenedTime(time(NULL));
1135
1136 UT_ASSERT(m_iEditTime >= iEditTime);
1137 m_iEditTime -= iEditTime;
1138
1139 // now save me as I am
1140 m_bDoNotAdjustHistory = true;
1141 save();
1142 _clearUndo();
1143 m_bDoNotAdjustHistory = false;
1144 }
1145
1146 return true;
1147 }
1148
showHistory(AV_View * pView)1149 bool AD_Document::showHistory(AV_View * pView)
1150 {
1151 XAP_Frame * pFrame = static_cast<XAP_Frame *> ( pView->getParentData());
1152 UT_return_val_if_fail(pFrame, false);
1153
1154 pFrame->raise();
1155
1156 XAP_DialogFactory * pDialogFactory
1157 = static_cast<XAP_DialogFactory *>(pFrame->getDialogFactory());
1158
1159 XAP_Dialog_History * pDialog
1160 = static_cast<XAP_Dialog_History *>(pDialogFactory->requestDialog(XAP_DIALOG_ID_HISTORY));
1161
1162 UT_return_val_if_fail(pDialog,false);
1163
1164 pDialog->setDocument(this);
1165 pDialog->runModal(pFrame);
1166
1167 bool bShow = (pDialog->getAnswer() == XAP_Dialog_History::a_OK);
1168 bool bRet = false;
1169
1170 if (bShow)
1171 {
1172 UT_uint32 iVersion = pDialog->getSelectionId();
1173 UT_uint32 iOrigVersion = iVersion;
1174
1175 const XAP_StringSet * pSS = XAP_App::getApp()->getStringSet();
1176
1177 if(iVersion)
1178 {
1179 switch(verifyHistoryState(iVersion))
1180 {
1181 case ADHIST_PARTIAL_RESTORE:
1182 {
1183 // display warning message allowing user to
1184 // cancel, etc.
1185 UT_return_val_if_fail(pSS,false);
1186 UT_String s1, s2;
1187 const char * msg1, * msg2, * msg3, * msg4;
1188
1189 if(iVersion)
1190 {
1191 // full restore possible
1192 msg1 = pSS->getValue(XAP_STRING_ID_MSG_HistoryPartRestore1);
1193 msg2 = pSS->getValue(XAP_STRING_ID_MSG_HistoryPartRestore2);
1194 msg4 = pSS->getValue(XAP_STRING_ID_MSG_HistoryPartRestore4);
1195 UT_return_val_if_fail(msg1 && msg2 && msg4, false);
1196
1197 s1 = msg1;
1198 s1 += " ";
1199 s1 += msg2;
1200 s1 += " ";
1201 s1 += msg4;
1202
1203 UT_String_sprintf(s2,s1.c_str(),iOrigVersion,iVersion,iOrigVersion);
1204
1205 switch(pFrame->showMessageBox(s2.c_str(),
1206 XAP_Dialog_MessageBox::b_YNC,
1207 XAP_Dialog_MessageBox::a_YES))
1208 {
1209 case XAP_Dialog_MessageBox::a_NO:
1210 bRet = _restoreVersion(pFrame, iOrigVersion);
1211 break;
1212
1213 case XAP_Dialog_MessageBox::a_YES:
1214 bRet = _restoreVersion(pFrame, iVersion);
1215 break;
1216
1217 case XAP_Dialog_MessageBox::a_CANCEL:
1218 break;
1219
1220 default:
1221 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1222 }
1223
1224 }
1225 else
1226 {
1227 // full restore not possible
1228 msg1 = pSS->getValue(XAP_STRING_ID_MSG_HistoryPartRestore1);
1229 msg3 = pSS->getValue(XAP_STRING_ID_MSG_HistoryPartRestore3);
1230 msg4 = pSS->getValue(XAP_STRING_ID_MSG_HistoryPartRestore4);
1231 UT_return_val_if_fail(msg1 && msg3 && msg4,false);
1232
1233 s1 = msg1;
1234 s1 += " ";
1235 s1 += msg3;
1236 s1 += " ";
1237 s1 += msg4;
1238
1239 UT_String_sprintf(s2, s1.c_str(), iOrigVersion);
1240
1241 switch(pFrame->showMessageBox(s2.c_str(),
1242 XAP_Dialog_MessageBox::b_OC,
1243 XAP_Dialog_MessageBox::a_OK))
1244 {
1245 case XAP_Dialog_MessageBox::a_OK:
1246 bRet = _restoreVersion(pFrame, iOrigVersion);
1247 break;
1248
1249 case XAP_Dialog_MessageBox::a_CANCEL:
1250 break;
1251
1252 default:
1253 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1254 }
1255
1256 }
1257 }
1258 break;
1259
1260 case ADHIST_FULL_RESTORE:
1261 bRet = _restoreVersion(pFrame, iVersion);
1262 break;
1263
1264 case ADHIST_NO_RESTORE:
1265 // issue a warning message and quit
1266 {
1267
1268 UT_return_val_if_fail(pSS,false);
1269 UT_String s2;
1270 const char * msg1;
1271
1272 msg1 = pSS->getValue(XAP_STRING_ID_MSG_HistoryNoRestore);
1273 UT_return_val_if_fail(msg1,false);
1274
1275 UT_String_sprintf(s2, msg1, iOrigVersion);
1276
1277 pFrame->showMessageBox(s2.c_str(),
1278 XAP_Dialog_MessageBox::b_O,
1279 XAP_Dialog_MessageBox::a_OK);
1280 }
1281 break;
1282
1283 default:
1284 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1285 }
1286 }
1287 }
1288
1289 pDialogFactory->releaseDialog(pDialog);
1290
1291 return bRet;
1292 }
1293
saveAs(const char * szFilename,int ieft,const char * props)1294 UT_Error AD_Document::saveAs(const char * szFilename, int ieft, const char * props)
1295 {
1296 UT_Error e = _saveAs(szFilename, ieft, props);
1297
1298 m_bAfterFirstSave |= (UT_OK == e);
1299 return e;
1300 }
1301
1302
saveAs(const char * szFilename,int ieft,bool cpy,const char * props)1303 UT_Error AD_Document::saveAs(const char * szFilename, int ieft, bool cpy, const char * props)
1304 {
1305 UT_Error e = _saveAs(szFilename, ieft, cpy, props);
1306
1307 m_bAfterFirstSave |= (UT_OK == e);
1308 return e;
1309 }
1310
1311
save(void)1312 UT_Error AD_Document::save(void)
1313 {
1314 UT_Error e = _save();
1315
1316 m_bAfterFirstSave |= (UT_OK == e);
1317 return e;
1318 }
1319
purgeAllRevisions(AV_View * pView)1320 bool AD_Document::purgeAllRevisions(AV_View * pView)
1321 {
1322 UT_return_val_if_fail( pView, false );
1323
1324 XAP_Frame * pFrame = static_cast<XAP_Frame *> ( pView->getParentData());
1325 UT_return_val_if_fail( pFrame, false );
1326
1327 if(pFrame->showMessageBox(XAP_STRING_ID_MSG_NoUndo,
1328 XAP_Dialog_MessageBox::b_YN,
1329 XAP_Dialog_MessageBox::a_YES, getFilename())
1330 == XAP_Dialog_MessageBox::a_NO)
1331 {
1332 return false;
1333 }
1334
1335 setMarkRevisions(false);
1336 bool bRet = acceptAllRevisions();
1337 purgeRevisionTable(true);
1338 _clearUndo();
1339 return bRet;
1340 }
1341
1342
1343 ///////////////////////////////////////////////////
1344 // AD_VersionData
1345 //
1346 // constructor for new entries
AD_VersionData(UT_uint32 v,time_t start,bool autorev,UT_uint32 xid)1347 AD_VersionData::AD_VersionData(UT_uint32 v, time_t start, bool autorev, UT_uint32 xid)
1348 :m_iId(v),m_pUUID(NULL),m_tStart(start),m_bAutoRevision(autorev),m_iTopXID(xid)
1349 {
1350 // we do not create uuid's based on the main doc uuid as
1351 // AD_Document::getNewUUID() does; this is because we need to be
1352 // able to distinguish between versions of documents created at
1353 // different place at the same time.
1354 UT_UUIDGenerator * pGen = XAP_App::getApp()->getUUIDGenerator();
1355 UT_return_if_fail(pGen);
1356
1357 m_pUUID = pGen->createUUID();
1358 UT_return_if_fail(m_pUUID);
1359 m_tStart = m_pUUID->getTime();
1360 }
1361
1362
1363 // constructors for importers
AD_VersionData(UT_uint32 v,UT_UTF8String & uuid,time_t start,bool autorev,UT_uint32 iTopXID)1364 AD_VersionData::AD_VersionData(UT_uint32 v, UT_UTF8String &uuid, time_t start, bool autorev, UT_uint32 iTopXID):
1365 m_iId(v),m_pUUID(NULL),m_tStart(start),m_bAutoRevision(autorev),m_iTopXID(iTopXID)
1366 {
1367 UT_UUIDGenerator * pGen = XAP_App::getApp()->getUUIDGenerator();
1368 UT_return_if_fail(pGen);
1369
1370 m_pUUID = pGen->createUUID(uuid);
1371 UT_ASSERT_HARMLESS(m_pUUID);
1372 }
1373
AD_VersionData(UT_uint32 v,const char * uuid,time_t start,bool autorev,UT_uint32 iTopXID)1374 AD_VersionData::AD_VersionData(UT_uint32 v, const char *uuid, time_t start, bool autorev, UT_uint32 iTopXID):
1375 m_iId(v),m_pUUID(NULL),m_tStart(start),m_bAutoRevision(autorev),m_iTopXID(iTopXID)
1376 {
1377 UT_UUIDGenerator * pGen = XAP_App::getApp()->getUUIDGenerator();
1378 UT_return_if_fail(pGen);
1379
1380 m_pUUID = pGen->createUUID(uuid);
1381 UT_ASSERT_HARMLESS(m_pUUID);
1382 }
1383
1384 // copy constructor
AD_VersionData(const AD_VersionData & v)1385 AD_VersionData::AD_VersionData(const AD_VersionData & v):
1386 m_iId(v.m_iId), m_pUUID(NULL), m_bAutoRevision(v.m_bAutoRevision), m_iTopXID(v.m_iTopXID)
1387 {
1388 UT_return_if_fail(v.m_pUUID);
1389 UT_UUIDGenerator * pGen = XAP_App::getApp()->getUUIDGenerator();
1390 UT_return_if_fail(pGen);
1391
1392 m_pUUID = pGen->createUUID(*(v.m_pUUID));
1393 UT_ASSERT(m_pUUID);
1394
1395 m_tStart = v.m_tStart;
1396 }
1397
operator =(const AD_VersionData & v)1398 AD_VersionData & AD_VersionData::operator = (const AD_VersionData &v)
1399 {
1400 m_iId = v.m_iId;
1401 *m_pUUID = *(v.m_pUUID);
1402 m_tStart = v.m_tStart;
1403 m_iTopXID = v.m_iTopXID;
1404 m_bAutoRevision = v.m_bAutoRevision;
1405 return *this;
1406 }
1407
operator ==(const AD_VersionData & v)1408 bool AD_VersionData::operator == (const AD_VersionData &v)
1409 {
1410 return (m_iId == v.m_iId && m_tStart == v.m_tStart
1411 && *m_pUUID == *(v.m_pUUID) && m_bAutoRevision == v.m_bAutoRevision && m_iTopXID == v.m_iTopXID);
1412 }
1413
~AD_VersionData()1414 AD_VersionData::~AD_VersionData()
1415 {
1416 DELETEP(m_pUUID);
1417 }
1418
getTime() const1419 time_t AD_VersionData::getTime()const
1420 {
1421 if(!m_pUUID)
1422 return 0;
1423
1424 return m_pUUID->getTime();
1425 }
1426
newUID()1427 bool AD_VersionData::newUID()
1428 {
1429 if(!m_pUUID)
1430 return false;
1431
1432 return m_pUUID->makeUUID();
1433 }
1434