OSDN Git Service

Add incremental search functions for summary or preview view.
[mave/mave.git] / mave_models.rb
index 0ac1c9a..52f06ec 100644 (file)
@@ -5,16 +5,45 @@ require 'digest/md5'
 
 #===============================================================================
 #
+#      ショートカットキークラス
+#
+class MaveShortcuts
+
+       @@rsv = 'zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA9876543210'
+
+       def initialize
+               @fw = Hash.new
+               @rv = Hash.new
+       end
+
+       def assign(hint, instance)
+               hint.gsub(/[^0-9a-zA-Z]/, '').concat(@@rsv).each_byte {|key|
+                       @rv[(@fw[key] = instance).object_id] = key and break unless(@fw[key])
+               }
+       end
+
+       def [](param)
+               param.is_a?(Integer) ? @fw[param] : @rv[param.object_id]
+       end
+
+       def release(instance)
+               @fw.delete(self[instance])
+               @rv.delete(instance.object_id)
+       end
+end
+
+#===============================================================================
+#
 #      連番処理付き GDBM クラス
 #
 class SqGDBM < GDBM
 
-       @@start = '100'
+       @@start = 100
        @@sym = '#last#'
 
        def initialize(*params)
                super
-               self[@@sym] = @@start unless(self[@@sym])
+               self[@@sym] ||= @@start.to_s
        end
 
        #-----------------------------------------------------------
@@ -36,10 +65,12 @@ end
 
 #===============================================================================
 #
-#      フラグ処理用 GDBM クラス
+#      フラグ処理/メール総数管理用 GDBM クラス
 #
 class FlagGDBM < GDBM
 
+       @@n_mail_sym = '#n_mail#'                                                                       # メール総数
+
        def initialize(*params)
                @alloc_pos = -1
                @pos_flag = {}
@@ -61,6 +92,22 @@ class FlagGDBM < GDBM
        def get_flag(key, flag)
                self[key] ? self[key][@pos_flag[flag]] : @default
        end
+
+       def reset_n(sym = @@n_mail_sym)
+               self[sym] ||= 0.to_s
+       end
+
+       def get_n(sym = @@n_mail_sym)
+               self[sym]
+       end
+
+       def inc_n(sym = @@n_mail_sym)
+               self[sym] = (self[sym].to_i + 1).to_s
+       end
+
+       def dec_n(sym = @@n_mail_sym)
+               self[sym] = (self[sym].to_i - 1).to_s
+       end
 end
 
 #===============================================================================
@@ -100,6 +147,10 @@ class MaveBaseModel
                @views[name] = view
        end
 
+       def dirty
+               @dirty += 1
+       end
+
        def dirty?
                @clean < @dirty and @clean = @dirty
        end
@@ -215,12 +266,14 @@ class MaveAccounts < MaveBaseModel
        def regular
                @accounts[@configs[:ACCOUNTS][@regular_nth][:NAME]]
        end
+
        def previous
                begin
                        @regular_nth -= 1; @regular_nth %= @configs[:ACCOUNTS].size
                end until(@accounts[@configs[:ACCOUNTS][@regular_nth][:NAME]].enable)
                regular
        end
+
        def next
                begin
                        @regular_nth += 1; @regular_nth %= @configs[:ACCOUNTS].size
@@ -342,6 +395,8 @@ class MaveFolder < MaveDirectory
                [:READ, :FLAG, :NOTICE, :FOLD].each {|flag|
                        @flags_sq.alloc_flag(flag)
                }
+               @flags_sq.get_n                         || @flags_sq.reset_n                            # メール総数
+               @flags_sq.get_n('#r_mail#')     || @flags_sq.reset_n('#r_mail#')        # 既読メール総数
 
                # フォルダの設定ファイルを読む(folder_configs プロパティと、bind? メソッドが追加される)
                begin
@@ -373,7 +428,7 @@ class MaveFolder < MaveDirectory
                Digest::MD5.file(config_filename).to_s
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------------- MaveFolder ----
        #
        #       指定のメール連番のメールインスタンスを返す
        #
@@ -381,7 +436,7 @@ class MaveFolder < MaveDirectory
                sq ? MaveMail.new({:CONFIGS => @configs, :FILE => File.new(@path + '/' + @filename_sq[sq]), :FOLDER => self, :SQ => sq}) : nil
        end
  
-       #-----------------------------------------------------------
+       #------------------------------------------- MaveFolder ----
        #
        #       メールの概要を返す
        #
@@ -403,7 +458,7 @@ class MaveFolder < MaveDirectory
                ]
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------------- MaveFolder ----
        #
        #       フォルダ内にメールを追加する
        #
@@ -442,10 +497,14 @@ class MaveFolder < MaveDirectory
                                @sq_rootsq.delete(old_rootsq)
                        end
                end
+
+               # メール総数カウントアップ
+               @flags_sq.inc_n
+
                @dirty += 1
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------------- MaveFolder ----
        #
        #       フォルダ内にメールを上書きする
        #
