LT Project: GTK Bibliographic formatting
We have been covering the forms taken by the general formatter, used to provide the detailed information for a given book. The other formatting model is the bibliographic formatter model, where only the core bibliographic information is printed, reordered and formatted in the standard form for bibliographies in scholarly works, or at least as close an approximation as can be managed.
The basic class was discussed several posts ago. Its extension into GTK handling is along quite different lines than the standard formatter. For the latter, a range of formatting options were wanted; for this only changing _Title_ into actual italics is needed for GUI formatting (although we also roll in the formatting in red for titles under reconsideration). On the other hand, we want to retain the fairly finicky logic used in the base-level bibliographic formatter.
class GtkGridBibliographicFieldFormatter : public LtLibrary::IFieldFormatter
{
public:
GtkGridBibliographicFieldFormatter(
GtkGrid *inGrid, const DetailRequestButtonFactory &inFactory);
~GtkGridBibliographicFieldFormatter() override;
void formatId(const int inId) const override;
void format(std::ostream &outStream, const LtLibrary::ELibraryRecord inRec,
const std::string &inValue) const override;
void formatTitle(std::ostream &outStream,
const LtLibrary::ELibraryRecord inRec,
const std::string &inValue,
const std::string_view inPostTitleValue) const override;
void formatAuthor(
std::ostream &outStream,
LtLibrary::ISettableAuthorContainer &outPostTitle,
const std::string &inValue, const std::string &inValue2,
const LtLibrary::ISecondaryAuthorSet &inSecondaryAuthors) const override;
static void ResetRow() { s_Row = 1; }
void markAsUnderReconsideration() const override;
protected:
void resetTextBuffer() const;
const DetailRequestButtonFactory &m_factory;
mutable GtkTextBuffer *m_buffer;
mutable GtkTextIter m_iter;
mutable IBibliographicTitleInserter *m_inserter;
inline static int s_Row = 1;
private:
LtLibrary::BibliographicFieldFormatter m_streamFormatter;
mutable GtkGrid *m_grid;
mutable int m_id = 0;
inline static TextBufferTagHandler m_handler{ std::array<TagStyles, 2>{
TagStyles::Italic, TagStyles::Error } };
};
This class delegates to the base-level formatter, and then inserts the output into the GTK buffer with at most only a small amount of tweaking.
The ordinary format() function is, accordingly, very short:
void GtkGridBibliographicFieldFormatter::format(
std::ostream &outStream, const LtLibrary::ELibraryRecord inRec,
const std::string &inValue) const
{
gtk_text_buffer_get_end_iter(m_buffer, &m_iter);
std::ostringstream str;
m_streamFormatter.format(str, inRec, inValue);
gtk_text_buffer_insert(m_buffer, &m_iter, str.str().c_str(),
str.str().length());
}
formatAuthor() delegates all the post-title determination logic to the stream version:
void GtkGridBibliographicFieldFormatter::formatAuthor(
std::ostream &outStream, LtLibrary::ISettableAuthorContainer &outPostTitle,
const std::string &inValue, const std::string &inValue2,
const LtLibrary::ISecondaryAuthorSet &inSecondaryAuthors) const
{
resetTextBuffer();
gtk_text_buffer_get_end_iter(m_buffer, &m_iter);
std::ostringstream str;
m_streamFormatter.formatAuthor(str, outPostTitle, inValue, inValue2,
inSecondaryAuthors);
gtk_text_buffer_insert(m_buffer, &m_iter, str.str().c_str(),
str.str().length());
}
formatTitle() removes the underlines used in the streamed format and then does output using a strategy determined by whether a work is under reconsideration or not:
void GtkGridBibliographicFieldFormatter::formatTitle(
std::ostream &outStream, const LtLibrary::ELibraryRecord inRec,
const std::string &inValue, const std::string_view inPostTitleValue) const
{
gtk_text_buffer_get_end_iter(m_buffer, &m_iter);
std::ostringstream str;
m_streamFormatter.formatTitle(str, inRec, inValue, inPostTitleValue);
std::string s = str.str().substr(1);
if (std::size_t index = s.find('_'); index != std::string::npos) [[likely]]
{
m_inserter
= m_inserter->insertTitle(s.substr(0, index), m_buffer, &m_iter);
m_inserter->insertPostTitle(s.substr(index + 1), m_buffer, &m_iter);
}
else // "Can't happen"
m_inserter = &NormalBibliographicTitleInserter::theInserter;
}
The interface for IBibliographicTitleInserter --
class IBibliographicTitleInserter
{
public:
virtual ~IBibliographicTitleInserter();
virtual IBibliographicTitleInserter *
insertTitle(const std::string &inTitle, GtkTextBuffer *inBuffer,
GtkTextIter *inIter) const = 0;
virtual void insertPostTitle(const std::string &inStr,
GtkTextBuffer *inBuffer,
GtkTextIter *inIter) const = 0;
};
-- has a couple of interesting wrinkles in its GTK implementations.
There are two stateless implementations. The normal one has the following code:
auto NormalBibliographicTitleInserter::insertTitle(const std::string &inTitle,
GtkTextBuffer *inBuffer,
GtkTextIter *inIter) const
-> NormalBibliographicTitleInserter *
{
gtk_text_buffer_insert_with_tags_by_name(
inBuffer, inIter, inTitle.c_str(), inTitle.length(), "italic", nullptr);
return &theInserter;
}
void NormalBibliographicTitleInserter::insertPostTitle(
const std::string &inStr, GtkTextBuffer *inBuffer,
GtkTextIter *inIter) const
{
if (!inStr.empty())
gtk_text_buffer_insert(inBuffer, inIter, inStr.c_str(), inStr.length());
}
using a static instance in its interface:
class NormalBibliographicTitleInserter : public IBibliographicTitleInserter
{
public:
~NormalBibliographicTitleInserter() override;
NormalBibliographicTitleInserter *insertTitle(const std::string &inTitle,
GtkTextBuffer *inBuffer,
GtkTextIter *inIter) const override;
void insertPostTitle(const std::string &inStr, GtkTextBuffer *inBuffer,
GtkTextIter *inIter) const override;
static NormalBibliographicTitleInserter theInserter;
};
The implementation for the UnderReconsideration version -- set explicitly in the higher-level class, once per book -- has a no-op for insertPostTitle(), because that function is never called. The insertTitle() call:
IBibliographicTitleInserter *
UnderReconsiderationBibliographicTitleInserter::insertTitle(
const std::string &inTitle, GtkTextBuffer *inBuffer,
GtkTextIter *inIter) const
{
gtk_text_buffer_insert_with_tags_by_name(inBuffer, inIter, inTitle.c_str(),
inTitle.length(), "italic", "error",
nullptr);
return &NormalBibliographicTitleInserter::theInserter;
}
returns a pointer to the normal implementation, so the calling sequence
m_inserter
= m_inserter->insertTitle(s.substr(0, index), m_buffer, &m_iter);
m_inserter->insertPostTitle(s.substr(index + 1), m_buffer, &m_iter);
always resets m_inserter to the normal version for the second call.
Comments
Post a Comment