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