OSDN Git Service

Change idx sub dir's time stamp when saving idx.
[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 GType ThreadListModel::get_column_type_vfunc(const int index) const {
196   assert(index >= 0 && index < boost::mpl::size<ModelColumns::type>::value);
197
198   GType value = 0;
199   model_column::GetColumnGType functor(index, value);
200   boost::mpl::for_each<ModelColumns::type>(functor);
201   return value;
202 }
203
204 Gtk::TreeModelFlags ThreadListModel::get_flags_vfunc() const {
205   return Gtk::TREE_MODEL_LIST_ONLY;
206 }
207
208 int ThreadListModel::get_n_columns_vfunc() const {
209   return boost::mpl::size<ModelColumns::type>::value;
210 }
211
212 bool ThreadListModel::get_iter_vfunc(const Gtk::TreeModel::Path& path, iterator& iter) const {
213   assert(path.get_depth() == 1); // no children.
214
215   iter = iterator();
216
217   if (path.empty()) return false;
218
219   const size_t index = path.front();
220
221   if (index >= list_.size()) return false;
222
223   iter.set_stamp(1);
224   iter.gobj()->user_data = GINT_TO_POINTER(index);
225
226   return true;
227 }
228
229 Gtk::TreeModel::Path ThreadListModel::get_path_vfunc(const iterator& iter) const {
230   const GtkTreeIter* gtktreeiter = iter.gobj();
231   const size_t index = GPOINTER_TO_INT(gtktreeiter->user_data);
232
233   Gtk::TreeModel::Path path;
234   path.append_index(index);
235   return path;
236 }
237
238 void ThreadListModel::get_value_vfunc(const iterator& iter, const int column,
239     Glib::ValueBase& value) const {
240
241   if (iter.get_stamp() != 1) return;
242   if (column >= boost::mpl::size<model_column::List>::value) return;
243
244   const size_t index = GPOINTER_TO_INT(iter.gobj()->user_data);
245   if (index >= order_.size()) return;
246
247   const std::string& id = order_[index];
248
249   StoreType::const_iterator it = list_.find(id);
250   assert(it != list_.end());
251
252   const ModelColumns& record = it->second;
253   model_column::GetColumnData functor(record, column, value);
254   boost::mpl::for_each<model_column::List>(functor);
255 }
256
257 bool ThreadListModel::iter_children_vfunc(const iterator& parent,
258     iterator& iter) const {
259   return iter_nth_child_vfunc(parent, 0, iter);
260 }
261
262 bool ThreadListModel::iter_has_child_vfunc(const iterator& iter) const {
263   return false;
264 }
265
266 bool ThreadListModel::iter_is_valid(const iterator& iter) const {
267   return iter.gobj()->stamp == 1 && Gtk::TreeModel::iter_is_valid(iter);
268 }
269
270 int ThreadListModel::iter_n_children_vfunc(const iterator& iter) const {
271   return 0;
272 }
273
274 int ThreadListModel::iter_n_root_children_vfunc() const {
275   return list_.size();
276 }
277
278 bool ThreadListModel::iter_next_vfunc(const iterator& iter, iterator& iter_next) const {
279   iter_next = iterator();
280
281   if (iter.get_stamp() != 1) return false;
282
283   size_t index = GPOINTER_TO_INT(iter.gobj()->user_data);
284   ++index;
285
286   if (index >= list_.size()) return false;
287
288   iter_next.gobj()->stamp = 1;
289   iter_next.gobj()->user_data = GINT_TO_POINTER(index);
290
291   return true;
292 }
293
294 bool ThreadListModel::iter_nth_child_vfunc(const iterator& parent, int n,
295     iterator& iter) const {
296   iter = iterator();
297   return false;
298 }
299
300 bool ThreadListModel::iter_nth_root_child_vfunc(int n, iterator& iter) const {
301   if (unsigned(n) >= list_.size()) return false;
302
303   const unsigned int row_index = n;
304   iter = iterator();
305   iter.set_stamp(1);
306   iter.gobj()->user_data = GINT_TO_POINTER(row_index);
307   return true;
308 }
309
310 bool ThreadListModel::iter_parent_vfunc(const iterator& child, iterator& iter) const {
311   iter = iterator();
312   return false;
313 }
314
315
316 } // namespace dialektos