1 /* AbiWord
2 * Copyright (C) 1998 AbiSource, Inc.
3 * Updates by Ben Martin in 2011.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301 USA.
19 */
20
21
22 #include "ut_types.h"
23 #include "pf_Frag.h"
24 #include "pt_PieceTable.h"
25 #include "pf_Fragments.h"
26
pf_Frag(pt_PieceTable * pPT,PFType type,UT_uint32 length)27 pf_Frag::pf_Frag(pt_PieceTable * pPT, PFType type, UT_uint32 length):
28 m_type(type),
29 m_pField(NULL),
30 m_pPieceTable(pPT),
31 m_indexAP(0),
32 m_length(length),
33 m_leftTreeLength(0),
34 m_iXID(0),
35 m_pMyNode(NULL)
36 {
37 }
38
~pf_Frag()39 pf_Frag::~pf_Frag()
40 {
41 xxx_UT_DEBUGMSG(("Delete Frag of Type %d pointer %p \n",getType(),this));
42 }
43
44 /*!
45 returns true if both content and fmt of the two frags is identical
46 */
operator ==(const pf_Frag & f2) const47 bool pf_Frag::operator == (const pf_Frag & f2) const
48 {
49 if(getType() != f2.getType())
50 return false;
51
52 // decide if the two frags have same piecetables
53 if(!m_pPieceTable || !f2.m_pPieceTable)
54 return false;
55
56 if(m_pPieceTable == f2.m_pPieceTable)
57 {
58 if(m_indexAP != f2.m_indexAP)
59 return false;
60 }
61 else
62 {
63 // different PT, do it the hard way ...
64 const PP_AttrProp * pAP1;
65 const PP_AttrProp * pAP2;
66
67 m_pPieceTable->getAttrProp(m_indexAP, &pAP1);
68 f2.m_pPieceTable->getAttrProp(f2.m_indexAP, &pAP2);
69
70 UT_return_val_if_fail(pAP1 && pAP2, false);
71
72 if(!pAP1->isEquivalent(pAP2))
73 {
74 return false;
75 }
76 }
77
78 return _isContentEqual(f2);
79 }
80
81 /*!
82 Returns true if the content of the two fragments is identical, but
83 ignores formatting properies.
84 */
isContentEqual(const pf_Frag & f2) const85 bool pf_Frag::isContentEqual(const pf_Frag & f2) const
86 {
87 if(getType() != f2.getType())
88 return false;
89
90 // check we have PT to fidle with ...
91 if(!m_pPieceTable || !f2.m_pPieceTable)
92 return false;
93
94 return _isContentEqual(f2);
95 }
96
getPos(void) const97 PT_DocPosition pf_Frag::getPos(void) const
98 {
99 UT_return_val_if_fail(m_pMyNode,0);
100 pf_Fragments * fragments = &(m_pPieceTable->getFragments());
101 const pf_Fragments::Iterator it(fragments,m_pMyNode);
102 PT_DocPosition pos = fragments->documentPosition(it);
103 return pos;
104 }
105
106 /*!
107 * Tell the fragments tree that the length of this item changed by
108 * delta.
109 * delta = new_length - old_length
110 */
lengthChanged(UT_sint32 delta)111 void pf_Frag::lengthChanged(UT_sint32 delta)
112 {
113 UT_return_if_fail(m_pMyNode);
114 pf_Fragments * fragments = &(m_pPieceTable->getFragments());
115 fragments->changeSize(delta);
116 pf_Fragments::Iterator it(fragments,m_pMyNode);
117 fragments->fixSize(it);
118 }
119
120 /* We need the following function to accumulate left tree length */
accLeftTreeLength(PT_DocPosition length)121 void pf_Frag:: accLeftTreeLength(PT_DocPosition length)
122 {
123 m_leftTreeLength += length;
124 }
125
_setNode(pf_Fragments::Node * pNode)126 void pf_Frag::_setNode(pf_Fragments::Node * pNode)
127 {
128 m_pMyNode = pNode;
129 }
130
_getNode(void) const131 pf_Fragments::Node * pf_Frag::_getNode(void) const
132 {
133 return m_pMyNode;
134 }
135
createSpecialChangeRecord(PX_ChangeRecord **,PT_DocPosition) const136 bool pf_Frag::createSpecialChangeRecord(PX_ChangeRecord ** /*ppcr*/,
137 PT_DocPosition /*dpos*/) const
138 {
139 // really this should be declared abstract in pf_Frag,
140 // but we didn't derrive a sub-class for EOD -- it actually
141 // uses the base class as is.
142
143 // this function must be overloaded for all sub-classes.
144
145 UT_ASSERT_HARMLESS(0);
146 return true;
147 }
148
getField(void) const149 fd_Field * pf_Frag::getField(void) const
150 {
151 return m_pField;
152 }
153
getNext(void) const154 pf_Frag* pf_Frag::getNext(void) const
155 {
156 UT_return_val_if_fail(m_pMyNode,NULL);
157 pf_Fragments::Iterator it(&(m_pPieceTable->getFragments()),m_pMyNode);
158 it++;
159 return it.value();
160 }
161
162
getPrev(void) const163 pf_Frag* pf_Frag::getPrev(void) const
164 {
165 UT_return_val_if_fail(m_pMyNode,NULL);
166 pf_Fragments::Iterator it(&(m_pPieceTable->getFragments()),m_pMyNode);
167 it--;
168 return it.value();
169 }
170
171 #include "pf_Frag_Strux.h"
172
isStuxType(const pf_Frag * const pf,PTStruxType t)173 static bool isStuxType( const pf_Frag* const pf, PTStruxType t )
174 {
175 if( pf->getType() != pf_Frag::PFT_Strux )
176 return false;
177
178 const pf_Frag_Strux* const pfs = static_cast<const pf_Frag_Strux* const>(pf);
179 return pfs->getStruxType() == t;
180 }
181
182 /**
183 * Get the next strux of the given type from the document. Note that
184 * the return value can never be this fragment even if this fragment
185 * is also a strux of the sought type.
186 *
187 * This way, you can skip from on PTX_Block to the next in a loop using
188 * pf_Frag* pf = getFragOfType( PTX_Block );
189 * for( ; pf; pf = pf->getNextStrux(PTX_Block) )
190 * {
191 * ...
192 * }
193 */
getNextStrux(PTStruxType t) const194 pf_Frag_Strux* pf_Frag::getNextStrux(PTStruxType t) const
195 {
196 UT_return_val_if_fail(m_pMyNode,NULL);
197 pf_Fragments& fragments = m_pPieceTable->getFragments();
198 pf_Fragments::Iterator it(&(fragments),m_pMyNode);
199 // If we are the desired type, move ahead already.
200 if( isStuxType( this, t ))
201 {
202 it++;
203 }
204 for( pf_Fragments::Iterator e = fragments.end(); it != e; ++it )
205 {
206 pf_Frag* pf = it.value();
207 if( !pf )
208 return 0;
209 if( isStuxType( pf, t ))
210 {
211 return static_cast<pf_Frag_Strux*>(pf);
212 }
213 }
214 return 0;
215 }
216
217 pf_Frag_Strux*
tryDownCastStrux(PTStruxType t) const218 pf_Frag::tryDownCastStrux(PTStruxType t) const
219 {
220 if( getType() == pf_Frag::PFT_Strux )
221 {
222 pf_Fragments& fragments = m_pPieceTable->getFragments();
223 pf_Fragments::Iterator it(&(fragments),m_pMyNode);
224 pf_Frag* pf = it.value();
225 pf_Frag_Strux* pfs = static_cast<pf_Frag_Strux*>(pf);
226 PTStruxType eStruxType = pfs->getStruxType();
227 if( eStruxType == t )
228 return pfs;
229 }
230 return 0;
231 }
232
tryDownCastStrux(pf_Frag * pf,PTStruxType t)233 pf_Frag_Strux* tryDownCastStrux( pf_Frag* pf, PTStruxType t)
234 {
235 if( !pf )
236 return 0;
237 return pf->tryDownCastStrux( t );
238 }
239
240
241
242 #include "pf_Frag_Object.h"
243 #include "pf_Frag_Strux.h"
244 #include "pd_DocumentRDF.h"
245
246 std::string
getXMLID() const247 pf_Frag::getXMLID() const
248 {
249 std::string ret = "";
250
251 const PP_AttrProp* pAP = NULL;
252 m_pPieceTable->getAttrProp( getIndexAP() ,&pAP );
253 if( !pAP )
254 return ret;
255 const char* v = 0;
256
257 if(getType() == pf_Frag::PFT_Object)
258 {
259 const pf_Frag_Object* pOb = static_cast<const pf_Frag_Object*>(this);
260
261 if(pOb->getObjectType() == PTO_Bookmark)
262 {
263 if( pAP->getAttribute(PT_XMLID, v) && v)
264 {
265 ret = v;
266 }
267 }
268 if(pOb->getObjectType() == PTO_RDFAnchor)
269 {
270 RDFAnchor a(pAP);
271 ret = a.getID();
272 }
273 }
274 if(getType() == pf_Frag::PFT_Strux)
275 {
276 const pf_Frag_Strux* pfs = static_cast<const pf_Frag_Strux*>(this);
277 PTStruxType st = pfs->getStruxType();
278 if( st == PTX_Block || st == PTX_SectionCell )
279 {
280 if(pAP->getAttribute("xml:id", v))
281 {
282 ret = v;
283 }
284 }
285 }
286
287 return ret;
288 }
289
290