OSDN Git Service

Reimprement regist and unregist a window to session.
authorAiwota Programmer <aiwotaprog@tetteke.tk>
Sat, 2 Sep 2006 17:57:31 +0000 (02:57 +0900)
committerAiwota Programmer <aiwotaprog@tetteke.tk>
Sat, 2 Sep 2006 17:57:31 +0000 (02:57 +0900)
Add saving and restoring the window state.

src/FukuiNoNamari/board_window.py
src/FukuiNoNamari/config.py
src/FukuiNoNamari/misc.py
src/FukuiNoNamari/session.py
src/FukuiNoNamari/thread_window.py
src/FukuiNoNamari/threadlistmodel.py
src/FukuiNoNamari/winwrapbase.py [new file with mode: 0644]

index dca86c4..a597538 100644 (file)
@@ -23,6 +23,7 @@ import os
 import time
 import gobject
 import gconf
+import traceback
 
 import board_data
 import uri_opener
@@ -31,6 +32,7 @@ from threadlistmodel import ThreadListModel
 from BbsType import bbs_type_judge_uri
 import config
 import session
+import winwrapbase
 
 GLADE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                          "..", "data")
@@ -48,11 +50,10 @@ def open_board(uri, update=False):
             winwrap.load(update)
     else:
         winwrap = WinWrap(uri)
-        session.window_created(uri, winwrap)
         winwrap.load(update)
 
 
-class WinWrap:
+class WinWrap(winwrapbase.WinWrapBase):
 
     def __init__(self, uri):
 
@@ -119,38 +120,29 @@ class WinWrap:
                   "on_popup_menu_open_activate": self.on_open_thread}
         self.widget_tree.signal_autoconnect(sigdic)
 
-        self.gconf_client = gconf.client_get_default()
-        self.gconf_key_base = "/apps/" + config.APPNAME.lower() + \
-                              "/board_states/"
+        self.restore()
+        self.window.show()
 
-        width = self.gconf_client.get_int(
-            self.gconf_key_base + "window_width")
-        height = self.gconf_client.get_int(
-            self.gconf_key_base + "window_height")
-        self.window.set_default_size(width, height)
+        self.created()
 
-        self.window.show()
+    def destroy(self):
+        self.save()
+        self.window.destroy()
 
-        if not self.gconf_client.get_bool(self.gconf_key_base + "toolbar"):
-            self.toolbar.parent.hide()
-        if not self.gconf_client.get_bool(self.gconf_key_base + "statusbar"):
-            self.statusbar.hide()
+    def get_uri(self):
+        return self.bbs_type.get_uri_base()
 
     def on_toolbar_activate(self, widget):
         if self.toolbar.parent.get_property("visible"):
             self.toolbar.parent.hide()
-            self.gconf_client.set_bool(self.gconf_key_base + "toolbar", False)
         else:
             self.toolbar.parent.show()
-            self.gconf_client.set_bool(self.gconf_key_base + "toolbar", True)
 
     def on_statusbar_activate(self, widget):
         if self.statusbar.get_property("visible"):
             self.statusbar.hide()
-            self.gconf_client.set_bool(self.gconf_key_base+"statusbar", False)
         else:
             self.statusbar.show()
-            self.gconf_client.set_bool(self.gconf_key_base + "statusbar", True)
 
     def updated_thread_highlight(self, column, cell, model, iter):
 
@@ -189,20 +181,17 @@ class WinWrap:
                 "%Y/%m/%d(%a) %H:%M:%S", time.localtime(lastmod)))
 
     def on_board_window_delete_event(self, widget, event):
-        w, h = widget.get_size()
-        self.gconf_client.set_int(self.gconf_key_base + "window_width", w)
-        self.gconf_client.set_int(self.gconf_key_base + "window_height", h)
-
+        self.save()
         return False
 
     def on_board_window_destroy(self, widget):
-        pass
+        self.destroyed()
 
     def on_quit_activate(self, widget):
         session.main_quit()
 
     def on_close_activate(self, widget):
