OSDN Git Service

Add a menu item 'Close'.
[fukui-no-namari/dialektos.git] / src / buffer_builder.hxx
1 /*
2  * Copyright (C) 2009 by Aiwota Programmer
3  * aiwotaprog@tetteke.tk
4  *
5  * This file is part of Dialektos.
6  *
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.
11  *
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.
16  *
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/>.
19  */
20
21 #ifndef BUFFER_BUILDER_HXX
22 #define BUFFER_BUILDER_HXX
23
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"
36
37
38 namespace dialektos {
39
40
41 /*! @brief build text lines and text elements. */
42 class BufferBuilder : boost::noncopyable {
43 public:
44   /*! @brief constructor. */
45   BufferBuilder(text_view::Layoutable& view, int res_num);
46
47   ~BufferBuilder();
48
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);
52
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);
56
57   /*! @brief receive the number of res and output it to the thread view. */
58   void add_res_num(int res_num, bool bold);
59
60   /*! @brief append current text line to the thread view and prepare new line. */
61   void new_line(int left_margin);
62
63   /*! @brief flush the cache. */
64   void flush();
65
66 private:
67
68   /*! @brief add respondent numbers to the res num map. */
69   template <typename RangeT>
70   void add_respondents(const RangeT& range);
71
72   text_view::Layoutable& text_view_;
73   int res_num_;
74   TextLine* current_line_;
75 };
76
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);
81
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;
88   }
89
90   if (boost::empty(href)){
91     current_line_->add_element(
92         new text_element::Plain(std::make_pair(start, end), bold));
93   } else {
94     if (boost::starts_with(std::make_pair(start, end), ">>")) {
95       using boost::next;
96       add_respondents(std::make_pair(next(next(start)), end));
97     }
98     current_line_->add_element(
99         new text_element::Anchor(std::make_pair(start, end), bold, href));
100   }
101 }
102
103 template <typename RangeT, typename RangeT2>
104 void BufferBuilder::add_id(const RangeT& range, bool bold,
105     const RangeT2& id) {
106   assert( current_line_ != 0);
107
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_);
112 }
113
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;
118   using boost::begin;
119   using boost::end;
120
121   boost::iterator_range<Iterator> hiphen;
122   hiphen = boost::algorithm::find_first(range, "-");
123
124   if (hiphen.empty()) {
125     // consider one res
126     int num = 0;
127     try {
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_);
131   } else {
132     // consider a range of multiple res
133     int left = 0;
134     int right = 0;
135     try {
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_);
144     }
145   }
146 }
147
148
149 }  // namespace dialektos
150
151 #endif