When copying a selection from a document, one might have the case where there are matched pairs of markers in the document. More...
#include <pl_ListenerCoupleCloser.h>
When copying a selection from a document, one might have the case where there are matched pairs of markers in the document.
When only one of the pair of markers is in the selection to copy, a simple copy using a listener on just that range will likely output an invalid document.
Consider the document below with the selection highlighted below it. If one attaches a pl_listener and calls PD_Document::tellListenerSubset() they will only see the bm-start tag. To generate a valid document, a listener would have to remember which pair tags are still open and close them in an appropriate order.
This is some text <bm-start>I can jump here<bm-end> ^-------------------------^
The closer class maintains a reference to the document and a delegate listener. The delegate listener will see all the populate() calls for the given document range, and then the closer will call populate() on the delegate for tags which are open in the range but not closed in the range. And the converse, where a tag is closed in the range but opened before the start of the range.
For the above document fragment, the delegate will the following because they are in the selected document range: " text " <bm-start> "I can jump"
From there the closer will find the matching <bm-end> and call delegate->populate(). So the delegate will see something like the following as the selection and have matched start and end bookmark tags.
text <bm-start>I can jump<bm-end>
Having this functionality in a separate closer class allows for extension by inheritance, and allows tellListenerSubset() to handle cases that one might not consider right off the bat, such as the following where the missing matching tag is actually before the selected range. In this case the closer will emit the required matching populate(bm-start) before the selected document content. Handling open tags before the range is a bit tricky because the call to delegate->populate() must be in document order and not the reverse order that might be used to step backwards from the desired range. This scenario is handled for you with the PL_ListenerCoupleCloser and pt_PieceTable::tellListenerSubset(): The delegate listener only ever sees items once, and in document ordering.
Some text <bm-start>I can jump here<bm-end> and then more waffle ^-------------------------^
While all range cases might not be covered right now, this class is a good foundation for adding new cases as they are found such that all listeners can benefit from proper closed ranges.
This class can be passed as the "closer" parameter to PD_Document::tellListenerSubset() and maintains the open/closed state of matched tags. Once the document range has been visited PD_Document::tellListenerSubset() calls methods like populateClose() in the closer which in turn might call populate() on the delegate listener.
typedef std::list< std::string > PL_ListenerCoupleCloser::stringlist_t [protected] |
PL_ListenerCoupleCloser::PL_ListenerCoupleCloser | ( | ) |
PL_ListenerCoupleCloser::~PL_ListenerCoupleCloser | ( | ) | [virtual] |
virtual bool PL_ListenerCoupleCloser::change | ( | fl_ContainerLayout * | , | |
const PX_ChangeRecord * | ||||
) | [inline, virtual] |
Implements PL_Listener.
PL_FinishingListener * PL_ListenerCoupleCloser::getAfterContentListener | ( | ) |
References m_AfterContentListener.
Referenced by pt_PieceTable::tellListenerSubset().
PL_FinishingListener * PL_ListenerCoupleCloser::getBeforeContentListener | ( | ) |
References m_BeforeContentListener.
Referenced by pt_PieceTable::tellListenerSubset().
PD_Document * PL_ListenerCoupleCloser::getDocument | ( | void | ) |
References m_pDocument.
Referenced by populate(), populateAfter(), and populateBefore().
PL_FinishingListener * PL_ListenerCoupleCloser::getNullContentListener | ( | ) |
References m_NullContentListener.
Referenced by pt_PieceTable::tellListenerSubset().
virtual bool PL_ListenerCoupleCloser::insertStrux | ( | fl_ContainerLayout * | , | |
const PX_ChangeRecord * | , | |||
pf_Frag_Strux * | , | |||
PL_ListenerId | , | |||
void(*)(pf_Frag_Strux *sdhNew,PL_ListenerId lid,fl_ContainerLayout *sfhNew) | ||||
) | [inline, virtual] |
Implements PL_Listener.
bool PL_ListenerCoupleCloser::populate | ( | fl_ContainerLayout * | sfh, | |
const PX_ChangeRecord * | pcr | |||
) | [virtual] |
Implements PL_Listener.
References getDocument(), RDFAnchor::getID(), PD_Bookmark::getID(), PX_ChangeRecord::getIndexAP(), PX_ChangeRecord_Object::getObjectType(), PX_ChangeRecord::getType(), RDFAnchor::isEnd(), PD_Bookmark::isEnd(), m_bookmarkUnclosedStack, m_bookmarkUnopenedStack, m_rdfUnclosedAnchorStack, m_rdfUnopenedAnchorStack, PTO_Bookmark, PTO_RDFAnchor, PX_ChangeRecord::PXT_InsertObject, PX_ChangeRecord::PXT_InsertSpan, trackOpenClose(), and UT_DEBUGMSG.
Referenced by pt_PieceTable::tellListenerSubset().
bool PL_ListenerCoupleCloser::populateAfter | ( | fl_ContainerLayout * | sfh, | |
const PX_ChangeRecord * | pcr | |||
) | [private, virtual] |
References getDocument(), RDFAnchor::getID(), PD_Bookmark::getID(), PX_ChangeRecord::getIndexAP(), PX_ChangeRecord_Object::getObjectType(), PX_ChangeRecord::getType(), RDFAnchor::isEnd(), PD_Bookmark::isEnd(), m_bookmarkUnclosedStack, m_delegate, m_rdfUnclosedAnchorStack, PL_Listener::populate(), PTO_Bookmark, PTO_RDFAnchor, PX_ChangeRecord::PXT_InsertObject, PX_ChangeRecord::PXT_InsertSpan, shouldClose(), and UT_DEBUGMSG.
Referenced by PL_ListenerCoupleCloser::AfterContentListener::populate().
bool PL_ListenerCoupleCloser::populateBefore | ( | fl_ContainerLayout * | sfh, | |
const PX_ChangeRecord * | pcr | |||
) | [private, virtual] |
References getDocument(), RDFAnchor::getID(), PD_Bookmark::getID(), PX_ChangeRecord::getIndexAP(), PX_ChangeRecord_Object::getObjectType(), PX_ChangeRecord::getType(), RDFAnchor::isEnd(), PD_Bookmark::isEnd(), m_bookmarkUnopenedStack, m_delegate, m_rdfUnopenedAnchorStack, PL_Listener::populate(), PTO_Bookmark, PTO_RDFAnchor, PX_ChangeRecord::PXT_InsertObject, PX_ChangeRecord::PXT_InsertSpan, shouldOpen(), and UT_DEBUGMSG.
Referenced by PL_ListenerCoupleCloser::BeforeContentListener::populate().
bool PL_ListenerCoupleCloser::populateStrux | ( | pf_Frag_Strux * | sdh, | |
const PX_ChangeRecord * | pcr, | |||
fl_ContainerLayout ** | psfh | |||
) | [virtual] |
Implements PL_Listener.
Referenced by pt_PieceTable::tellListenerSubset().
bool PL_ListenerCoupleCloser::populateStruxAfter | ( | pf_Frag_Strux * | sdh, | |
const PX_ChangeRecord * | pcr, | |||
fl_ContainerLayout ** | psfh | |||
) | [private, virtual] |
References PX_ChangeRecord::getIndexAP(), PX_ChangeRecord::getType(), and UT_DEBUGMSG.
Referenced by PL_ListenerCoupleCloser::AfterContentListener::populateStrux().
bool PL_ListenerCoupleCloser::populateStruxBefore | ( | pf_Frag_Strux * | sdh, | |
const PX_ChangeRecord * | pcr, | |||
fl_ContainerLayout ** | psfh | |||
) | [private, virtual] |
References PX_ChangeRecord::getIndexAP(), PX_ChangeRecord::getType(), and UT_DEBUGMSG.
Referenced by PL_ListenerCoupleCloser::BeforeContentListener::populateStrux().
void PL_ListenerCoupleCloser::reset | ( | void | ) |
References m_bookmarkUnclosedStack, m_bookmarkUnopenedStack, m_rdfUnclosedAnchorStack, and m_rdfUnopenedAnchorStack.
Referenced by pt_PieceTable::tellListenerSubset().
void PL_ListenerCoupleCloser::setDelegate | ( | PL_Listener * | delegate | ) |
References m_delegate.
Referenced by pt_PieceTable::tellListenerSubset().
void PL_ListenerCoupleCloser::setDocument | ( | PD_Document * | pDoc | ) |
References m_pDocument.
Referenced by pt_PieceTable::tellListenerSubset().
bool PL_ListenerCoupleCloser::shouldClose | ( | const std::string & | id, | |
bool | isEnd, | |||
stringlist_t & | sl | |||
) | [protected] |
Referenced by populateAfter().
bool PL_ListenerCoupleCloser::shouldOpen | ( | const std::string & | id, | |
bool | isEnd, | |||
stringlist_t & | sl | |||
) | [protected] |
Referenced by populateBefore().
virtual bool PL_ListenerCoupleCloser::signal | ( | UT_uint32 | ) | [inline, virtual] |
Implements PL_Listener.
void PL_ListenerCoupleCloser::trackOpenClose | ( | const std::string & | id, | |
bool | isEnd, | |||
stringlist_t & | unclosed, | |||
stringlist_t & | unopened | |||
) | [protected] |
Referenced by populate().
Referenced by getAfterContentListener().
Referenced by getBeforeContentListener().
Referenced by PL_ListenerCoupleCloser::AfterContentListener::isFinished(), populate(), populateAfter(), and reset().
Referenced by PL_ListenerCoupleCloser::BeforeContentListener::isFinished(), populate(), populateBefore(), and reset().
PL_Listener* PL_ListenerCoupleCloser::m_delegate [protected] |
Referenced by populateAfter(), populateBefore(), and setDelegate().
Referenced by getNullContentListener().
PD_Document* PL_ListenerCoupleCloser::m_pDocument [protected] |
Referenced by getDocument(), and setDocument().
Referenced by PL_ListenerCoupleCloser::AfterContentListener::isFinished(), populate(), populateAfter(), and reset().
Referenced by PL_ListenerCoupleCloser::BeforeContentListener::isFinished(), populate(), populateBefore(), and reset().