-        self.window.destroy()
+        self.destroy()
 
     def on_refresh_activate(self, widget):
         t = board_data.GetRemote(
@@ -349,3 +338,140 @@ class WinWrap:
             t = board_data.LoadLocal(
                 self.bbs, self.board, self.update_datastore)
             t.start()
+
+    def save(self):
+        try:
+            states_path = misc.get_board_states_path(
+                self.bbs_type.bbs_type, self.bbs_type.board)
+            dirname = os.path.dirname(states_path)
+
+            # save only if board dir exists.
+            if os.path.exists(dirname):
+                window_width, window_height = self.window.get_size()
+                toolbar_visible = self.toolbar.parent.get_property("visible")
+                statusbar_visible = self.statusbar.get_property("visible")
+
+                columns = self.treeview.get_columns()
+                order = ""
+                width = ""
+                for column in columns:
+                    for name, kolumn in self.treeviewcolumn.iteritems():
+                        if column == kolumn:
+                            if order:
+                                order += ","
+                            order += name
+                            if width:
+                                width += ","
+                            width += str(column.get_width())
+                            break
+                sort_column_name, sort_reverse = \
+                                  self.treeview.get_model().get_sort()
+                sort_reverse = str(sort_reverse)
+
+                f = file(states_path, "w")
+
+                f.write("columns=" + order + "\n")
+                f.write("widths=" + width + "\n")
+                f.write("sort_column=" + sort_column_name + "\n")
+                f.write("sort_reverse=" + sort_reverse + "\n")
+                f.write("window_width=" + str(window_width) + "\n")
+                f.write("window_height=" + str(window_height) + "\n")
+                f.write("toolbar_visible=" + str(toolbar_visible) + "\n")
+                f.write("statusbar_visible=" + str(statusbar_visible) + "\n")
+
+                f.close()
+        except:
+            traceback.print_exc()
+
+    def restore(self):
+        try:
+            window_height = 600
+            window_width = 600
+            toolbar_visible = True
+            statusbar_visible = True
+
+            try:
+                key_base = config.gconf_app_key_base() + "/board_states"
+                gconf_client = gconf.client_get_default()
+                width = gconf_client.get_int(key_base + "/window_width")
+                height = gconf_client.get_int(key_base + "/window_height")
+                toolbar_visible = gconf_client.get_bool(
+                    key_base + "/toolbar")
+                statusbar_visible = gconf_client.get_bool(
+                    key_base + "/statusbar")
+                if width != 0:
+                    window_width = width
+                if height != 0:
+                    window_height = height
+            except:
+                traceback.print_exc()
+
+            states_path = misc.get_board_states_path(
+                self.bbs_type.bbs_type, self.bbs_type.board)
+            if os.path.exists(states_path):
+                sort_column_name = "num"
+                sort_reverse = False
+                for line in file(states_path):
+                    if line.startswith("columns="):
+                        line = line[len("columns="):].rstrip("\n")
+                        base_column = None
+                        for name in line.split(","):
+                            if name in self.treeviewcolumn:
+                                column = self.treeviewcolumn[name]
+                                self.treeview.move_column_after(
+                                    column, base_column)
+                                base_column = column
+                    elif line.startswith("widths="):
+                        line = line[len("widths="):].rstrip("\n")
+                        columns = self.treeview.get_columns()
+                        for i, width in enumerate(line.split(",")):
+                            try:
+                                width = int(width)
+                            except:
+                                pass
+                            else:
+                                if i < len(columns):
+                                    columns[i].set_fixed_width(width)
+                    elif line.startswith("sort_column="):
+                        kolumn_name = line[len("sort_column="):].rstrip("\n")
+                        if kolumn_name in ThreadListModel.column_names:
+                            sort_column_name = kolumn_name
+                    elif line.startswith("sort_reverse="):
+                        reverse = line[len("sort_reverse="):].rstrip("\n")
+                        sort_reverse = reverse == "True"
+                    elif line.startswith("window_height="):
+                        height = window_height
+                        try:
+                            height = int(
+                                line[len("window_height="):].rstrip("\n"))
+                        except:
+                            pass
+                        else:
+                            window_height = height
+                    elif line.startswith("window_width="):
+                        width = window_width
+                        try:
+                            width = int(
+                                line[len("window_width="):].rstrip("\n"))
+                        except:
+                            pass
+                        else:
+                            window_width = width
+                    elif line.startswith("toolbar_visible="):
+                        tbar = line[len("toolbar_visible="):].rstrip("\n")
+                        toolbar_visible = tbar == "True"
+                    elif line.startswith("statusbar_visible="):
+                        sbar = line[len("statusbar_visible="):].rstrip("\n")
+                        statusbar_visible = sbar == "True"
+
+                self.treeview.get_model().sort(
+                    sort_column_name, True, sort_reverse)
+
+            self.window.set_default_size(window_width, window_height)
+
+            if not toolbar_visible:
+                gobject.idle_add(self.toolbar.parent.hide)
+            if not statusbar_visible:
+                gobject.idle_add(self.statusbar.hide)
+        except:
+            traceback.print_exc()
index 05794ca..5bfce95 100644 (file)
@@ -21,3 +21,6 @@ APPNAME = "example-1.0"
 
 def get_config_dir_path():
     return os.path.expanduser("~/." + APPNAME.lower())
+
+def gconf_app_key_base():
+    return "/apps/" + APPNAME.lower()
index 08cb313..0382536 100644 (file)
@@ -47,6 +47,12 @@ def get_thread_idx_dir_path(bbs, board):
 
     return os.path.join(get_board_dir_path(bbs, board), "idx")
 
+def get_thread_states_dir_path(bbs, board):
+    if not bbs or not board:
+        raise ValueError, "parameter must not be empty"
+
+    return os.path.join(get_board_dir_path(bbs, board), "states")
+
 def get_thread_dat_path(bbs, board, thread):
     """Returns thread dat file path
 
@@ -91,6 +97,21 @@ def get_board_subjecttxt_path(bbs, board):
 
     return os.path.join(get_logs_dir_path(), bbs, board, "subject.txt")
 
+def get_thread_states_path(bbs, board, thread):
+    # if parameter is empty, raise ValueError
+    if not bbs or not board or not thread:
+        raise ValueError, "parameter must not be empty"
+
+    return os.path.join(get_thread_states_dir_path(bbs, board),
+                        thread + ".states")
+
+def get_board_states_path(bbs, board):
+    # if parameter is empty, raise ValueError
+    if not bbs or not board:
+        raise ValueError, "parameter must not be empty"
+
+    return os.path.join(get_board_dir_path(bbs, board), "board.states")
+
 def get_board_idx_path(bbs, board):
     """Returns board idx file path
 
index 9f97563..920e173 100644 (file)
@@ -20,40 +20,43 @@ pygtk.require('2.0')
 import gtk
 import gobject
 import gconf
+import traceback
 
 import uri_opener
 from BbsType import bbs_type_judge_uri
 from BbsType import bbs_type_exception
 import config
 
-_gconf_key_windows = "/apps/" + config.APPNAME + "/windows"
-
 # key: /bbs/board/thread value: toplevel window widget
 _windows = {}
 
 def get_window(key):
     if key in _windows:
-        return _windows[key]["winwrap"]
+        return _windows[key]
     else:
         return None
 
-def window_created(key, winwrap):
-    if not key or not winwrap:
+def regist(winwrap):
+    if not winwrap:
         raise ValueError, "parameter must not be empty"
 
+    key = winwrap.get_uri()
+    if not key:
+        raise ValueError, "uri must not be empty"
+
     if key in _windows:
         return False
-    handler_id = winwrap.window.connect("destroy", on_window_destroy, key)
-    _windows[key] = {"winwrap": winwrap, "handler_id": handler_id}
+
+    _windows[key] = winwrap
     print "regist to _windows", key
     return True
 
-def on_window_destroy(widget, key):
+def unregist(winwrap):
+    key = winwrap.get_uri()
     if key not in _windows:
+        print key, "is not found in _windows"
         return
 
-    do_on_window_destroy(key, get_window(key))
-
     del _windows[key]
     print "unregist from _windows", key
 
@@ -62,7 +65,7 @@ def on_window_destroy(widget, key):
         on_all_window_destroy()
 
 def on_all_window_destroy():
-    main_quit()
+    gtk.main_quit()
 
 def thread_idx_updated(thread_uri, idx_dic):
     if not thread_uri or not idx_dic:
@@ -76,36 +79,38 @@ def on_thread_idx_updated(thread_uri, idx_dic):
     if winwrap:
         winwrap.on_thread_idx_updated(thread_uri, idx_dic)
 
-def do_on_window_destroy(uri, winwrap):
-    print "window destroyed:", uri
-    
 def main_quit():
     print "session main quit"
 
     uris = _windows.keys()
     try:
         gconf_client = gconf.client_get_default()
+        gconf_key_windows = config.gconf_app_key_base() + "/windows"
         if uris:
             gconf_client.set_list(
-                _gconf_key_windows, gconf.VALUE_STRING, uris)
+                gconf_key_windows, gconf.VALUE_STRING, uris)
             print "save windows", uris
         else:
