OSDN Git Service

States of windows are saved and restored.
[fukui-no-namari/dialektos.git] / src / thread_window.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_window.hxx"
22
23 #include <glibmm/convert.h>
24 #include <gtkmm/stock.h>
25 #include <boost/date_time/posix_time/posix_time.hpp>
26 #include <boost/filesystem.hpp>
27 #include <iostream>
28 #include <fstream>
29 #include "bbs_detail_base.hxx"
30 #include "thread_idx.hxx"
31 #include "http_get.hxx"
32 #include "misc.hxx"
33 #include "uri_opener.hxx"
34 #include "thread_window_state.hxx"
35
36
37 namespace dialektos {
38
39
40 void ThreadWindow::create(std::auto_ptr<bbs_detail::Base> bbs) {
41   regist(new ThreadWindow(bbs));
42 }
43
44 ThreadWindow::ThreadWindow(std::auto_ptr<bbs_detail::Base> bbs) :
45   SuperClass(),
46   text_view_(new text_view::TextView),
47   scrolled_(text_view_->get_adjustment()),
48   bbs_(bbs), http_getter_(), idx_() {
49
50   // additional menuitems for board window
51   action_group_->add(Gtk::Action::create("FileDelete", Gtk::Stock::DELETE),
52       sigc::mem_fun(*this, &ThreadWindow::on_action_file_delete));
53   action_group_->add(
54       Gtk::Action::create("FileBoard", Gtk::Stock::GO_UP, "Show _Board"),
55       sigc::mem_fun(*this, &ThreadWindow::on_action_file_board));
56
57   Glib::ustring ui =
58     "<ui>"
59     "  <menubar name='MenuBar'>"
60     "    <menu action='MenuFile'>"
61     "      <menuitem action='FileDelete'/>"
62     "      <separator/>"
63     "      <menuitem action='FileBoard'/>"
64     "    </menu>"
65     "  </menubar>"
66     "</ui>";
67
68   ui_manager_->add_ui_from_string(ui);
69
70   scrolled_.add(*text_view_);
71   add(scrolled_);
72
73   text_view_->signal_button_press_event().connect_notify(
74       sigc::mem_fun(*this, &ThreadWindow::on_child_button_press));
75
76   ThreadWindowState state;
77   state.from_xml(boost::filesystem::path(bbs_->get_thread_state_path()));
78   set_default_size(state.width, state.height);
79   if (state.menubar) menubar_->show();
80   if (state.toolbar) toolbar_->show();
81   if (state.statusbar) statusbar_.show();
82
83   show_all();
84
85   load();
86   text_view_->jump_to_res_num(state.displayed_res_num);
87 }
88
89 bool ThreadWindow::load() {
90   using namespace boost::posix_time;
91   ptime start = microsec_clock::local_time();
92
93   if (bbs_) {
94
95     bbs_->load_thread(*text_view_);
96     text_view_->relayout();
97     text_view_->queue_draw();
98
99     std::cout <<
100     to_simple_string(microsec_clock::local_time() - start) << std::endl;
101
102     idx_ = ThreadIdx::from_xml(bbs_->get_thread_idx_path());
103     set_title(idx_.title_);
104   }
105
106   return false;
107 }
108
109 bool ThreadWindow::is_same(const bbs_detail::Base& bbs) const {
110   const bbs_detail::Base& lhs = *bbs_;
111   return lhs == bbs;
112 }
113
114 std::string ThreadWindow::get_uri() const {
115   return bbs_->get_thread_uri();
116 }
117
118
119 void ThreadWindow::on_action_view_refresh() {
120   if (http_getter_) return;
121
122   statusbar_.push("HTTP/1.0 GET...");
123
124   const std::string uri = bbs_->get_thread_dat_uri();
125   http::Header request_header = bbs_->get_thread_dat_request_header();
126   if (!request_header.get_range().empty()) {
127     request_header.set_if_modified_since(idx_.last_modified_);
128     request_header.set_if_none_match(idx_.etag_);
129   }
130
131   http_getter_.reset(new http::GetInThread(uri, request_header));
132   http_getter_->signal_end().connect(
133       sigc::mem_fun(*this, &ThreadWindow::on_http_get_end));
134   http_getter_->run();
135 }
136
137 void ThreadWindow::on_action_view_stop() {
138   if (http_getter_) http_getter_->cancel();
139 }
140
141 void ThreadWindow::on_action_file_delete() {
142   const boost::filesystem::path dat(bbs_->get_thread_file_path());
143   try {
144     if (boost::filesystem::exists(dat)) boost::filesystem::remove(dat);
145   } catch (const boost::filesystem::filesystem_error& e) {
146     std::cerr << e.what() << std::endl;
147   }
148
149   const boost::filesystem::path xml(bbs_->get_thread_idx_path());
150   try {
151     if (boost::filesystem::exists(xml)) boost::filesystem::remove(xml);
152   } catch (const boost::filesystem::filesystem_error& e) {
153     std::cerr << e.what() << std::endl;
154   }
155 }
156
157 void ThreadWindow::on_action_file_board() {
158   uri_opener::open(bbs_->get_board_uri());
159 }
160
161 void ThreadWindow::on_http_get_end(bool success) {
162 //  const std::string uri = http_getter_->get_uri();
163 //  const http::Header request_header = http_getter_->get_request_header();
164   const http::Response response = http_getter_->get_response();
165   const boost::system::error_code err = http_getter_->get_error();
166   http_getter_.reset(0);
167   if (err) {
168     statusbar_.push(err.message());
169     return;
170   }
171   if (!success) {
172     statusbar_.push("Canceled.");
173     return;
174   }
175
176   on_refresh_end(response.get_status_line(), response.get_header());
177
178   const int code = response.get_status_line().get_code();
179   if (code != 200 && code != 206) return;
180
181   if (code == 200) {
182     // initialize text_view_
183     scrolled_.remove(*text_view_);
184     text_view_.reset(new text_view::TextView);
185     scrolled_.set_adjustment(text_view_->get_adjustment());
186     scrolled_.add(*text_view_);
187
188     text_view_->signal_button_press_event().connect_notify(
189         sigc::mem_fun(*this, &ThreadWindow::on_child_button_press));
190     text_view_->show();
191   }
192
193   bbs_->load_thread_from_string(response.get_content(), *text_view_);
194   text_view_->relayout();
195   text_view_->queue_draw();
196
197   save_content(response);
198 }
199
200 void ThreadWindow::on_refresh_end(const http::StatusLine& status,
201     const http::Header& header) {
202   std::string message = status.get_line();
203   const std::string last_modified = header.get_last_modified();
204   if (!last_modified.empty()) {
205     message += " ";
206     message += last_modified;
207   }
208   statusbar_.push(message);
209 }
210
211 void ThreadWindow::save_content(const http::Response& response) {
212   const int code = response.get_status_line().get_code();
213   if (code != 200 && code != 206) return;
214
215   if (!misc::create_directories(boost::filesystem::path(
216       bbs_->get_thread_file_path()).parent_path())) return;
217   std::ofstream ofs(bbs_->get_thread_file_path().c_str(),
218       code == 200 ?
219           std::ios::out | std::ios::trunc : std::ios::out | std::ios::app);
220   ofs << response.get_content();
221   ofs.close();
222
223   if (code == 200) {
224     idx_.title_ = bbs_->get_title_from_string(response.get_content());
225     set_title(idx_.title_);
226   }
227
228   idx_.last_modified_ = response.get_header().get_last_modified();
229   idx_.etag_ = response.get_header().get_etag();
230
231   idx_.line_count_ = text_view_->get_res_num();
232
233   idx_.to_xml(boost::filesystem::path(bbs_->get_thread_idx_path()));
234 }
235
236 void ThreadWindow::save_state() const {
237   ThreadWindowState state;
238   state.width = get_width();
239   state.height = get_height();
240   state.menubar = menubar_->is_visible();
241   state.toolbar = toolbar_->is_visible();
242   state.statusbar = statusbar_.is_visible();
243   state.displayed_res_num = text_view_->get_displayed_res_num();
244   state.to_xml(boost::filesystem::path(bbs_->get_thread_state_path()));
245 }
246
247 } // namespace dialektos