2 * Copyright (C) 2009 by Aiwota Programmer
3 * aiwotaprog@tetteke.tk
5 * This file is part of Dialektos.
7 * Dialektos is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * Dialektos is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Dialektos. If not, see <http://www.gnu.org/licenses/>.
21 #ifndef BUFFER_BUILDER_HXX
22 #define BUFFER_BUILDER_HXX
24 #include <glibmm/ustring.h>
25 #include <boost/range.hpp>
26 #include <boost/algorithm/string.hpp>
27 #include <boost/lexical_cast.hpp>
28 #include <boost/utility.hpp>
29 #include "text_view_layoutable.hxx"
30 #include "text_line.hxx"
31 #include "text_element_plain.hxx"
32 #include "text_element_anchor.hxx"
33 #include "text_element_id.hxx"
34 #include "text_element_res_num_map.hxx"
35 #include "text_element_id_map.hxx"
41 /*! @brief build text lines and text elements. */
42 class BufferBuilder : boost::noncopyable {
44 /*! @brief constructor. */
45 BufferBuilder(text_view::Layoutable& view, int res_num);
49 /*! @brief receive a text and output it to the thread view */
50 template <typename RangeT, typename RangeT2>
51 void add_text(const RangeT& range, bool bold, const RangeT2& href);
53 /*! @brief receive an id and output to it the thread view. */
54 template <typename RangeT, typename RangeT2>
55 void add_id(const RangeT& range, bool bold, const RangeT2& id);
57 /*! @brief receive the number of res and output it to the thread view. */
58 void add_res_num(int res_num, bool bold);
60 /*! @brief append current text line to the thread view and prepare new line. */
61 void new_line(int left_margin);
63 /*! @brief flush the cache. */
68 /*! @brief add respondent numbers to the res num map. */
69 template <typename RangeT>
70 void add_respondents(const RangeT& range);
72 text_view::Layoutable& text_view_;
74 TextLine* current_line_;
77 template <typename RangeT, typename RangeT2>
78 void BufferBuilder::add_text(const RangeT& range, bool bold,
79 const RangeT2& href) {
80 assert( current_line_ != 0);
82 typedef typename boost::range_const_iterator<RangeT>::type Iterator;
83 Iterator start = boost::begin(range);
84 Iterator end = boost::end(range);
85 if (current_line_->empty()) {
86 // this is the first element. skip white space.
87 for (; start != end; ++start) if (*start != ' ') break;
90 if (boost::empty(href)){
91 current_line_->add_element(
92 new text_element::Plain(std::make_pair(start, end), bold));
94 if (boost::starts_with(std::make_pair(start, end), ">>")) {
96 add_respondents(std::make_pair(next(next(start)), end));
98 current_line_->add_element(
99 new text_element::Anchor(std::make_pair(start, end), bold, href));
103 template <typename RangeT, typename RangeT2>
104 void BufferBuilder::add_id(const RangeT& range, bool bold,
106 assert( current_line_ != 0);
108 Glib::ustring id_str = Glib::ustring(boost::begin(id), boost::end(id));
109 current_line_->add_element(new text_element::ID(range, bold, id_str,
110 text_view_.get_id_map()));
111 text_view_.get_id_map()->add(id_str, res_num_);
114 template <typename RangeT>
115 void BufferBuilder::add_respondents(const RangeT& range) {
116 typedef typename boost::range_const_iterator<RangeT>::type Iterator;
117 using boost::lexical_cast;
121 boost::iterator_range<Iterator> hiphen;
122 hiphen = boost::algorithm::find_first(range, "-");
124 if (hiphen.empty()) {
128 num = lexical_cast<int>(std::string(begin(range), end(range)));
129 } catch (const std::exception&) {}
130 if (num > 0) text_view_.get_res_num_map()->add(num, res_num_);
132 // consider a range of multiple res
136 left = lexical_cast<int>(std::string(begin(range), begin(hiphen)));
137 right = lexical_cast<int>(std::string(end(hiphen), end(range)));
138 } catch (const std::exception&) {}
139 if (left > right) std::swap(left, right);
140 if (left != 0 && right != 0 && right - left < 10) {
141 // TODO the time of dictionary reference should be only once.
142 for (int i = left; i <= right; ++i)
143 text_view_.get_res_num_map()->add(i, res_num_);
149 } // namespace dialektos