#include <gtkmm/menu.h>
#include <gtkmm/uimanager.h>
#include <gtkmm/actiongroup.h>
+#include <boost/foreach.hpp>
#include <iostream>
#include "bookmark_window.hxx"
ApplicationWindow::add(vbox_);
build_menubar();
+ statusbar_.set_no_show_all(true);
}
ApplicationFrameWork::~ApplicationFrameWork() {}
ui_manager_->add_ui_from_string(ui_info);
menubar_ = ui_manager_->get_widget("/MenuBar");
+ menubar_->set_no_show_all(true);
+ menubar_->hide();
toolbar_ = ui_manager_->get_widget("/ToolBar");
+ toolbar_->set_no_show_all(true);
+ toolbar_->hide();
popupmenu_ =
dynamic_cast<Gtk::Menu*>(ui_manager_->get_widget("/MenuPopup"));
void ApplicationFrameWork::on_action_file_quit() {
save();
+ BOOST_FOREACH(const ApplicationWindow& window, windows)
+ window.save_state();
windows.clear();
Gtk::Main::quit();
}
bool ApplicationWindow::on_delete_event(GdkEventAny* /*event*/) {
using namespace boost::lambda;
// using boost::lambda::_1;
+ save_state();
windows.erase_if(&_1 == this);
if (!windows.empty()) save();
if (windows.empty()) Gtk::Main::quit();
virtual ~ApplicationWindow();
static bool is_opened(const bbs_detail::Base& bbs);
static void load();
+ virtual void save_state() const = 0;
protected:
ApplicationWindow();
static void regist(ApplicationWindow* window);
return xml.file_string();
}
+std::string Base::get_thread_state_path() const {
+ const boost::filesystem::path dir(get_board_dir_path());
+ const boost::filesystem::path xml = dir / "states" / (thread_ + ".xml");
+ return xml.file_string();
+}
std::string Base::get_thread_dat_uri() const {
return "http://" + host_ + "/" + board_ + "/dat/" + thread_ + ".dat";
return sbj.file_string();
}
+std::string Base::get_board_state_path() const {
+ boost::filesystem::path xml(get_board_dir_path());
+ xml = xml / "boardstate.xml";
+ return xml.file_string();
+}
+
std::string Base::get_board_subject_uri() const {
std::stringstream ss;
ss << boost::format("http://%1%/%2%/%3%")
virtual std::string get_board_dir_path() const;
virtual std::string get_thread_file_path() const;
virtual std::string get_thread_idx_path() const;
+ virtual std::string get_thread_state_path() const;
virtual std::string get_thread_dat_uri() const;
virtual std::string get_thread_uri() const;
virtual std::string get_another_thread_uri(const std::string& thread) const;
virtual std::string get_board_subject_path() const;
+ virtual std::string get_board_state_path() const;
virtual std::string get_board_subject_uri() const;
virtual std::string get_board_uri() const;
virtual std::string get_board_subject_idx_path() const;
#include <fstream>
#include <iostream>
#include <sstream>
+#include <vector>
+#include <algorithm>
#include "bbs_detail_base.hxx"
#include "thread_list_model.hxx"
#include "board_subject_idx.hxx"
#include "http_date.hxx"
#include "misc.hxx"
+#include "board_window_state.hxx"
namespace dialektos {
+namespace {
+struct LessSecond {
+ template <typename PairType>
+ bool operator()(const PairType& lhs, const PairType& rhs) const {
+ return lhs.second < rhs.second;
+ }
+};
+}
+
void BoardWindow::create(std::auto_ptr<bbs_detail::Base> bbs) {
regist(new BoardWindow(bbs));
tree_view_.signal_button_press_event().connect_notify(
sigc::mem_fun(*this, &BoardWindow::on_child_button_press));
- set_default_size(400,300);
scrolled_.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
add(scrolled_);
tree_view_.append_column(*Gtk::manage(new view_column::Average));
tree_view_.append_column(*Gtk::manage(new view_column::StartTime));
+ BoardWindowState state;
+ state.from_xml(boost::filesystem::path(bbs_->get_board_state_path()));
+
+ set_default_size(state.width, state.height);
+ if (state.menubar) menubar_->show();
+ if (state.toolbar) toolbar_->show();
+ if (state.statusbar) statusbar_.show();
+
+ // set columns widths
+ BOOST_FOREACH(Gtk::TreeViewColumn* column, tree_view_.get_columns()) {
+ BoardWindowState::ColumnInfo info = state.columns[column->get_title()];
+ if (info.width > 0) column->set_fixed_width(info.width);
+ }
+
+ // set columns order.
+ typedef std::pair<Gtk::TreeViewColumn*, int> PairType;
+ std::vector<PairType> column_order;
+ BOOST_FOREACH(Gtk::TreeViewColumn* column, tree_view_.get_columns()) {
+ BoardWindowState::ColumnInfo info = state.columns[column->get_title()];
+ column_order.push_back(std::make_pair(column, info.order));
+ }
+ std::sort(column_order.begin(), column_order.end(), LessSecond());
+
+ Gtk::TreeViewColumn* previous_column = 0;
+ BOOST_FOREACH(PairType& pair, column_order) {
+ if (!previous_column) tree_view_.move_column_to_start(*pair.first);
+ else tree_view_.move_column_after(*pair.first, *previous_column);
+ previous_column = pair.first;
+ }
+
using namespace boost::posix_time;
ptime start = microsec_clock::local_time();
statusbar_.push(message);
}
+void BoardWindow::save_state() const{
+ BoardWindowState state;
+ state.width = get_width();
+ state.height = get_height();
+ state.menubar = menubar_->is_visible();
+ state.toolbar = toolbar_->is_visible();
+ state.statusbar = statusbar_.is_visible();
+
+ int order = 0;
+ BOOST_FOREACH(const Gtk::TreeViewColumn* column, tree_view_.get_columns()) {
+ BoardWindowState::ColumnInfo info;
+ info.width = column->get_width();
+ info.order = order;
+ state.columns[column->get_title()] = info;
+ ++order;
+ }
+
+ state.to_xml(boost::filesystem::path(bbs_->get_board_state_path()));
+}
+
+
} // namespace dialektos
public:
static void create(std::auto_ptr<bbs_detail::Base> bbs);
virtual ~BoardWindow();
+ virtual void save_state() const;
protected:
BoardWindow(std::auto_ptr<bbs_detail::Base> bbs);
--- /dev/null
+/*
+ * Copyright (C) 2009 by Aiwota Programmer
+ * aiwotaprog@tetteke.tk
+ *
+ * This file is part of Dialektos.
+ *
+ * Dialektos is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dialektos is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dialektos. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "board_window_state.hxx"
+
+#include <boost/archive/xml_iarchive.hpp>
+#include <boost/archive/xml_oarchive.hpp>
+#include <boost/serialization/nvp.hpp>
+#include <boost/filesystem.hpp>
+#include <fstream>
+#include <iostream>
+
+
+namespace dialektos {
+
+
+BoardWindowState::BoardWindowState() :
+ width(400), height(300), menubar(true), toolbar(true), statusbar(true) {
+}
+
+void BoardWindowState::from_xml(const boost::filesystem::path& xml) {
+ if (!boost::filesystem::exists(xml) ||
+ !boost::filesystem::is_regular_file(xml))
+ return;
+
+ std::ifstream ifs(xml.file_string().c_str());
+ try {
+ boost::archive::xml_iarchive ia(ifs);
+ ia >> boost::serialization::make_nvp("BoardWindowState", *this);
+ } catch (const boost::archive::archive_exception& e) {
+ std::cerr << e.what() << " " << xml << std::endl;
+ }
+}
+
+void BoardWindowState::to_xml(const boost::filesystem::path& xml) {
+ // Do not save if subject.txt does not exist.
+ if (!boost::filesystem::exists(xml.parent_path() / "subject.txt")) return;
+ std::ofstream ofs(xml.file_string().c_str());
+ try {
+ boost::archive::xml_oarchive oa(ofs);
+ oa << boost::serialization::make_nvp("BoardWindowState", *this);
+ } catch (const boost::archive::archive_exception& e) {
+ std::cerr << e.what() << " " << xml << std::endl;
+ }
+}
+
+
+} // namespace dialektos
--- /dev/null
+/*
+ * Copyright (C) 2009 by Aiwota Programmer
+ * aiwotaprog@tetteke.tk
+ *
+ * This file is part of Dialektos.
+ *
+ * Dialektos is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dialektos is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dialektos. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef BOARD_WINDOW_STATE_HXX
+#define BOARD_WINDOW_STATE_HX_
+
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/nvp.hpp>
+#include <boost/serialization/map.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/filesystem/path.hpp>
+#include <map>
+#include <string>
+
+
+namespace dialektos {
+
+
+struct BoardWindowState {
+ struct ColumnInfo {
+ ColumnInfo() : width(0), order(-1) {}
+ int width;
+ unsigned int order;
+ private:
+ friend class boost::serialization::access;
+ template <typename ArchiveType>
+ void serialize(ArchiveType& ar, const unsigned int version) {
+ ar & boost::serialization::make_nvp("ColumnWidth", width);
+ ar & boost::serialization::make_nvp("ColumnOrder", order);
+ }
+ };
+
+ struct SortInfo {
+ SortInfo() : column("No."), ascendant(true) {}
+ std::string column;
+ bool ascendant;
+ private:
+ friend class boost::serialization::access;
+ template <typename ArchiveType>
+ void serialize(ArchiveType& ar, const unsigned int version) {
+ ar & boost::serialization::make_nvp("SortColumn", column);
+ ar & boost::serialization::make_nvp("SortOrder", ascendant);
+ }
+ };
+
+ BoardWindowState();
+
+ int width;
+ int height;
+ bool menubar;
+ bool toolbar;
+ bool statusbar;
+ std::map<std::string, ColumnInfo> columns;
+ SortInfo sort;
+
+ void from_xml(const boost::filesystem::path& xml);
+ void to_xml(const boost::filesystem::path& xml);
+
+private:
+ friend class boost::serialization::access;
+ template <typename ArchiveType>
+ void serialize(ArchiveType& ar, const unsigned int version) {
+ ar & boost::serialization::make_nvp("WindowWidth", width);
+ ar & boost::serialization::make_nvp("WindowHeight", height);
+ ar & boost::serialization::make_nvp("MenubarVisible", menubar);
+ ar & boost::serialization::make_nvp("ToolbarVisible", toolbar);
+ ar & boost::serialization::make_nvp("StatusbarVisible", statusbar);
+ ar & boost::serialization::make_nvp("Columns", columns);
+ ar & boost::serialization::make_nvp("SortColumn", sort);
+ }
+
+};
+
+
+} // namespace dialektos
+
+
+#endif
#include "text_view.hxx"
+#include <boost/foreach.hpp>
#include <iostream>
#include "text_line.hxx"
return 0;
}
+void TextView::jump_to_res_num(const int res_num) {
+ if (res_num < 1 || res_num > get_res_num()) return;
+
+ BOOST_FOREACH(TextLine& line, line_list_) {
+ const int res = line.get_res_num();
+ if (res_num == res) {
+ adjustment_.set_value(line.get_y());
+ break;
+ }
+ }
+}
+
void TextView::on_anchor_click_event(const text_element::Anchor& elem) {
std::cout << elem.get_href() << std::endl;
}
/*! @brief Gets the first number of res on the top of the widget. */
int get_displayed_res_num() const;
+ void jump_to_res_num(int res_num);
protected:
virtual void on_anchor_click_event(const text_element::Anchor& elem);
#include "http_get.hxx"
#include "misc.hxx"
#include "uri_opener.hxx"
+#include "thread_window_state.hxx"
namespace dialektos {
ui_manager_->add_ui_from_string(ui);
- set_default_size(400,300);
-
scrolled_.add(*text_view_);
add(scrolled_);
text_view_->signal_button_press_event().connect_notify(
sigc::mem_fun(*this, &ThreadWindow::on_child_button_press));
+ ThreadWindowState state;
+ state.from_xml(boost::filesystem::path(bbs_->get_thread_state_path()));
+ set_default_size(state.width, state.height);
+ if (state.menubar) menubar_->show();
+ if (state.toolbar) toolbar_->show();
+ if (state.statusbar) statusbar_.show();
+
show_all();
load();
+ text_view_->jump_to_res_num(state.displayed_res_num);
}
bool ThreadWindow::load() {
idx_.to_xml(boost::filesystem::path(bbs_->get_thread_idx_path()));
}
+void ThreadWindow::save_state() const {
+ ThreadWindowState state;
+ state.width = get_width();
+ state.height = get_height();
+ state.menubar = menubar_->is_visible();
+ state.toolbar = toolbar_->is_visible();
+ state.statusbar = statusbar_.is_visible();
+ state.displayed_res_num = text_view_->get_displayed_res_num();
+ state.to_xml(boost::filesystem::path(bbs_->get_thread_state_path()));
+}
} // namespace dialektos
static void create(std::auto_ptr<bbs_detail::Base> bbs);
bool load();
virtual ~ThreadWindow(){}
+ virtual void save_state() const;
protected:
ThreadWindow(std::auto_ptr<bbs_detail::Base> bbs);
--- /dev/null
+/*
+ * Copyright (C) 2009 by Aiwota Programmer
+ * aiwotaprog@tetteke.tk
+ *
+ * This file is part of Dialektos.
+ *
+ * Dialektos is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dialektos is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dialektos. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "thread_window_state.hxx"
+
+#include <boost/archive/xml_iarchive.hpp>
+#include <boost/archive/xml_oarchive.hpp>
+#include <boost/serialization/nvp.hpp>
+#include <boost/filesystem.hpp>
+#include <fstream>
+#include <iostream>
+#include <string>
+#include "misc.hxx"
+
+
+namespace dialektos {
+
+
+ThreadWindowState::ThreadWindowState() :
+ width(400), height(300), displayed_res_num(0),
+ menubar(true), toolbar(true), statusbar(true) {
+}
+
+void ThreadWindowState::from_xml(const boost::filesystem::path& xml) {
+ if (!boost::filesystem::exists(xml) ||
+ !boost::filesystem::is_regular_file(xml))
+ return;
+
+ std::ifstream ifs(xml.file_string().c_str());
+ try {
+ boost::archive::xml_iarchive ia(ifs);
+ ia >> boost::serialization::make_nvp("ThreadWindowState", *this);
+ } catch (const boost::archive::archive_exception& e) {
+ std::cerr << e.what() << " " << xml << std::endl;
+ }
+}
+
+void ThreadWindowState::to_xml(const boost::filesystem::path& xml) {
+ // do not save if corresponding dat file does not exist.
+ std::string leaf = xml.leaf();
+ boost::filesystem::path dat =
+ xml.parent_path().parent_path() /
+ "dat" / (leaf.substr(0, leaf.size() - 3) + "dat");
+ if (!boost::filesystem::exists(dat)) return;
+ if (!misc::create_directories(xml.parent_path())) return;
+ std::ofstream ofs(xml.file_string().c_str());
+ try {
+ boost::archive::xml_oarchive oa(ofs);
+ oa << boost::serialization::make_nvp("ThreadWindowState", *this);
+ } catch (const boost::archive::archive_exception& e) {
+ std::cerr << e.what() << " " << xml << std::endl;
+ }
+}
+
+
+} // namespace dialektos
--- /dev/null
+/*
+ * Copyright (C) 2009 by Aiwota Programmer
+ * aiwotaprog@tetteke.tk
+ *
+ * This file is part of Dialektos.
+ *
+ * Dialektos is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dialektos is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dialektos. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef THREAD_WINDOW_STATE_HXX
+#define THREAD_WINDOW_STATE_HXX
+
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/nvp.hpp>
+#include <boost/filesystem/path.hpp>
+
+
+namespace dialektos {
+
+
+struct ThreadWindowState {
+ ThreadWindowState();
+
+ int width;
+ int height;
+ int displayed_res_num;
+ bool menubar;
+ bool toolbar;
+ bool statusbar;
+
+ void from_xml(const boost::filesystem::path& xml);
+ void to_xml(const boost::filesystem::path& xml);
+
+private:
+ friend class boost::serialization::access;
+ template <typename ArchiveType>
+ void serialize(ArchiveType& ar, const unsigned int version) {
+ ar & boost::serialization::make_nvp("WindowWidth", width);
+ ar & boost::serialization::make_nvp("WindowHeight", height);
+ ar & boost::serialization::make_nvp("DisplayedResNum", displayed_res_num);
+ ar & boost::serialization::make_nvp("MenubarVisible", menubar);
+ ar & boost::serialization::make_nvp("ToolbarVisible", toolbar);
+ ar & boost::serialization::make_nvp("StatusbarVisible", statusbar);
+ }
+};
+
+
+} // namespace dialektos
+
+
+#endif