-            gconf_client.unset(_gconf_key_windows)
+            gconf_client.unset(gconf_key_windows)
             print "save no window"
     except:
         pass
 
-    for uri, value in _windows.iteritems():
-        value["winwrap"].window.disconnect(value["handler_id"])
-        value["winwrap"].window.destroy()
-        do_on_window_destroy(uri, value["winwrap"])
+    temp = dict(_windows)
+    for uri, winwrap in temp.iteritems():
+        try:
+            winwrap.destroy()
+        except:
+            traceback.print_exc()
 
+    # not reach here.
     gtk.main_quit()
 
 def restore():
     gconf_client = gconf.client_get_default()
 
-    uris = gconf_client.get_list(_gconf_key_windows, gconf.VALUE_STRING)
+    gconf_key_windows = config.gconf_app_key_base() + "/windows"
+    uris = gconf_client.get_list(gconf_key_windows, gconf.VALUE_STRING)
     for uri in uris:
         try:
             uri_opener.open_uri(uri)
index 42ba4b7..4dbbc03 100644 (file)
@@ -29,6 +29,7 @@ import gnome
 import gobject
 import threading
 import gconf
+import traceback
 
 import misc
 import datfile
@@ -41,6 +42,7 @@ from http_sub import HTTPRedirectHandler302
 from BbsType import bbs_type_judge_uri
 from BbsType import bbs_type_exception
 import config