@@ -461,7 +520,7 @@ class MaveFolder < MaveDirectory
                @dirty += 1
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------------- MaveFolder ----
        #
        #       フォルダ内のメールを返す
        #
@@ -528,20 +587,22 @@ class MaveFolder < MaveDirectory
                }
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------------- MaveFolder ----
        #
        #       各種フラグ処理
        #
        def read(sq)
-               @flags_sq.set_flag(sq, :READ, ?R)
+               read?(sq) or  @flags_sq.set_flag(sq, :READ, ?R) and @flags_sq.inc_n('#r_mail#')
                @dirty += 1
+               #### folders.dirty
        end
        def read?(sq)
                @flags_sq.get_flag(sq, :READ) == ?R
        end
        def unread(sq)
-               @flags_sq.set_flag(sq, :READ, ?_)
+               read?(sq) and @flags_sq.set_flag(sq, :READ, ?_) and @flags_sq.dec_n('#r_mail#')
                @dirty += 1
+               #### folders.dirty
        end
 
        def flag(sq)
@@ -600,15 +661,18 @@ end
 #
 class MaveFolders < MaveBaseModel
 
+       attr_reader :shortcuts
+
        def initialize(params)
                super
                @folders                = {}
+               @shortcuts              = MaveShortcuts.new
 
                begin
                        Dir.open(@configs[:ROOT_DIRECTORY]) {|dir|
                                dir.each {|name|
                                        next if(name =~ /^[._]/ or !File.directory?(dir.path + '/' + name))
-                                       @folders[name] = MaveFolder.new({:CONFIGS => @configs, :NAME => name})
+                                       open_folder(name)
                                }
                        }
                rescue
@@ -617,19 +681,25 @@ class MaveFolders < MaveBaseModel
                end
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------------ MaveFolders ----
        #
        #       メールフォルダ「群」を通して、メールフォルダを作成/開く
        #
        def open_folder(name)
-               @folders[name] || (@dirty += 1 and @folders[name] = MaveFolder.new({:CONFIGS => @configs, :NAME => name}))
+               unless(@folders[name])
+                       it = @folders[name] = MaveFolder.new({:CONFIGS => @configs, :NAME => name})
+                       @shortcuts.assign(it.configs[:SHORTCUT_HINT] + it.configs[:LIST_NAME] + it.name, it)
+                       @dirty += 1
+               end
+               @folders[name]
        end
 
        def close_folder(name)
+               @shortcuts.release(@folders[name])
                @folders[name].close; @dirty += 1; @folders[name] = nil
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------------ MaveFolders ----
        #
        #       メールフォルダを順に渡す
        #
@@ -641,9 +711,23 @@ class MaveFolders < MaveBaseModel
                }
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------------ MaveFolders ----
+       #
+       #       メールフォルダの概要を返す
+       #
+       def abstract_of_folder(folder)
+               '%c %c) %s (%d/%d)' % [
+                       ?.,
+                       @shortcuts[folder],
+                       folder.configs[:LIST_NAME],
+                       (it = folder.flags_sq.get_n.to_i) - folder.flags_sq.get_n('#r_mail#').to_i,
+                       it,
+               ]
+       end
+
+       #------------------------------------------ MaveFolders ----
        #
-       #       フォルダの設定ファイルを上書きする
+       #       ã\83¡ã\83¼ã\83«ã\83\95ã\82©ã\83«ã\83\80ã\81®è¨­å®\9aã\83\95ã\82¡ã\82¤ã\83«ã\82\92ä¸\8aæ\9b¸ã\81\8dã\81\99ã\82\8b
        #
        def overwrite_folder_configs(folder, new_configs)
                File.open(folder.config_filename, 'w') {|fw| fw.write(new_configs.read) }
@@ -662,7 +746,7 @@ class MaveMail < MaveBaseModel
 
        @@debug_what_charset = false
 
-       #-----------------------------------------------------------
+       #--------------------------------------------- MaveMail ----
        #
        #       キャラクタセット情報表示、切り替え(デバッグ用)
        #
@@ -701,7 +785,7 @@ class MaveMail < MaveBaseModel
                Digest::MD5.file(@file.path).to_s
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------------- MaveMail ----
        #
        #       メールヘッダを解析
        #
@@ -770,7 +854,7 @@ class MaveMail < MaveBaseModel
                @body = it.new(@file, @content, @boundary)
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------------- MaveMail ----
        #
        #       メールヘッダの行を順に渡す
        #
@@ -782,17 +866,23 @@ class MaveMail < MaveBaseModel
                }
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------------- MaveMail ----
        #
        #       メールボディの行を順に渡す
        #
-       def body_each
-               nth = -1; while(it = self[nth += 1])
+       def body_each(start = 0)
+               nth = start - 1; while(it = self[nth += 1])
                        yield(it)
                end
        end
 
-       #-----------------------------------------------------------
+       def body_reverse_each(start = 0)
+               nth = start + 1; while(it = self[nth -= 1])
+                       yield(it)
+               end
+       end
+
+       #--------------------------------------------- MaveMail ----
        #
        #       メールの特定の行を返す
        #
