OSDN Git Service

26fdb252985049c5c07565b98ed4741ec3d842b3
[fukui-no-namari/dialektos.git] / src / thread_list_model.cxx
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 #include "thread_list_model.hxx"
22
23 #include <gtkmm/treemodel.h>
24 #include <gtkmm/treepath.h>
25 #include <boost/mpl/size.hpp>
26 #include <boost/mpl/for_each.hpp>
27 #include <boost/mpl/find.hpp>
28 #include <boost/mpl/pop_front.hpp>
29 #include <boost/foreach.hpp>
30 #include <boost/integer_traits.hpp>
31
32
33 namespace dialektos {
34
35 namespace model_column {
36
37 struct GetColumnData {
38   GetColumnData(
39       const ModelColumns& model_columns,
40       size_t index,
41       Glib::ValueBase& data)
42   : index_(index), model_columns_(model_columns), data_(data) {
43         assert(index < unsigned(boost::mpl::size<ModelColumns::type>::value));
44       }
45
46   template <typename TypeHolderT>
47   void operator()(const TypeHolderT& /*t*/) {
48     using namespace boost::mpl;
49     if (index_ == unsigned(find<ModelColumns::type, TypeHolderT>::type::pos::value)) {
50       Glib::Value<typename TypeHolderT::type> value;
51       value.init(Glib::Value<typename TypeHolderT::type>::value_type());
52
53       value.set(field<TypeHolderT>(model_columns_));
54       data_.init(Glib::Value<typename TypeHolderT::type>::value_type());
55       data_ = value;
56     }
57   }
58
59   const size_t index_;
60   const dialektos::ModelColumns& model_columns_;
61   Glib::ValueBase& data_;
62 };
63
64 struct GetColumnGType {
65   GetColumnGType(size_t index, GType& data) : index_(index), data_(data) {
66         assert(index < unsigned(boost::mpl::size<ModelColumns::type>::value));
67       }
68
69   template <typename TypeHolderT>
70   void operator()(const TypeHolderT& /*t*/) {
71     using namespace boost::mpl;
72     if (index_ == unsigned(find<ModelColumns::type, TypeHolderT>::type::pos::value)) {
73       data_ = Glib::Value<typename TypeHolderT::type>::value_type();
74     }
75   }
76
77   const size_t index_;
78   GType& data_;
79 };
80
81 } // namespace model_column
82
83 namespace {
84 struct CompareNumber {
85   CompareNumber(boost::unordered_map<std::string, ModelColumns>& cols) :
86     cols_(cols) {}
87
88   bool operator()(const std::string& lhs, const std::string& rhs) const {
89     boost::unordered_map<std::string, ModelColumns>::const_iterator it = cols_.find(lhs);
90     assert(it != cols_.end());
91     const ModelColumns& left_cols = it->second;
92
93     it = cols_.find(rhs);
94     assert(it != cols_.end());
95     const ModelColumns& right_cols = it->second;
96
97     int left_num = model_column::field<model_column::Number>(left_cols);
98     int right_num = model_column::field<model_column::Number>(right_cols);
99
100     if (left_num == 0) left_num = boost::integer_traits<int>::const_max;
101     if (right_num == 0) right_num = boost::integer_traits<int>::const_max;
102
103     return left_num < right_num;
104   }
105   boost::unordered_map<std::string, ModelColumns>& cols_;
106 };
107 }
108
109
110 Glib::RefPtr<ThreadListModel> ThreadListModel::create() {
111   return Glib::RefPtr<ThreadListModel>(new ThreadListModel());
112 }
113
114 ThreadListModel::ThreadListModel():
115   Glib::ObjectBase(typeid(ThreadListModel)),
116   Glib::Object(),
117   list_(), order_() {
118 }
119
120 ThreadListModel::~ThreadListModel() {}
121
122 void ThreadListModel::append(const ModelColumns& record) {
123   const model_column::ID::type& id = model_column::field<model_column::ID>(record);
124   StoreType::iterator it = list_.find(id);
125   if (it != list_.end()) {
126     list_[id] = record;
127   } else {
128     list_[id] = record;
129     order_.push_back(model_column::field<model_column::ID>(record));
130
131     const size_t index = list_.size() -1;
132     iterator iter;
133     iter.gobj()->stamp = 1;
134     iter.gobj()->user_data = GINT_TO_POINTER(index);
135     iter.gobj()->user_data2 = 0;
136     iter.gobj()->user_data3 = 0;
137
138     Gtk::TreeModel::Path path;
139     path.append_index(index);
140     row_inserted(path, iter);
141   }
142 }
143
144 void ThreadListModel::set_buffer(
145     const boost::unordered_map<model_column::ID::type, ModelColumns>& buffer) {
146
147   // remove all rows
148   for(size_t i = 0; i != list_.size(); i++) {
149     Gtk::TreeModel::Path path;
150     path.append_index(0);
151     row_deleted(path);
152   }
153
154   list_ = StoreType();
155   order_ = OrderType();
156
157   typedef std::pair<model_column::ID::type, ModelColumns> PairType;
158   BOOST_FOREACH(const PairType& pair, buffer) {
159     const ModelColumns& cols = pair.second;
160     append(cols);
161   }
162
163   boost::unordered_map<std::string, int> old_order;
164   for (size_t i = 0; i != order_.size(); ++i) old_order[order_[i]] = i;
165
166   std::sort(order_.begin(), order_.end(), CompareNumber(list_));
167
168   std::vector<int> new_order;
169   new_order.reserve(order_.size());
170
171   BOOST_FOREACH(const std::string& id, order_) {
172     new_order.push_back(old_order[id]);
173   }
174
175   if (!new_order.empty())
176     rows_reordered(Gtk::TreeModel::Path(), &(new_order[0]));
177 }
178
179 void ThreadListModel::get_buffer(
180     boost::unordered_map<model_column::ID::type, ModelColumns>& buffer) const {
181   buffer = list_;
182 }
183
184 const ModelColumns& ThreadListModel::get_model_columns(const size_t row_index) const {
185   assert(row_index < list_.size());
186
187   const std::string& id = order_[row_index];
188   StoreType::const_iterator it = list_.find(id);
189
190   assert(it != list_.end());
191
192   return it->second;
193 }
194
195 void ThreadListModel::update_row(const ModelColumns& record) {
196   const model_column::ID::type& id = model_column::field<model_column::ID>(record);
197
198   StoreType::iterator it = list_.find(id);
199   if (it != list_.end()) {
200     model_column::field<model_column::Title>(it->second) =
201       model_column::field<model_column::Title>(record);
202     model_column::field<model_column::LineCount>(it->second) =
203       model_column::field<model_column::LineCount>(record);
204     OrderType::iterator jt = std::find(order_.begin(), order_.end(), id);
205     if (jt != order_.end()) {
206       const size_t row_index = std::distance(order_.begin(), jt);
207       Gtk::TreePath path;
208       path.append_index(row_index);
209       iterator iter;
210       iter.set_stamp(1);
211       iter.gobj()->user_data = GINT_TO_POINTER(row_index);
212       row_changed(path, iter);
213     }
214   } else {
215     append(record);
216   }
217 }
218
219
220 GType ThreadListModel::get_column_type_vfunc(const int index) const {
221   assert(index >= 0 && index < boost::mpl::size<ModelColumns::type>::value);
222
223   GType value = 0;
224   model_column::GetColumnGType functor(index, value);
225   boost::mpl::for_each<ModelColumns::type>(functor);
226   return value;
227 }
228
229 Gtk::TreeModelFlags ThreadListModel::get_flags_vfunc() const {
230   return Gtk::TREE_MODEL_LIST_ONLY;
231 }
232
233 int ThreadListModel::get_n_columns_vfunc() const {
234   return boost::mpl::size<ModelColumns::type>::value;
235 }
236
237 bool ThreadListModel::get_iter_vfunc(const Gtk::TreeModel::Path& path, iterator& iter) const {
238   assert(path.get_depth() == 1); // no children.
239
240   iter = iterator();
241
242   if (path.empty()) return false;
243
244   const size_t index = path.front();
245
246   if (index >= list_.size()) return false;
247
248   iter.set_stamp(1);
249   iter.gobj()->user_data = GINT_TO_POINTER(index);
250
251   return true;
252 }
253
254 Gtk::TreeModel::Path ThreadListModel::get_path_vfunc(const iterator& iter) const {
255   const GtkTreeIter* gtktreeiter = iter.gobj();
256   const size_t index = GPOINTER_TO_INT(gtktreeiter->user_data);
257
258   Gtk::TreeModel::Path path;
259   path.append_index(index);
260   return path;
261 }
262
263 void ThreadListModel::get_value_vfunc(const iterator& iter, const int column,
264     Glib::ValueBase& value) const {
265
266   if (iter.get_stamp() != 1) return;
267   if (column >= boost::mpl::size<model_column::List>::value) return;
268
269   const size_t index = GPOINTER_TO_INT(iter.gobj()->user_data);
270   if (index >= order_.size()) return;
271
272   const std::string& id = order_[index];
273
274   StoreType::const_iterator it = list_.find(id);
275   assert(it != list_.end());
276
277   const ModelColumns& record = it->second;
278   model_column::GetColumnData functor(record, column, value);
279   boost::mpl::for_each<model_column::List>(functor);
280 }
281
282 bool ThreadListModel::iter_children_vfunc(const iterator& parent,
283     iterator& iter) const {
284   return iter_nth_child_vfunc(parent, 0, iter);
285 }
286
287 bool ThreadListModel::iter_has_child_vfunc(const iterator& iter) const {
288   return false;
289 }
290
291 bool ThreadListModel::iter_is_valid(const iterator& iter) const {
292   return iter.gobj()->stamp == 1 && Gtk::TreeModel::iter_is_valid(iter);
293 }
294
295 int ThreadListModel::iter_n_children_vfunc(const iterator& iter) const {
296   return 0;
297 }
298
299 int ThreadListModel::iter_n_root_children_vfunc() const {
300   return list_.size();
301 }
302
303 bool ThreadListModel::iter_next_vfunc(const iterator& iter, iterator& iter_next) const {
304   iter_next = iterator();
305
306   if (iter.get_stamp() != 1) return false;
307
308   size_t index = GPOINTER_TO_INT(iter.gobj()->user_data);
309   ++index;
310
311   if (index >= list_.size()) return false;
312
313   iter_next.gobj()->stamp = 1;
314   iter_next.gobj()->user_data = GINT_TO_POINTER(index);
315
316   return true;
317 }
318
319 bool ThreadListModel::iter_nth_child_vfunc(const iterator& parent, int n,
320     iterator& iter) const {
321   iter = iterator();
322   return false;
323 }
324
325 bool ThreadListModel::iter_nth_root_child_vfunc(int n, iterator& iter) const {
326   if (unsigned(n) >= list_.size()) return false;
327
328   const unsigned int row_index = n;
329   iter = iterator();
330   iter.set_stamp(1);
331   iter.gobj()->user_data = GINT_TO_POINTER(row_index);
332   return true;
333 }
334
335 bool ThreadListModel::iter_parent_vfunc(const iterator& child, iterator& iter) const {
336   iter = iterator();
337   return false;
338 }
339
340
341 } // namespace dialektos