]> git.cworth.org Git - sup/blobdiff - lib/sup/modes/thread-index-mode.rb
'A' archives and kills buffer in thread-view-mode (required significant updatedes...
[sup] / lib / sup / modes / thread-index-mode.rb
index 51d1d44da35acc71c1dd9876c0f8b11cbe4d99c0..de799000b9d1975d500166e3e8e799cb6db49534 100644 (file)
@@ -1,3 +1,4 @@
+require 'thread'
 module Redwood
 
 ## subclasses should implement load_threads
@@ -16,6 +17,7 @@ class ThreadIndexMode < LineCursorMode
     k.add :edit_labels, "Edit or add labels for a thread", 'l'
     k.add :edit_message, "Edit message (drafts only)", 'e'
     k.add :mark_as_spam, "Mark thread as spam", 'S'
+    k.add :delete, "Mark thread for deletion", 'd'
     k.add :kill, "Kill thread (never to be seen in inbox again)", '&'
     k.add :save, "Save changes now", '$'
     k.add :jump_to_next_new, "Jump to next new thread", :tab
@@ -44,6 +46,7 @@ class ThreadIndexMode < LineCursorMode
 
   def lines; @text.length; end
   def [] i; @text[i]; end
+  def contains_thread? t; !@lines[t].nil?; end
 
   def reload
     drop_all_threads
@@ -55,11 +58,22 @@ class ThreadIndexMode < LineCursorMode
   def select t=nil
     t ||= @threads[curpos]
 
+    ## this isn't working entirely. TODO:figure out why
+    # t = t.clone # required so that messages added later on don't completely
+                # screw everything up
+
     ## TODO: don't regen text completely
     Redwood::reporting_thread do
+      BufferManager.say("Loading message bodies...") do |sid|
+        t.each { |m, *o| m.load_from_source! if m }
+      end
       mode = ThreadViewMode.new t, @hidden_labels
       BufferManager.spawn t.subj, mode
       BufferManager.draw_screen
+      mode.jump_to_first_open
+      BufferManager.draw_screen # lame TODO: make this unnecessary
+      ## the first draw_screen is needed before topline and botline
+      ## are set, and the second to show the cursor having moved
     end
   end
 
@@ -67,45 +81,48 @@ class ThreadIndexMode < LineCursorMode
     threads.each { |t| select t }
   end
   
-  def handle_starred_update m
+  def handle_starred_update sender, m
     return unless(t = @ts.thread_for m)
-    @starred_cache[t] = t.has_label? :starred
     update_text_for_line @lines[t]
+    BufferManager.draw_screen
   end
 
-  def handle_read_update m
-    return unless(t = @ts.thread_for m)
-    @new_cache[t] = false
+  def handle_read_update sender, t
+    return unless @lines[t]
     update_text_for_line @lines[t]
+    BufferManager.draw_screen
   end
 
+  def handle_archived_update *a; handle_read_update *a; end
+
   ## overwrite me!
   def is_relevant? m; false; end
 
-  def handle_add_update m
+  def handle_add_update sender, m
     if is_relevant?(m) || @ts.is_relevant?(m)
       @ts.load_thread_for_message m
-      @new_cache.delete @ts.thread_for(m) # force recalculation of newness
       update
+      BufferManager.draw_screen
     end
   end
 
-  def handle_delete_update mid
+  def handle_delete_update sender, mid
     if @ts.contains_id? mid
       @ts.remove mid
       update
+      BufferManager.draw_screen
     end
   end
 
   def update
     ## let's see you do THIS in python
-    @threads = @ts.threads.select { |t| !@hidden_threads[t] }.sort_by { |t| t.date }.reverse
+    @threads = @ts.threads.select { |t| !@hidden_threads[t] && !t.has_label?(:killed) }.sort_by { |t| t.date }.reverse
     @size_width = (@threads.map { |t| t.size }.max || 0).num_digits
     regen_text
   end
 
   def edit_message
-    t = @threads[curpos] or return
+    return unless(t = @threads[curpos])
     message, *crap = t.find { |m, *o| m.has_label? :draft }
     if message
       mode = ResumeMode.new message
@@ -115,39 +132,56 @@ class ThreadIndexMode < LineCursorMode
     end
   end
 
-  def toggle_starred
+  def actually_toggle_starred t
+    if t.has_label? :starred # if ANY message has a star
+      t.remove_label :starred # remove from all
+    else
+      t.first.add_label :starred # add only to first
+    end
+  end  
+
+  def toggle_starred 
     t = @threads[curpos] or return
-    @starred_cache[t] = t.toggle_label :starred
+    actually_toggle_starred t
     update_text_for_line curpos
     cursor_down
   end
 
   def multi_toggle_starred threads
-    threads.each { |t| @starred_cache[t] = t.toggle_label :starred }
+    threads.each { |t| actually_toggle_starred t }
     regen_text
   end
 
-  def toggle_archived
-    return unless(t = @threads[curpos])
-    t.toggle_label :inbox
+  def actually_toggle_archived t
+    if t.has_label? :inbox
+      t.remove_label :inbox
+      UpdateManager.relay self, :unarchived, t
+    else
+      t.add_label :inbox
+      UpdateManager.relay self, :archived, t
+    end
+  end
+
+  def toggle_archived 
+    t = @threads[curpos] or return
+    actually_toggle_archived t
     update_text_for_line curpos
-    cursor_down
   end
 
   def multi_toggle_archived threads
-    threads.each { |t| t.toggle_label :inbox }
+    threads.each { |t| actually_toggle_archived t }
     regen_text
   end
 
   def toggle_new
     t = @threads[curpos] or return
-    @new_cache[t] = t.toggle_label :unread
+    t.toggle_label :unread
     update_text_for_line curpos
     cursor_down
   end
 
   def multi_toggle_new threads
-    threads.each { |t| @new_cache[t] = t.toggle_label :unread }
+    threads.each { |t| t.toggle_label :unread }
     regen_text
   end
 
@@ -157,9 +191,8 @@ class ThreadIndexMode < LineCursorMode
   end
 
   def jump_to_next_new
-    t = @threads[curpos] or return
-    n = ((curpos + 1) .. lines).find { |i| @new_cache[@threads[i]] }
-    n = (0 ... curpos).find { |i| @new_cache[@threads[i]] } unless n
+    n = ((curpos + 1) ... lines).find { |i| @threads[i].has_label? :unread }
+    n = (0 ... curpos).find { |i| @threads[i].has_label? :unread } unless n
     if n
       set_cursor_pos n
     else
@@ -180,6 +213,19 @@ class ThreadIndexMode < LineCursorMode
     regen_text
   end
 
+  def delete
+    t = @threads[curpos] or return
+    multi_delete [t]
+  end
+
+  def multi_delete threads
+    threads.each do |t|
+      t.toggle_label :deleted
+      hide_thread t
+    end
+    regen_text
+  end
+
   def kill
     t = @threads[curpos] or return
     multi_kill [t]
@@ -232,6 +278,7 @@ class ThreadIndexMode < LineCursorMode
     speciall = (@hidden_labels + LabelManager::RESERVED_LABELS).uniq
     keepl, modifyl = thread.labels.partition { |t| speciall.member? t }
     label_string = modifyl.join(" ")
+    label_string += " " unless label_string.empty?
 
     answer = BufferManager.ask :edit_labels, "edit labels: ", label_string
     return unless answer
@@ -266,6 +313,7 @@ class ThreadIndexMode < LineCursorMode
     t = @threads[curpos] or return
     m = t.latest_message
     return if m.nil? # probably won't happen
+    m.load_from_source!
     mode = ReplyMode.new m
     BufferManager.spawn "Reply to #{m.subj}", mode
   end
@@ -274,6 +322,7 @@ class ThreadIndexMode < LineCursorMode
     t = @threads[curpos] or return
     m = t.latest_message
     return if m.nil? # probably won't happen
+    m.load_from_source!
     mode = ForwardMode.new m
     BufferManager.spawn "Forward of #{m.subj}", mode
     mode.edit
@@ -291,11 +340,13 @@ class ThreadIndexMode < LineCursorMode
   def load_n_threads n=LOAD_MORE_THREAD_NUM, opts={}
     @mbid = BufferManager.say "Searching for threads..."
     orig_size = @ts.size
+    last_update = Time.now - 9999 # oh yeah
     @ts.load_n_threads(@ts.size + n, opts) do |i|
       BufferManager.say "Loaded #{i} threads...", @mbid
-      if i % 5 == 0
+      if (Time.now - last_update) >= 0.25
         update
         BufferManager.draw_screen
+        last_update = Time.now
       end
     end
     @ts.threads.each { |th| th.labels.each { |l| LabelManager << l } }
@@ -325,11 +376,6 @@ protected
     update
   end
 
-  def remove_label_and_hide_thread t, label
-    t.remove_label label
-    hide_thread t
-  end
-
   def hide_thread t
     raise "already hidden" if @hidden_threads[t]
     @hidden_threads[t] = true
@@ -358,18 +404,18 @@ protected
   end
 
   def text_for_thread t
-    date = (@date_cache[t] ||= t.date.to_nice_s(Time.now)) 
-    from = (@who_cache[t] ||= author_text_for_thread(t))
+    date = t.date.to_nice_s(Time.now)
+    from = author_text_for_thread(t)
     if from.length > @from_width
       from = from[0 ... (@from_width - 1)]
       from += "." unless from[-1] == ?\s
     end
 
-    new = @new_cache.member?(t) ? @new_cache[t] : @new_cache[t] = t.has_label?(:unread)
-    starred = @starred_cache.member?(t) ? @starred_cache[t] : @starred_cache[t] = t.has_label?(:starred)
+    new = t.has_label?(:unread)
+    starred = t.has_label?(:starred)
 
-    dp = (@dp_cache[t] ||= t.direct_participants.any? { |p| AccountManager.is_account? p })
-    p = (@p_cache[t] ||= (dp || t.participants.any? { |p| AccountManager.is_account? p }))
+    dp = t.direct_participants.any? { |p| AccountManager.is_account? p }
+    p = dp || t.participants.any? { |p| AccountManager.is_account? p }
 
     base_color = (new ? :index_new_color : :index_old_color)
     [ 
@@ -392,12 +438,7 @@ private
 
   def initialize_threads
     @ts = ThreadSet.new Index.instance
-    @date_cache = {}
-    @who_cache = {}
-    @dp_cache = {}
-    @p_cache = {}
-    @new_cache = {}
-    @starred_cache = {}
+    @ts_mutex = Mutex.new
     @hidden_threads = {}
   end
 end