+import winwrapbase
 
 GLADE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                          "..", "data")
@@ -64,7 +66,6 @@ def open_thread(uri, update=False):
             winwrap.load(update)
     else:
         winwrap = WinWrap(bbs_type.uri)  # pass original uri
-        session.window_created(uri, winwrap)
         winwrap.load(update)
 
     # jump to the res if necessary.
@@ -107,7 +108,7 @@ class FileWrap:
         return self._file
 
 
-class WinWrap:
+class WinWrap(winwrapbase.WinWrapBase):
     hovering_over_link = False
     hand_cursor = gtk.gdk.Cursor(gtk.gdk.HAND2)
     regular_cursor = gtk.gdk.Cursor(gtk.gdk.XTERM)
@@ -163,23 +164,17 @@ class WinWrap:
                               self.on_motion_notify_event)
         self.textview.connect("visibility-notify-event",
                               self.on_visibility_notify_event)
+        self.restore()
+        self.window.show()
 
-        self.gconf_client = gconf.client_get_default()
-        self.gconf_key_base = "/apps/" + config.APPNAME.lower() + \
-                              "/thread_states/"
+        self.created()
 
-        width = self.gconf_client.get_int(
-            self.gconf_key_base + "window_width")
-        height = self.gconf_client.get_int(
-            self.gconf_key_base + "window_height")
-        self.window.set_default_size(width, height)
+    def destroy(self):
+        self.save()
+        self.window.destroy()
 
-        self.window.show()
-
-        if not self.gconf_client.get_bool(self.gconf_key_base + "toolbar"):
-            self.toolbar.parent.hide()
-        if not self.gconf_client.get_bool(self.gconf_key_base + "statusbar"):
-            self.statusbar.hide()
+    def get_uri(self):
+        return self.bbs_type.get_thread_uri()
 
     def on_compose_clicked(self, widget):
         import submit_window
@@ -188,18 +183,14 @@ class WinWrap:
     def on_toolbar_activate(self, widget):
         if self.toolbar.parent.get_property("visible"):
             self.toolbar.parent.hide()
-            self.gconf_client.set_bool(self.gconf_key_base + "toolbar", False)
         else:
             self.toolbar.parent.show()
-            self.gconf_client.set_bool(self.gconf_key_base + "toolbar", True)
 
     def on_statusbar_activate(self, widget):
         if self.statusbar.get_property("visible"):
             self.statusbar.hide()
-            self.gconf_client.set_bool(self.gconf_key_base+"statusbar", False)
         else:
             self.statusbar.show()
-            self.gconf_client.set_bool(self.gconf_key_base + "statusbar", True)
 
     def on_event_after(self, widget, event):
         if event.type != gtk.gdk.BUTTON_RELEASE:
@@ -276,17 +267,14 @@ class WinWrap:
                 self.regular_cursor)
 
     def on_close_activate(self, widget):
-        self.window.destroy()
+        self.destroy()
 
     def on_thread_window_delete_event(self, widget, event):
-        w, h = widget.get_size()
-        self.gconf_client.set_int(self.gconf_key_base + "window_width", w)
-        self.gconf_client.set_int(self.gconf_key_base + "window_height", h)
-
+        self.save()
         return False
         
     def on_thread_window_destroy(self, widget):
-        -1
+        self.destroyed()
 
     def on_quit_activate(self, widget):
         session.main_quit()
@@ -561,3 +549,95 @@ class WinWrap:
             self.update()
         else:
             self.load_dat()
