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