1 /* AbiWord
2 * Copyright (C) 2011 Ben Martin
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA.
18 */
19
20 #include "pl_ListenerCoupleCloser.h"
21 #include "pp_AttrProp.h"
22 #include "pf_Frag_Strux.h"
23 #include "px_CR_FmtMark.h"
24 #include "px_CR_FmtMarkChange.h"
25 #include "px_CR_Object.h"
26 #include "px_CR_ObjectChange.h"
27 #include "px_CR_Span.h"
28 #include "px_CR_SpanChange.h"
29 #include "px_CR_Strux.h"
30 #include "px_CR_StruxChange.h"
31
32 #include <pd_DocumentRDF.h>
33
34
35 class PD_Bookmark
36 {
37 const PP_AttrProp* m_pAP;
38 bool m_isEnd;
39 std::string m_id;
40 public:
41 PD_Bookmark( PD_Document* pDoc, PT_AttrPropIndex api );
42 bool isEnd();
43 std::string getID();
44 };
45
PD_Bookmark(PD_Document * pDoc,PT_AttrPropIndex api)46 PD_Bookmark::PD_Bookmark( PD_Document* pDoc, PT_AttrPropIndex api )
47 : m_pAP( 0 )
48 , m_isEnd( true )
49 {
50 pDoc->getAttrProp(api,&m_pAP);
51
52 const gchar* pValue = NULL;
53 if(m_pAP
54 && m_pAP->getAttribute("type",pValue)
55 && pValue
56 && (strcmp(pValue, "start") == 0))
57 {
58 m_isEnd = false;
59 }
60
61 if(m_pAP->getAttribute("name",pValue) && pValue)
62 {
63 m_id = pValue;
64 }
65 }
66
isEnd()67 bool PD_Bookmark::isEnd()
68 {
69 return m_isEnd;
70 }
71
getID()72 std::string PD_Bookmark::getID()
73 {
74 return m_id;
75 }
76
77 bool
shouldClose(const std::string & id,bool,stringlist_t & sl)78 PL_ListenerCoupleCloser::shouldClose( const std::string& id,
79 bool /*isEnd*/,
80 stringlist_t& sl )
81 {
82 stringlist_t::iterator iter = find( sl.begin(), sl.end(), id );
83 if( iter != sl.end() )
84 {
85 sl.erase( iter );
86 return true;
87 }
88 return false;
89 }
90
91 /********************************************************************************/
92 /********************************************************************************/
93 /********************************************************************************/
94 /********************************************************************************/
95 /********************************************************************************/
96
97
PL_ListenerCoupleCloser()98 PL_ListenerCoupleCloser::PL_ListenerCoupleCloser()
99 : m_pDocument(0)
100 , m_delegate(0)
101 , m_AfterContentListener(this)
102 , m_BeforeContentListener(this)
103 , m_NullContentListener(this)
104 {
105 }
106
~PL_ListenerCoupleCloser()107 PL_ListenerCoupleCloser::~PL_ListenerCoupleCloser()
108 {
109 }
110
111 PD_Document*
getDocument(void)112 PL_ListenerCoupleCloser::getDocument(void)
113 {
114 return m_pDocument;
115 }
116
117 void
setDocument(PD_Document * pDoc)118 PL_ListenerCoupleCloser::setDocument(PD_Document * pDoc)
119 {
120 m_pDocument = pDoc;
121 }
122
123
124 void
setDelegate(PL_Listener * delegate)125 PL_ListenerCoupleCloser::setDelegate( PL_Listener* delegate )
126 {
127 m_delegate = delegate;
128 }
129
130 void
reset()131 PL_ListenerCoupleCloser::reset()
132 {
133 m_rdfUnclosedAnchorStack.clear();
134 m_rdfUnopenedAnchorStack.clear();
135 m_bookmarkUnclosedStack.clear();
136 m_bookmarkUnopenedStack.clear();
137 }
138
139
140
141 /****************************************/
142 /****************************************/
143 /****************************************/
144
145 bool
populateStrux(pf_Frag_Strux *,const PX_ChangeRecord *,fl_ContainerLayout **)146 PL_ListenerCoupleCloser::populateStrux( pf_Frag_Strux* /*sdh*/,
147 const PX_ChangeRecord * /*pcr*/,
148 fl_ContainerLayout* * /* psfh */ )
149 {
150 return true;
151 }
152
153 void
trackOpenClose(const std::string & id,bool isEnd,stringlist_t & unclosed,stringlist_t & unopened)154 PL_ListenerCoupleCloser::trackOpenClose( const std::string& id,
155 bool isEnd,
156 stringlist_t& unclosed,
157 stringlist_t& unopened )
158 {
159 if( isEnd )
160 {
161 stringlist_t::iterator iter = find( unclosed.begin(),
162 unclosed.end(),
163 id );
164 if( iter == unclosed.end() )
165 {
166 // closing an object which was not opened in range.
167 unopened.push_back( id );
168 }
169 else
170 {
171 unclosed.erase( iter );
172 }
173 }
174 else
175 {
176 unclosed.push_back( id );
177 }
178 }
179
180
181 bool
populate(fl_ContainerLayout *,const PX_ChangeRecord * pcr)182 PL_ListenerCoupleCloser::populate(fl_ContainerLayout* /* sfh */,
183 const PX_ChangeRecord * pcr)
184 {
185 UT_DebugOnly<PT_AttrPropIndex> indexAP = pcr->getIndexAP();
186 UT_DEBUGMSG(("MIQ: PL_ListenerCoupleCloser::Populate() indexAP %d pcr.type:%d \n",
187 (PT_AttrPropIndex)indexAP, pcr->getType() ));
188 switch (pcr->getType())
189 {
190 case PX_ChangeRecord::PXT_InsertSpan:
191 {
192 return true;
193 }
194 case PX_ChangeRecord::PXT_InsertObject:
195 {
196 const PX_ChangeRecord_Object * pcro = static_cast<const PX_ChangeRecord_Object *>(pcr);
197 PT_AttrPropIndex api = pcr->getIndexAP();
198 switch (pcro->getObjectType())
199 {
200 case PTO_Bookmark:
201 {
202 PD_Bookmark a( getDocument(), api );
203 trackOpenClose( a.getID(), a.isEnd(),
204 m_bookmarkUnclosedStack,
205 m_bookmarkUnopenedStack );
206 break;
207 }
208
209 case PTO_RDFAnchor:
210 {
211 RDFAnchor a( getDocument(), api );
212 trackOpenClose( a.getID(), a.isEnd(),
213 m_rdfUnclosedAnchorStack,
214 m_rdfUnopenedAnchorStack );
215
216 // std::string xmlid = a.getID();
217
218 // if( a.isEnd() )
219 // {
220 // stringlist_t::iterator iter = find( m_rdfUnclosedAnchorStack.begin(),
221 // m_rdfUnclosedAnchorStack.end(),
222 // xmlid );
223 // if( iter == m_rdfUnclosedAnchorStack.end() )
224 // {
225 // // closing an rdf anchor which was not opened in range.
226 // m_rdfUnopenedAnchorStack.push_back( xmlid );
227 // }
228 // else
229 // {
230 // m_rdfUnclosedAnchorStack.erase( iter );
231 // }
232 // }
233 // else
234 // {
235 // m_rdfUnclosedAnchorStack.push_back( xmlid );
236 // }
237
238 break;
239 }
240 default:
241 break;
242 }
243
244 return true;
245 }
246 default:
247 return true;
248 }
249 return true;
250 }
251
252
253 /****************************************/
254 /****************************************/
255 /****************************************/
256 /****************************************/
257 /****************************************/
258 /****************************************/
259
260 bool
populateStruxAfter(pf_Frag_Strux *,const PX_ChangeRecord * pcr,fl_ContainerLayout **)261 PL_ListenerCoupleCloser::populateStruxAfter( pf_Frag_Strux* /*sdh*/,
262 const PX_ChangeRecord * pcr,
263 fl_ContainerLayout* * /* psfh */ )
264 {
265 UT_DebugOnly<PT_AttrPropIndex> indexAP = pcr->getIndexAP();
266 UT_DEBUGMSG(("MIQ: PL_ListenerCoupleCloser::PopulateStruxAfter() indexAP %d pcr.type:%d \n",
267 (PT_AttrPropIndex)indexAP, pcr->getType() ));
268 return true;
269 }
270
271
272
273
274 bool
populateAfter(fl_ContainerLayout * sfh,const PX_ChangeRecord * pcr)275 PL_ListenerCoupleCloser::populateAfter( fl_ContainerLayout* sfh,
276 const PX_ChangeRecord * pcr )
277 {
278 UT_DebugOnly<PT_AttrPropIndex> indexAP = pcr->getIndexAP();
279 UT_DEBUGMSG(("MIQ: PL_ListenerCoupleCloser::PopulateAfter() indexAP %d pcr.type:%d \n",
280 (PT_AttrPropIndex)indexAP, pcr->getType() ));
281 switch (pcr->getType())
282 {
283 case PX_ChangeRecord::PXT_InsertSpan:
284 {
285 return true;
286 }
287 case PX_ChangeRecord::PXT_InsertObject:
288 {
289 const PX_ChangeRecord_Object * pcro = static_cast<const PX_ChangeRecord_Object *>(pcr);
290 PT_AttrPropIndex api = pcr->getIndexAP();
291 switch (pcro->getObjectType())
292 {
293 case PTO_Bookmark:
294 if( !m_bookmarkUnclosedStack.empty() )
295 {
296 PD_Bookmark a( getDocument(), api );
297 if( shouldClose( a.getID(), a.isEnd(), m_bookmarkUnclosedStack ) )
298 {
299 return m_delegate->populate( sfh, pcr );
300 }
301 break;
302 }
303 case PTO_RDFAnchor:
304 if( !m_rdfUnclosedAnchorStack.empty() )
305 {
306 RDFAnchor a( getDocument(), api );
307 UT_DEBUGMSG(("MIQ: PL_ListenerCoupleCloser::PopulateAfter() rdfid:%s \n",
308 a.getID().c_str() ));
309 if( shouldClose( a.getID(), a.isEnd(), m_rdfUnclosedAnchorStack ) )
310 {
311 return m_delegate->populate( sfh, pcr );
312 }
313 break;
314 }
315 default:
316 break;
317 }
318
319 return true;
320 }
321 default:
322 return true;
323 }
324 return true;
325 }
326
populate(fl_ContainerLayout * sfh,const PX_ChangeRecord * pcr)327 bool PL_ListenerCoupleCloser::AfterContentListener::populate( fl_ContainerLayout* sfh,
328 const PX_ChangeRecord * pcr )
329 {
330 return m_self->populateAfter( sfh, pcr );
331 }
332
333 bool
populateStrux(pf_Frag_Strux * sdh,const PX_ChangeRecord * pcr,fl_ContainerLayout ** psfh)334 PL_ListenerCoupleCloser::AfterContentListener::populateStrux( pf_Frag_Strux* sdh,
335 const PX_ChangeRecord * pcr,
336 fl_ContainerLayout* * psfh )
337 {
338 return m_self->populateStruxAfter( sdh, pcr, psfh );
339 }
340
isFinished()341 bool PL_ListenerCoupleCloser::AfterContentListener::isFinished()
342 {
343 return m_self->m_rdfUnclosedAnchorStack.empty()
344 && m_self->m_bookmarkUnclosedStack.empty();
345 }
346
347 /****************************************/
348 /****************************************/
349 /****************************************/
350
351 bool
populateStruxBefore(pf_Frag_Strux *,const PX_ChangeRecord * pcr,fl_ContainerLayout **)352 PL_ListenerCoupleCloser::populateStruxBefore( pf_Frag_Strux* /*sdh*/,
353 const PX_ChangeRecord * pcr,
354 fl_ContainerLayout* * /* psfh */ )
355 {
356 UT_DebugOnly<PT_AttrPropIndex> indexAP = pcr->getIndexAP();
357 UT_DEBUGMSG(("MIQ: PL_ListenerCoupleCloser::PopulateStruxBefore() indexAP %d pcr.type:%d \n",
358 (PT_AttrPropIndex)indexAP, pcr->getType() ));
359
360
361 return true;
362 }
363
364 bool
shouldOpen(const std::string & id,bool,stringlist_t & sl)365 PL_ListenerCoupleCloser::shouldOpen( const std::string& id,
366 bool /*isEnd*/,
367 stringlist_t& sl )
368 {
369 stringlist_t::iterator iter = find( sl.begin(), sl.end(), id );
370 if( iter != sl.end() )
371 {
372 sl.erase( iter );
373 return true;
374 }
375 return false;
376 }
377
378 bool
populateBefore(fl_ContainerLayout * sfh,const PX_ChangeRecord * pcr)379 PL_ListenerCoupleCloser::populateBefore( fl_ContainerLayout* sfh,
380 const PX_ChangeRecord * pcr )
381 {
382 UT_DebugOnly<PT_AttrPropIndex> indexAP = pcr->getIndexAP();
383 UT_DEBUGMSG(("MIQ: PL_ListenerCoupleCloser::PopulateBefore() indexAP %d pcr.type:%d \n",
384 (PT_AttrPropIndex)indexAP, pcr->getType() ));
385 switch (pcr->getType())
386 {
387 case PX_ChangeRecord::PXT_InsertSpan:
388 {
389 return true;
390 }
391 case PX_ChangeRecord::PXT_InsertObject:
392 {
393 const PX_ChangeRecord_Object * pcro = static_cast<const PX_ChangeRecord_Object *>(pcr);
394 PT_AttrPropIndex api = pcr->getIndexAP();
395 switch (pcro->getObjectType())
396 {
397 case PTO_Bookmark:
398 if( !m_bookmarkUnopenedStack.empty() )
399 {
400 PD_Bookmark a( getDocument(), api );
401 if( shouldOpen( a.getID(), a.isEnd(), m_bookmarkUnopenedStack ))
402 return m_delegate->populate( sfh, pcr );
403 break;
404 }
405 case PTO_RDFAnchor:
406 if( !m_rdfUnopenedAnchorStack.empty() )
407 {
408 RDFAnchor a( getDocument(), api );
409 UT_DEBUGMSG(("MIQ: PL_ListenerCoupleCloser::PopulateBefore() rdfid:%s \n",
410 a.getID().c_str() ));
411 if( shouldOpen( a.getID(), a.isEnd(), m_rdfUnopenedAnchorStack ))
412 return m_delegate->populate( sfh, pcr );
413
414 // stringlist_t::iterator iter = find( m_rdfUnopenedAnchorStack.begin(),
415 // m_rdfUnopenedAnchorStack.end(),
416 // a.getID() );
417 // if( iter != m_rdfUnopenedAnchorStack.end() )
418 // {
419 // m_rdfUnopenedAnchorStack.erase( iter );
420 // return m_delegate->populate( sfh, pcr );
421 // }
422 break;
423 }
424 default:
425 break;
426 }
427
428 return true;
429 }
430 default:
431 return true;
432 }
433 return true;
434 }
435
436
populate(fl_ContainerLayout * sfh,const PX_ChangeRecord * pcr)437 bool PL_ListenerCoupleCloser::BeforeContentListener::populate( fl_ContainerLayout* sfh,
438 const PX_ChangeRecord * pcr )
439 {
440 return m_self->populateBefore( sfh, pcr );
441 }
442
443 bool
populateStrux(pf_Frag_Strux * sdh,const PX_ChangeRecord * pcr,fl_ContainerLayout ** psfh)444 PL_ListenerCoupleCloser::BeforeContentListener::populateStrux( pf_Frag_Strux* sdh,
445 const PX_ChangeRecord * pcr,
446 fl_ContainerLayout* * psfh )
447 {
448 return m_self->populateStruxBefore( sdh, pcr, psfh );
449 }
450
isFinished()451 bool PL_ListenerCoupleCloser::BeforeContentListener::isFinished()
452 {
453 return m_self->m_rdfUnopenedAnchorStack.empty()
454 && m_self->m_bookmarkUnopenedStack.empty();
455 }
456
457
458 /****************************************/
459 /****************************************/
460 /****************************************/
461
462
463 PL_FinishingListener*
getAfterContentListener()464 PL_ListenerCoupleCloser::getAfterContentListener()
465 {
466 return &m_AfterContentListener;
467 }
468
469 PL_FinishingListener*
getBeforeContentListener()470 PL_ListenerCoupleCloser::getBeforeContentListener()
471 {
472 return &m_BeforeContentListener;
473 }
474
475
476 PL_FinishingListener*
getNullContentListener()477 PL_ListenerCoupleCloser::getNullContentListener()
478 {
479 return &m_NullContentListener;
480 }
481
482