+
+    def save(self):
+        try:
+            states_path = misc.get_thread_states_path(
+                self.bbs_type.bbs_type, self.bbs_type.board,
+                self.bbs_type.thread)
+            dat_path = misc.get_thread_dat_path(
+                self.bbs_type.bbs_type, self.bbs_type.board,
+                self.bbs_type.thread)
+
+            # save only if dat file exists.
+            if os.path.exists(dat_path):
+                window_width, window_height = self.window.get_size()
+                toolbar_visible = self.toolbar.parent.get_property("visible")
+                statusbar_visible = self.statusbar.get_property("visible")
+
+                dirname = os.path.dirname(states_path)
+                if not os.path.isdir(dirname):
+                    os.makedirs(dirname)
+
+                f = file(states_path, "w")
+
+                f.write("window_width=" + str(window_width) + "\n")
+                f.write("window_height=" + str(window_height) + "\n")
+                f.write("toolbar_visible=" + str(toolbar_visible) + "\n")
+                f.write("statusbar_visible=" + str(statusbar_visible) + "\n")
+
+                f.close()
+        except:
+            traceback.print_exc()
+
+    def restore(self):
+        try:
+            window_height = 600
+            window_width = 600
+            toolbar_visible = True
+            statusbar_visible = True
+
+            try:
+                key_base = config.gconf_app_key_base() + "/thread_states"
+                gconf_client = gconf.client_get_default()
+                width = gconf_client.get_int(key_base + "/window_width")
+                height = gconf_client.get_int(key_base + "/window_height")
+                toolbar_visible = gconf_client.get_bool(
+                    key_base + "/toolbar")
+                statusbar_visible = gconf_client.get_bool(
+                    key_base + "/statusbar")
+                if width != 0:
+                    window_width = width
+                if height != 0:
+                    window_height = height
+            except:
+                traceback.print_exc()
+
+            states_path = misc.get_thread_states_path(
+                self.bbs_type.bbs_type, self.bbs_type.board,
+                self.bbs_type.thread)
+            if os.path.exists(states_path):
+                for line in file(states_path):
+                    if line.startswith("window_height="):
+                        height = window_height
+                        try:
+                            height = int(
+                                line[len("window_height="):].rstrip("\n"))
+                        except:
+                            pass
+                        else:
+                            window_height = height
+                    elif line.startswith("window_width="):
+                        width = window_width
+                        try:
+                            width = int(
+                                line[len("window_width="):].rstrip("\n"))
+                        except:
+                            pass
+                        else:
+                            window_width = width
+                    elif line.startswith("toolbar_visible="):
+                        tbar = line[len("toolbar_visible="):].rstrip("\n")
+                        toolbar_visible = tbar == "True"
+                    elif line.startswith("statusbar_visible="):
+                        sbar = line[len("statusbar_visible="):].rstrip("\n")
+                        statusbar_visible = sbar == "True"
+
+            self.window.set_default_size(window_width, window_height)
+
+            if not toolbar_visible:
+                gobject.idle_add(self.toolbar.parent.hide)
+            if not statusbar_visible:
+                gobject.idle_add(self.statusbar.hide)
+        except:
+            traceback.print_exc()
index 5030155..9840ee9 100644 (file)
@@ -111,15 +111,18 @@ class ThreadListModel(gtk.GenericTreeModel):
             self.list.sort(h, lambda dic: dic[column_name], reverse)
         self.build_order_dict()
 
-    def sort(self, column_name):
+    def sort(self, column_name, order_specified=False, reverse=False):
         old_order_dict = self.order_dict
 
-        if column_name == self.sort_column_name:
-            # sort reverse
-            self.sort_reverse = not self.sort_reverse
+        if order_specified:
+            self.sort_reverse = reverse
         else:
-            self.sort_column_name = column_name
-            self.sort_reverse = False
+            if column_name == self.sort_column_name:
+                # sort reverse
+                self.sort_reverse = not self.sort_reverse
+            else:
+                self.sort_reverse = False
+        self.sort_column_name = column_name
 
         self.do_sort(self.sort_column_name, self.sort_reverse)
 
diff --git a/src/FukuiNoNamari/winwrapbase.py b/src/FukuiNoNamari/winwrapbase.py
new file mode 100644 (file)
index 0000000..7bba504
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (C) 2006 by Aiwota Programmer
+# aiwotaprog@tetteke.tk
+#
+# This program 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 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+import session
+
+
+class WinWrapBase:
+
+    def destroy(self):
+        pass
+
+    def get_uri(self):
+        pass
+
+    def on_thread_idx_updated(self, uri, dict):
+        pass
+
+
+    def created(self):
+        session.regist(self)
+
+    def destroyed(self):
+        session.unregist(self)