OSDN Git Service

Set window title.
[fukui-no-namari/dialektos.git] / src / board_window.cxx
index 949ce5f..acd4095 100644 (file)
@@ -22,6 +22,8 @@
 
 #include <glibmm/ustring.h>
 #include <glibmm/refptr.h>
+#include <sigc++/functors/mem_fun.h>
+#include <sigc++/signal.h>
 
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/lexical_cast.hpp>
 #include "board_subject_item.hxx"
 #include "thread_idx_cache.hxx"
 #include "uri_opener.hxx"
+#include "http_get.hxx"
+#include "board_subject_idx.hxx"
+#include "http_date.hxx"
+#include "misc.hxx"
 
 
 namespace dialektos {
@@ -53,7 +59,9 @@ void BoardWindow::create(std::auto_ptr<bbs_detail::Base> bbs) {
 
 BoardWindow::BoardWindow(std::auto_ptr<bbs_detail::Base> bbs) :
   ApplicationFrameWork(), tree_view_(), bbs_(bbs), scrolled_(),
-  tree_model_(ThreadListModel::create()) {
+  tree_model_(ThreadListModel::create()),
+  http_getter_()
+  {
 
   // additional menuitems for board window
   action_group_->add(Gtk::Action::create("FileOpen", "_Open Thread"),
@@ -104,6 +112,8 @@ BoardWindow::BoardWindow(std::auto_ptr<bbs_detail::Base> bbs) :
   std::cout <<
   to_simple_string(microsec_clock::local_time() - start) << std::endl;
 
+  set_title(get_uri());
+
   show_all();
 }
 
@@ -121,10 +131,19 @@ void BoardWindow::on_row_activated(const Gtk::TreeModel::Path& path,
   uri_opener::open(uri);
 }
 
+void BoardWindow::on_action_view_stop() {
+  if (http_getter_) http_getter_->cancel();
+}
+
 bool BoardWindow::is_same(const bbs_detail::Base& bbs) const {
   return *bbs_ == bbs;
 }
 
+std::string BoardWindow::get_uri() const {
+  return bbs_->get_board_uri();
+}
+
+
 void BoardWindow::load() {
   boost::unordered_map<model_column::ID::type, ModelColumns> buffer;
 
@@ -142,29 +161,30 @@ void BoardWindow::load() {
     buffer[cache.id_] = cols;
   }
 
-  merge_subject_txt(buffer);
+  const boost::filesystem::path sbj(bbs_->get_board_subject_path());
+  if (boost::filesystem::exists(sbj) && boost::filesystem::is_regular(sbj)) {
+    std::vector<SubjectItem> subjects;
+    bbs_->load_subject(subjects);
+
+    idx_ = SubjectIdx::from_xml(
+        boost::filesystem::path(bbs_->get_board_subject_idx_path()));
+
+    merge_subject_txt(subjects, buffer);
+  }
+
   tree_model_->set_buffer(buffer);
 }
 
 void BoardWindow::merge_subject_txt(
+    const std::vector<SubjectItem>& subjects,
     boost::unordered_map<std::string, ModelColumns>& buffer) {
-  const boost::filesystem::path sbj(bbs_->get_board_subject_path());
 
-  if (!boost::filesystem::exists(sbj) || !boost::filesystem::is_regular(sbj))
-    return;
-
-  std::vector<SubjectItem> subjects;
-  bbs_->load_subject(subjects);
-
-
-  // TODO use the last modified from a server.
   boost::posix_time::ptime last_modified;
   try {
-     std::time_t last_mod = boost::filesystem::last_write_time(sbj);
-     last_modified = boost::posix_time::from_time_t(last_mod);
-  } catch (const boost::filesystem::filesystem_error& e) {
+    last_modified = rfc1123_to_ptime(idx_.last_modified_);
+  } catch (const HTTPDateError& e) {
     std::cerr << e.what() << std::endl;
-    last_modified = boost::posix_time::second_clock::local_time();
+    last_modified = boost::posix_time::second_clock::universal_time();
   }
 
   BOOST_FOREACH(const SubjectItem& item, subjects) {
@@ -183,14 +203,105 @@ void BoardWindow::merge_subject_txt(
       const double average = item.res_num_ / (sec/60.0/60.0/24.0);
       model_column::field<model_column::Average>(cols) = average;
     } catch(const boost::bad_lexical_cast& e) {
-      std::cerr << e.what() << std::endl;
+      std::cerr << e.what() << "(" << item.id_ << ")" << std::endl;
     }
   }
 }
 
+void BoardWindow::unmerge_subject_txt(
+    boost::unordered_map<std::string, ModelColumns>& buffer) {
+  // remove thread ids which line_count_ is zero.
+  std::list<std::string> remove_list;
+  typedef boost::unordered_map<std::string, ModelColumns>::value_type PairType;
+  BOOST_FOREACH(PairType& pair, buffer) {
+    ModelColumns& cols = pair.second;
+    if (model_column::field<model_column::LineCount>(cols) == 0)
+      remove_list.push_back(pair.first);
+    else if (model_column::field<model_column::Number>(cols) != 0) {
+      model_column::field<model_column::Number>(cols) = 0;
+      model_column::field<model_column::ResNum>(cols) = 0;
+      model_column::field<model_column::Average>(cols) = 0;
+    }
+  }
+  BOOST_FOREACH(const std::string& id, remove_list)
+    buffer.erase(id);
+}
+
 void BoardWindow::on_action_file_open() {
   std::cout << "file open activated" << std::endl;
 }
 
+void BoardWindow::on_action_view_refresh() {
+  if (http_getter_) return;
+
+  statusbar_.push("HTTP/1.0 GET...");
+
+  const std::string uri = bbs_->get_board_subject_uri();
+  http::Header request_header = bbs_->get_board_subject_request_header();
+
+  SubjectIdx idx = SubjectIdx::from_xml(
+      boost::filesystem::path(bbs_->get_board_subject_idx_path()));
+  request_header.set_if_modified_since(idx.last_modified_);
+
+  http_getter_.reset(new http::GetInThread(uri, request_header));
+  http_getter_->signal_end().connect(
+      sigc::mem_fun(*this, &BoardWindow::on_http_get_end));
+  http_getter_->run();
+}
+
+void BoardWindow::save_content(const http::Response& response) {
+  // save the content to the file subject.txt
+  if (!misc::create_directories(boost::filesystem::path(
+          bbs_->get_board_subject_path()).parent_path())) return;
+  std::ofstream ofs(bbs_->get_board_subject_path().c_str());
+  ofs << response.get_content();
+  ofs.close();
+
+  // save the metadata to the file subject.xml
+  idx_.last_modified_ = response.get_header().get_last_modified();
+  idx_.to_xml(boost::filesystem::path(bbs_->get_board_subject_idx_path()));
+}
+
+void BoardWindow::on_http_get_end(bool success) {
+//  const std::string uri = http_getter_->get_uri();
+//  const http::Header request_header = http_getter_->get_request_header();
+  const http::Response response = http_getter_->get_response();
+  const boost::system::error_code err = http_getter_->get_error();
+  http_getter_.reset(0);
+  if (err) {
+    statusbar_.push(err.message());
+    return;
+  }
+  if (!success) {
+    statusbar_.push("Canceled.");
+    return;
+  }
+
+  on_refresh_end(response.get_status_line(), response.get_header());
+
+  std::vector<SubjectItem> subjects;
+  bbs_->load_subject_from_string(response.get_content(), subjects);
+
+  if (subjects.empty()) return;
+
+  save_content(response);
+
+  boost::unordered_map<std::string, ModelColumns> buffer;
+  tree_model_->get_buffer(buffer);
+  unmerge_subject_txt(buffer);
+  merge_subject_txt(subjects, buffer);
+  tree_model_->set_buffer(buffer);
+}
+
+void BoardWindow::on_refresh_end(const http::StatusLine& status,
+    const http::Header& header) {
+  std::string message = status.get_line();
+  const std::string last_modified = header.get_last_modified();
+  if (!last_modified.empty()) {
+    message += " ";
+    message += last_modified;
+  }
+  statusbar_.push(message);
+}
 
 } // namespace dialektos