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 #include "thread_window.hxx"
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>
29 #include "bbs_detail_base.hxx"
30 #include "thread_idx.hxx"
31 #include "http_get.hxx"
33 #include "uri_opener.hxx"
34 #include "thread_window_state.hxx"
40 void ThreadWindow::create(std::auto_ptr<bbs_detail::Base> bbs) {
41 regist(new ThreadWindow(bbs));
44 ThreadWindow::ThreadWindow(std::auto_ptr<bbs_detail::Base> bbs) :
46 text_view_(new text_view::TextView),
47 scrolled_(text_view_->get_adjustment()),
48 bbs_(bbs), http_getter_(), idx_() {
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));
54 Gtk::Action::create("FileBoard", Gtk::Stock::GO_UP, "Show _Board"),
55 sigc::mem_fun(*this, &ThreadWindow::on_action_file_board));
59 " <menubar name='MenuBar'>"
60 " <menu action='MenuFile'>"
61 " <menuitem action='FileDelete'/>"
63 " <menuitem action='FileBoard'/>"
68 ui_manager_->add_ui_from_string(ui);
70 scrolled_.add(*text_view_);
73 text_view_->signal_button_press_event().connect_notify(
74 sigc::mem_fun(*this, &ThreadWindow::on_child_button_press));
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();
86 text_view_->jump_to_res_num(state.displayed_res_num);
89 bool ThreadWindow::load() {
90 using namespace boost::posix_time;
91 ptime start = microsec_clock::local_time();
95 bbs_->load_thread(*text_view_);
96 text_view_->relayout();
97 text_view_->queue_draw();
100 to_simple_string(microsec_clock::local_time() - start) << std::endl;
102 idx_ = ThreadIdx::from_xml(bbs_->get_thread_idx_path());
103 set_title(idx_.title_);
109 bool ThreadWindow::is_same(const bbs_detail::Base& bbs) const {
110 const bbs_detail::Base& lhs = *bbs_;
114 std::string ThreadWindow::get_uri() const {
115 return bbs_->get_thread_uri();
119 void ThreadWindow::on_action_view_refresh() {
120 if (http_getter_) return;
122 statusbar_.push("HTTP/1.0 GET...");
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_);
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));
137 void ThreadWindow::on_action_view_stop() {
138 if (http_getter_) http_getter_->cancel();
141 void ThreadWindow::on_action_file_delete() {
142 const boost::filesystem::path dat(bbs_->get_thread_file_path());
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;
149 const boost::filesystem::path xml(bbs_->get_thread_idx_path());
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;
157 void ThreadWindow::on_action_file_board() {
158 uri_opener::open(bbs_->get_board_uri());
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);
168 statusbar_.push(err.message());
172 statusbar_.push("Canceled.");
176 on_refresh_end(response.get_status_line(), response.get_header());
178 const int code = response.get_status_line().get_code();
179 if (code != 200 && code != 206) return;
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_);
188 text_view_->signal_button_press_event().connect_notify(
189 sigc::mem_fun(*this, &ThreadWindow::on_child_button_press));
193 bbs_->load_thread_from_string(response.get_content(), *text_view_);
194 text_view_->relayout();
195 text_view_->queue_draw();
197 save_content(response);
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()) {
206 message += last_modified;
208 statusbar_.push(message);
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;
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(),
219 std::ios::out | std::ios::trunc : std::ios::out | std::ios::app);
220 ofs << response.get_content();
224 idx_.title_ = bbs_->get_title_from_string(response.get_content());
225 set_title(idx_.title_);
228 idx_.last_modified_ = response.get_header().get_last_modified();
229 idx_.etag_ = response.get_header().get_etag();
231 idx_.line_count_ = text_view_->get_res_num();
233 idx_.to_xml(boost::filesystem::path(bbs_->get_thread_idx_path()));
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()));
247 } // namespace dialektos