@@ -806,7 +896,7 @@ class MaveMail < MaveBaseModel
                end
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------------- MaveMail ----
        #
        #       メールの件名、送信者、宛先、同報、送信時刻などを返す
        #
@@ -826,7 +916,7 @@ class MaveMail < MaveBaseModel
                Time.rfc2822(@header['Date']) rescue nil
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------------- MaveMail ----
        #
        #       Message-ID を返す
        #
@@ -834,7 +924,7 @@ class MaveMail < MaveBaseModel
                @message_id || (@header['Message-id'] =~ /<[^>]+?>/ ? (@message_id = $&) : raise('Bad Message-ID.'))
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------------- MaveMail ----
        #
        #       In-Reply-To, References を返す
        #
@@ -851,7 +941,7 @@ class MaveMail < MaveBaseModel
                (it = @header['References']) and it.scan(/<[^>]+?>/) {|id| yield id }
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------------- MaveMail ----
        #
        #       メールのサイズを返す
        #
@@ -859,7 +949,7 @@ class MaveMail < MaveBaseModel
                @file.lstat.size
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------------- MaveMail ----
        #
        #       マルチパートかどうかを返す
        #
@@ -867,7 +957,7 @@ class MaveMail < MaveBaseModel
                @content['type']['type'].index('multipart')
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------------- MaveMail ----
        #
        #       メール情報を返す
        #
@@ -921,7 +1011,7 @@ class MavePseudoMail < MaveMail
                @body_pos = pos
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------- MavePseudoMail ----
        #
        #       メールもどきを正しいメール形式で順に渡す
        #
@@ -939,7 +1029,7 @@ class MavePseudoMail < MaveMail
                }
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------- MavePseudoMail ----
        #
        #       各種メールもどきを順に渡す
        #
@@ -982,7 +1072,7 @@ class MavePseudoMail < MaveMail
                }
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------- MavePseudoMail ----
        #
        #       新規メールもどき作成
        #
@@ -1004,7 +1094,7 @@ class MavePseudoMail < MaveMail
        def renew_message_each
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------- MavePseudoMail ----
        #
        #       返信メールもどき作成
        #
@@ -1048,7 +1138,7 @@ class MavePseudoMail < MaveMail
        def resend_message_each
        end
 
-       #-----------------------------------------------------------
+       #--------------------------------------- MavePseudoMail ----
        #
        #       メールもどきの(再)編集
        #
@@ -1085,11 +1175,10 @@ class MaveTextBox < MaveBaseModel
 
        def initialize(params)
                super
-               @prompt                 = params[:PROMPT] || '>'
                @text                   = params[:TEXT] || ''
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------------ MaveTextBox ----
        #
        #       文字をクリアする
        #
@@ -1098,7 +1187,7 @@ class MaveTextBox < MaveBaseModel
                @dirty += 1
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------------ MaveTextBox ----
        #
        #       文字を削除する
        #
@@ -1107,7 +1196,7 @@ class MaveTextBox < MaveBaseModel
                @dirty += 1
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------------ MaveTextBox ----
        #
        #       通常文字を入力する
        #
@@ -1116,8 +1205,13 @@ class MaveTextBox < MaveBaseModel
                @dirty += 1
        end
 
-       def line
-               @prompt + @text
+       #------------------------------------------ MaveTextBox ----
+       #
+       #       文字列をセットする
+       #
+       def set_text(text)
+               @text = text
+               @dirty += 1
        end
 end
 
@@ -1132,7 +1226,7 @@ class MaveCreateFolder < MaveTextBox
                @folders                = params[:FOLDERS]
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------- MaveCreateFolder ----
        #
        #       新規にフォルダを作成する
        #
@@ -1143,6 +1237,17 @@ end
 
 #===============================================================================
 #
+#      インクリメンタル検索モデルクラス
+#
+class MaveIncrementalSearch < MaveTextBox
+
+       def initialize(params)
+               super
+       end
+end
+
+#===============================================================================
+#
 #      ステータスモデルクラス
 #
 class MaveStatus < MaveBaseModel
@@ -1153,7 +1258,7 @@ class MaveStatus < MaveBaseModel
                @max_logs = 1000
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------------- MaveStatus ----
        #
        #       ログを追加
        #
@@ -1165,7 +1270,7 @@ class MaveStatus < MaveBaseModel
                @views.update                                                                                   # 表示のリアルタイム更新
        end
 
-       #-----------------------------------------------------------
+       #------------------------------------------- MaveStatus ----
        #
        #       ログを順に返す
        #
@@ -1253,6 +1358,7 @@ end
 class MaveTextPlainPart < MaveBasePart
 
        def [](nth)
+               return(nil) if(nth < 0)
                encoding = @content['transfer-encoding']['type'].upcase
                if(encoding == 'BASE64' or encoding == 'QUOTED-PRINTABLE')      ####
                        unless(@index)