*** empty log message ***
authorgc <gc>
Sat, 21 Jul 2007 16:41:17 +0000 (16:41 +0000)
committergc <gc>
Sat, 21 Jul 2007 16:41:17 +0000 (16:41 +0000)
bin/booh-classifier
lib/booh/booh-lib.rb

index f710760..c7c6efe 100644 (file)
@@ -66,7 +66,6 @@ def handle_options
 
             end
         end
-        puts "args: #{ARGV}"
     rescue
         puts $!
         usage
@@ -89,7 +88,7 @@ def set_cache_memory_use_figure
     else
         $config['cache-memory-use-figure'] = $config['cache-memory-use'].to_i
     end
-    msg 2, "Set cache memory use figure: #{$config['cache-memory-use-figure']} kB"
+    msg 2, "Cache memory used: #{$config['cache-memory-use-figure']} kB"
 end
 
 def read_config
@@ -181,35 +180,28 @@ end
 
 def get_mem
     IO.readlines('/proc/self/status').join =~ /VmRSS.*?(\d+)\s*kB/
-    puts $1
+    msg 3, "RSS: #{$1}"
     return $1.to_i
 end
 
 def show_mem(*txt)
     txt.length > 0 and print txt[0]
-    puts get_mem
-end
-
-def min(v1, v2)
-    return v1 < v2 ? v1 : v2
-end
-def max(v1, v2)
-    return v1 > v2 ? v1 : v2
+    msg 2, "RSS: #{get_mem}"
 end
 
 class Gdk::Color
     def darker
         color = dup
-        color.red = max(color.red - 10000, 0)
-        color.green = max(color.green - 10000, 0)
-        color.blue = max(color.blue - 10000, 0)
+        color.red = [ color.red - 10000, 0 ].max
+        color.green = [ color.green - 10000, 0 ].max
+        color.blue = [ color.blue - 10000, 0 ].max
         return color
     end
     def lighter
         color = dup
-        color.red = min(color.red + 10000, 65535)
-        color.green = min(color.green + 10000, 65535)
-        color.blue = min(color.blue + 10000, 65535)
+        color.red = [ color.red + 10000, 65535 ].min
+        color.green = [ color.green + 10000, 65535 ].min
+        color.blue = [ color.blue + 10000, 65535 ].min
         return color
     end
 end
@@ -220,13 +212,12 @@ $colors = [ Gdk::Color.new(0, 65535, 0),
             Gdk::Color.new(0, 65535, 65535),
             Gdk::Color.new(65535, 0, 65535) ]
 
-class Tag
+class Label
     attr_accessor :color, :name
     def initialize(name)
         @name = name
     end
 end
-$tags = {}
 
 class Entry
     @@thumbnails_height = 64
@@ -235,7 +226,7 @@ class Entry
         return @@thumbnails_height
     end
 
-    attr_accessor :path, :type, :angle, :button, :removed, :tagged
+    attr_accessor :path, :type, :angle, :button, :image, :removed, :labeled
 
     def initialize(path, type)
         @path = path
@@ -249,7 +240,7 @@ class Entry
     def pixbuf_full
         @protect_cleanup.synchronize {
             if @pixbuf_full.nil?
-                puts ">>> pixbuf_full #{path}"
+                msg 3, ">>> pixbuf_full #{path}"
                 load_into_pixbuf_full
             end
             return @pixbuf_full
@@ -260,7 +251,7 @@ class Entry
             if @pixbuf_full.nil?
                 return false
             else
-                puts ">>> free_pixbuf_full #{path}"
+                msg 3, ">>> free_pixbuf_full #{path}"
                 @pixbuf_full = nil
                 return true
             end
@@ -269,7 +260,7 @@ class Entry
     def pixbuf_main(width, height)
         @protect_cleanup.synchronize {
             if @pixbuf_main.nil? || width != @width || height != @height
-                puts ">>> pixbuf_main #{path}"
+                msg 3, ">>> pixbuf_main #{path}"
                 @width = width
                 @height = height
                 load_into_pixbuf_full  #- make sure it is loaded
@@ -297,7 +288,7 @@ class Entry
             if @pixbuf_main.nil?
                 return false
             else
-                puts ">>> free_pixbuf_main #{path}"
+                msg 3, ">>> free_pixbuf_main #{path}"
                 @pixbuf_main = nil
                 return true
             end
@@ -306,7 +297,7 @@ class Entry
     def pixbuf_thumbnail
         return @protect_cleanup.synchronize {
             if @pixbuf_thumbnail.nil?
-                puts ">>> pixbuf_thumbnail #{path}"
+                msg 3, ">>> pixbuf_thumbnail #{path}"
                 load_into_pixbuf_full  #- make sure it is loaded
                 @pixbuf_thumbnail = @pixbuf_full.scale(@pixbuf_full.width * (@@thumbnails_height.to_f/@pixbuf_full.height), @@thumbnails_height, Gdk::Pixbuf::INTERP_BILINEAR)
             end
@@ -318,7 +309,7 @@ class Entry
             if @pixbuf_thumbnail.nil?
                 return false
             else
-                puts ">>> free_pixbuf_thumbnail #{path}"
+                msg 3, ">>> free_pixbuf_thumbnail #{path}"
                 @pixbuf_thumbnail = nil
                 return true
             end
@@ -331,10 +322,10 @@ class Entry
             button.modify_bg(Gtk::StateType::NORMAL, red)
             button.modify_bg(Gtk::StateType::PRELIGHT, red.lighter)
             button.modify_bg(Gtk::StateType::ACTIVE, red)
-        elsif tagged
-            button.modify_bg(Gtk::StateType::NORMAL, tagged.color)
-            button.modify_bg(Gtk::StateType::PRELIGHT, tagged.color.lighter)
-            button.modify_bg(Gtk::StateType::ACTIVE, tagged.color)
+        elsif labeled
+            button.modify_bg(Gtk::StateType::NORMAL, labeled.color)
+            button.modify_bg(Gtk::StateType::PRELIGHT, labeled.color.lighter)
+            button.modify_bg(Gtk::StateType::ACTIVE, labeled.color)
         else
             # TODO need to add proper undo support :/
             white = Gdk::Color.new(55535, 55535, 55535)
@@ -345,21 +336,43 @@ class Entry
     end
 
     private
+    def cleanup_dir(dir)
+        Dir.entries(dir).each { |file| file != '.' && file != '..' and File.delete(File.join(dir, file)) }
+        Dir.delete(dir)
+    end
+
     def load_into_pixbuf_full
         if @pixbuf_full.nil?
-            puts ">>> load_into_pixbuf_full #{path}"
+            msg 3, ">>> load_into_pixbuf_full #{path}"
+            if type == 'video'
+                tmp = Tempfile.new("boohclassifiertemp")
+                tmp.close!
+                Dir.mkdir(dest_dir = tmp.path)
+                orig_base = File.basename(path)
+                if ! gen_video_thumbnail(path, dest_dir, orig_base, false, 0)
+                    cleanup_dir(dest_dir)
+                    return
+                end
+                image_path = "#{dest_dir}/#{orig_base}.jpg000000.jpg"
+            else
+                image_path = @path
+            end
             begin
-                @pixbuf_full = Gdk::Pixbuf.new(@path)
+                @pixbuf_full = Gdk::Pixbuf.new(image_path)
             rescue Gdk::PixbufError
-                puts "Cannot load #{@path}: #{$!}"
+                msg 0, "Cannot load #{image_path}: #{$!}"
                 return
             end
             if @pixbuf_full
                 if @angle.nil?
-                    @angle = guess_rotate(path)
+                    if type == 'image'
+                        @angle = guess_rotate(image_path)
+                    else
+                        @angle = 0
+                    end
                 end
                 if @angle != 0
-                    puts ">>> load_into_pixbuf_full #{path} => rotate #{@angle}"
+                    msg 3, ">>> load_into_pixbuf_full #{image_path} => rotate #{@angle}"
                     @pixbuf_full = rotate_pixbuf(@pixbuf_full, @angle)
                 end
                 if @pixbuf_full.height > @@max_height
@@ -367,6 +380,9 @@ class Entry
                     @pixbuf_full = @pixbuf_full.scale(@pixbuf_full.width * (@@max_height.to_f/@pixbuf_full.height), @@max_height, Gdk::Pixbuf::INTERP_BILINEAR)
                 end
             end
+            if type == 'video'
+                cleanup_dir(dest_dir)
+            end
         end
     end
 
@@ -385,22 +401,24 @@ class MainView < Gtk::DrawingArea
             @preloader = Thread.new {
                 #- background preloading
                 while true
-                    puts "background main preloading triggered..."
-                    if ! @index.nil?
+                    msg 3, "background main preloading triggered..."
+                    if ! @entry.nil?
+                        index = $allentries.index(@entry)
                         w, h = window.size
+                        w -= $videoborder_pixbuf.width * 2
                         for j in 1 .. $config['preload-distance'].to_i
-                            i = @index + j
+                            i = index + j
                             if i < $allentries.size
                                 $allentries[i].pixbuf_main(w, h)
                             end
-                            i = @index - j
+                            i = index - j
                             if i >= 0
                                 $allentries[i].pixbuf_main(w, h)
                             end
                             GC.start
                             mem = get_mem
                             if mem > $config['cache-memory-use-figure']
-                                puts "too much RSS, stopping main preloading"
+                                msg 3, "too much RSS, stopping main preloading"
                                 break
                             end
                         end
@@ -413,30 +431,32 @@ class MainView < Gtk::DrawingArea
         }
     end
 
-    def set_shown_entry(index)
-        if index == @index || index < 0 || index >= $allentries.size
+    def set_shown_entry(entry)
+        if ! entry.nil? && entry == @entry
             return
         end
-        old_index = @index
-        @index = index
-        if index.nil?
-            @entry = nil
-        else
-            @entry = $allentries[index]
-        end
-        if ! @entry.button
-            #- not loaded yet
-            @index = old_index
-            return
+        @entry = entry
+        if ! entry.nil?
+            if ! @entry.button
+                #- not loaded yet
+                return
+            else
+                @entry.button.grab_focus
+            end
         end
         redraw        
         @preloader.run
-        @entry.button.grab_focus
     end
 
-
     def get_shown_entry
-        return @index
+        return @entry
+    end
+
+    def show_next_entry(entry)
+        index = $allentries.index(entry) + 1
+        if index < $allentries.size
+            set_shown_entry($allentries[index])
+        end
     end
 
     def redraw
@@ -451,13 +471,14 @@ class MainView < Gtk::DrawingArea
     def update_shown
         if @entry
             width, height = window.size 
-            @pixbuf = @entry.pixbuf_main(width, height)
-            if @pixbuf.width == width
-                @xpos = 0
+            usable_width = width - $videoborder_pixbuf.width * 2
+            @pixbuf = @entry.pixbuf_main(usable_width, height)
+            if @pixbuf.width == usable_width
+                @xpos = $videoborder_pixbuf.width
                 @ypos = (height-@pixbuf.height)/2
             else
                 @xpos = (width-@pixbuf.width)/2
-                @ypos = 0
+                @ypos = (height-@pixbuf.height)/2
             end
             @preloader.run
         else
@@ -468,6 +489,15 @@ class MainView < Gtk::DrawingArea
     def draw
         if @pixbuf
             window.draw_pixbuf(nil, @pixbuf, 0, 0, @xpos, @ypos, -1, -1, Gdk::RGB::DITHER_NONE, -1, -1)
+            if @entry && @entry.type == 'video'
+                y = @ypos
+                while y < @ypos + @pixbuf.height
+                    render_height = [ @pixbuf.height, @ypos + @pixbuf.height - y ].min
+                    window.draw_pixbuf(nil, $videoborder_pixbuf, 0, 0, @xpos - $videoborder_pixbuf.width, y, -1, render_height, Gdk::RGB::DITHER_NONE, -1, -1)
+                    window.draw_pixbuf(nil, $videoborder_pixbuf, 0, 0, @xpos + @pixbuf.width, y, -1, render_height, Gdk::RGB::DITHER_NONE, -1, -1)
+                    y += $videoborder_pixbuf.height
+                end
+            end
         end
     end
 end
@@ -475,15 +505,15 @@ end
 def check_memory_free_cache_if_needed
     GC.start
     mem = get_mem
-    i = $mainview.get_shown_entry
-    puts "mem: #{mem} index: #{i}"
+    i = $allentries.index($mainview.get_shown_entry)
+    msg 3, "mem: #{mem} index: #{i}"
     return if i.nil?
     ($allentries.size - 1).downto(1) { |j|
         if mem < $config['cache-memory-use-figure'] * 2 / 3
             break
         end
         index = i + j
-        puts "too much RSS, freeing full size of #{i+j} and #{i-j}..."
+        msg 3, "too much RSS, freeing full size of #{i+j} and #{i-j}..."
         freedsomething = false
         if i + j < $allentries.size
             freedsomething |= $allentries[i+j].free_pixbuf_full
@@ -494,7 +524,7 @@ def check_memory_free_cache_if_needed
         if freedsomething
             GC.start
             mem = get_mem
-            puts "\tmem now: #{mem}"
+            msg 3, "\tmem now: #{mem}"
         end
     }
 end
@@ -608,7 +638,7 @@ def show_popup(parent, msg, *options)
     end
 end
 
-def thumbnail_keypressed(entry, i, event)
+def thumbnail_keypressed(entry, event)
     if event.state & Gdk::Window::MOD1_MASK != 0
         #- ALT pressed: Alt-Left and Alft-Right rotate
         if event.keyval == Gdk::Keyval::GDK_Left || event.keyval == Gdk::Keyval::GDK_Right
@@ -621,7 +651,7 @@ def thumbnail_keypressed(entry, i, event)
             entry.free_pixbuf_main
             entry.free_pixbuf_thumbnail
             $mainview.redraw
-            entry.button.set_image(img = Gtk::Image.new(entry.pixbuf_thumbnail))
+            entry.image.pixbuf = entry.pixbuf_thumbnail
         end
 
     elsif event.state & Gdk::Window::CONTROL_MASK != 0
@@ -635,54 +665,59 @@ def thumbnail_keypressed(entry, i, event)
 
     else
         removed_before = entry.removed
-        tag_before = entry.tagged
+        label_before = entry.labeled
 
         if event.keyval == Gdk::Keyval::GDK_Delete
             entry.removed = true
-            entry.tagged = nil
+            entry.labeled = nil
             entry.show_bg
-            $mainview.set_shown_entry(i + 1)
+            $mainview.show_next_entry(entry)
 
             save_undo(_("set for removal"),
                       proc {
                           entry.removed = removed_before
-                          entry.tagged = tag_before
+                          entry.labeled = label_before
                           entry.show_bg
-                          $mainview.set_shown_entry(i)
+                          $mainview.set_shown_entry(entry)
                           proc {
                               entry.removed = true
-                              entry.tagged = nil
+                              entry.labeled = nil
                               entry.show_bg
-                              $mainview.set_shown_entry(i)
+                              $mainview.set_shown_entry(entry)
                           }
                       })
 
         elsif event.keyval == Gdk::Keyval::GDK_space
             entry.removed = false
-            entry.tagged = nil
+            entry.labeled = nil
             entry.show_bg
-            $mainview.set_shown_entry(i + 1)
+            $mainview.show_next_entry(entry)
 
-            save_undo(_("remove tag"),
+            save_undo(_("remove label"),
                       proc {
                           entry.removed = removed_before
-                          entry.tagged = tag_before
+                          entry.labeled = label_before
                           entry.show_bg
-                          $mainview.set_shown_entry(i)
+                          $mainview.set_shown_entry(entry)
                           proc {
                               entry.removed = false
-                              entry.tagged = nil
+                              entry.labeled = nil
                               entry.show_bg
-                              $mainview.set_shown_entry(i)
+                              $mainview.set_shown_entry(entry)
                           }
                       })
 
+        elsif event.keyval == Gdk::Keyval::GDK_Return && entry.type == 'video'
+            cmd = from_utf8($config['video-viewer']).gsub('%f', "'#{entry.path}'") + ' &'
+            msg 2, cmd
+            system(cmd)
+
         else
             char = [ Gdk::Keyval.to_unicode(event.keyval) ].pack("C*")
             if char =~ /^[a-zA-z0-9]$/
-                tag = $tags[char]
+                label = $labels[char]
                 
-                if tag.nil?
+                if label.nil?
                     vb = Gtk::VBox.new(false, 0)
                     vb.pack_start(entry = Gtk::Entry.new.set_text(char), false, false)
                     vb.pack_start(Gtk::Alignment.new(0.5, 0.5, 0, 0).add(bt = Gtk::Button.new(utf8(_("  Change color  ")))))
@@ -698,44 +733,44 @@ def thumbnail_keypressed(entry, i, event)
                         bt.modify_bg(Gtk::StateType::ACTIVE, color.darker)
                     }
                     bt.clicked
-                    entry.signal_connect('changed') {  #- cannot add a new tag with first letter of an existing tag
-                        while $tags.has_key?(entry.text[0,1])
+                    entry.signal_connect('changed') {  #- cannot add a new label with first letter of an existing label
+                        while $labels.has_key?(entry.text[0,1])
                             entry.text = entry.text.sub(/./, '')
                         end
                     }
                     if show_popup($main_window,
-                                  utf8(_("You typed the text character '%s', which is not associated with a tag.\nType in the full name of the tag below to create a new one.")) % char,
+                                  utf8(_("You typed the text character '%s', which is not associated with a label.\nType in the full name of the label below to create a new one.")) % char,
                                   { :okcancel => true, :bottomwidget => vb, :data_getter => proc { text = entry.text },
                                     :stuff_connector => proc { |stuff| entry.select_region(0, 0)
                                                                        entry.position = -1
                                                                        entry.signal_connect('activate') { stuff[:dialog].response(Gtk::Dialog::RESPONSE_OK) } } } )
                         if text.length > 0
                             char = text[0,1]  #- in case it changed
-                            tag = Tag.new(text)
-                            tag.color = color
-                            $tags[char] = tag
-                            label = Gtk::Label.new.set_markup('<b>(' + char + ')</b>' + text[1..-1]).set_justify(Gtk::Justification::CENTER)
-                            $tags_vbox.pack_start(evt = Gtk::EventBox.new.add(label).modify_bg(Gtk::StateType::NORMAL, tag.color).show_all)
+                            label = Label.new(text)
+                            label.color = color
+                            $labels[char] = label
+                            lbl = Gtk::Label.new.set_markup('<b>(' + char + ')</b>' + text[1..-1]).set_justify(Gtk::Justification::CENTER)
+                            $labels_vbox.pack_start(evt = Gtk::EventBox.new.add(lbl).modify_bg(Gtk::StateType::NORMAL, label.color).show_all)
                         end
                     end
 
                 else
                     entry.removed = false
-                    entry.tagged = tag
+                    entry.labeled = label
                     entry.show_bg
-                    $mainview.set_shown_entry(i + 1)
+                    $mainview.show_next_entry(entry)
 
-                    save_undo(_("set tag"),
+                    save_undo(_("set label"),
                               proc {
                                   entry.removed = removed_before
-                                  entry.tagged = tag_before
+                                  entry.labeled = label_before
                                   entry.show_bg
-                                  $mainview.set_shown_entry(i)
+                                  $mainview.set_shown_entry(entry)
                                   proc {
                                       entry.removed = false
-                                      entry.tagged = tag
+                                      entry.labeled = label
                                       entry.show_bg
-                                      $mainview.set_shown_entry(i)
+                                      $mainview.set_shown_entry(entry)
                                   }
                               })
                 end
@@ -750,47 +785,75 @@ def sb_msg(msg)
         $statusbar.push(0, utf8(msg))
     end
 end
-    
+
+def real_show_entry(entry, tooltips, grab_focus)
+    #- for scoping the actual reference to 'entry'
+    gtk_thread_protect(proc {
+        msg 3, "using entry #{entry}"
+        entry.image = Gtk::Image.new(entry.pixbuf_thumbnail)
+        if entry.type == 'video'
+            entry.button = Gtk::Button.new.add(Gtk::HBox.new.pack_start(da1 = Gtk::DrawingArea.new.set_size_request($videoborder_pixbuf.width, -1), false, false).
+                                                             pack_start(entry.image).
+                                                             pack_start(da2 = Gtk::DrawingArea.new.set_size_request($videoborder_pixbuf.width, -1), false, false))
+            da1.signal_connect('realize') { da1.window.set_back_pixmap($videoborder_pixmap, false) }
+            da2.signal_connect('realize') { da2.window.set_back_pixmap($videoborder_pixmap, false) }
+        else
+            entry.button = Gtk::Button.new.set_image(entry.image)
+        end
+        tooltips.set_tip(entry.button, File.basename(entry.path).gsub(/\.[^.]+$/, ''), nil)
+        $imagesline.pack_start(entry.button.show_all, false, false)
+        entry.button.signal_connect('clicked') { $mainview.set_shown_entry(entry) }
+        entry.button.signal_connect('focus-in-event') { entry.button.clicked; autoscroll_if_needed(entry.button) }
+        entry.button.signal_connect('key-press-event') { |w, e| thumbnail_keypressed(entry, e) }
+        if grab_focus
+            entry.button.grab_focus
+        end
+    })
+end
+
 def show_entries
     e = Thread.new {
         t1 = Time.now
-        show_mem
         sb_msg(_("Loading images..."))
         tooltips = Gtk::Tooltips.new
         counter = 0
-        $allentries.each_with_index { |entry, i|
+        toremove = []
+        grab_focus = true
+        i = 0
+        total_size = 0
+        while i < $allentries.size
+            entry = $allentries[i]
             if entry.pixbuf_full
+                total_size += file_size(entry.path)
                 entry.pixbuf_thumbnail
-                gtk_thread_protect(proc { |i|
-                                       entry = $allentries[i]
-                                       entry.button = Gtk::Button.new.set_image(img = Gtk::Image.new(entry.pixbuf_thumbnail))
-                                       tooltips.set_tip(entry.button, File.basename(entry.path).gsub(/\.[^.]+$/, ''), nil)
-                                       $imagesline.pack_start(entry.button.show_all, false, false)
-                                       entry.button.signal_connect('clicked') { $mainview.set_shown_entry(i) }
-                                       entry.button.signal_connect('focus-in-event') { entry.button.clicked; autoscroll_if_needed(entry.button) }
-                                       entry.button.signal_connect('key-press-event') { |w, e| thumbnail_keypressed(entry, i, e) }
-                                       if i == 0
-                                           entry.button.grab_focus
-                                       end
-                                   }, i)
+                real_show_entry(entry, tooltips, grab_focus)
+                grab_focus = false
                 if i % 4 == 0
                     check_memory_free_cache_if_needed
                 end
                 counter += 1
+                i = i + 1
+
+            else
+                $allentries.delete_at(i)
             end
-        }
+        end
         check_memory_free_cache_if_needed
-        sb_msg(_("%d images loaded.") % counter)
-        puts "time: #{Time.now - t1}"
+        sb_msg(_("%d images of total %s kB loaded in %3.2f seconds.") % [ counter, commify(total_size / 1024), Time.now - t1 ])
     }
     e.priority = -1
 end
 
-def open_dir(path)
-    #- remove visual stuff, so that user will see something is happening
-    reset_tags
+def reset_all
+    reset_labels
     reset_thumbnails
     $mainview.set_shown_entry(nil)
+    sb_msg(nil)
+end
+
+def open_dir(path)
+    #- remove visual stuff, so that user will see something is happening
+    reset_all
     sb_msg(_("Scanning source directory..."))
 
     path = File.expand_path(path.sub(%r|/$|, ''))
@@ -815,7 +878,7 @@ def open_dir(path)
         end
         Dir.entries(dir).each { |file|
             type = entry2type(file)
-           if type && $allentries.size < 10
+           if type && $allentries.size < 120
                 $allentries << Entry.new(File.join(dir, file), type)
             end
         }
@@ -887,7 +950,7 @@ def execute
     table = Gtk::Table.new(0, 0, false)
     table.set_row_spacings(5)
     table.set_column_spacings(5)
-    table.attach(Gtk::Label.new.set_markup(utf8(_("<b>Tag name:</b>"))).set_justify(Gtk::Justification::CENTER), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL, 5, 0)
+    table.attach(Gtk::Label.new.set_markup(utf8(_("<b>Label name:</b>"))).set_justify(Gtk::Justification::CENTER), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL, 5, 0)
     table.attach(Gtk::Label.new.set_markup(utf8(_("<b>Amount of pictures:</b>"))).set_justify(Gtk::Justification::CENTER), 1, 2, 0, 1, Gtk::FILL, Gtk::FILL, 5, 0)
     table.attach(Gtk::Label.new.set_markup(utf8(_("<b>Pictures examples:</b>"))).set_justify(Gtk::Justification::CENTER), 2, 3, 0, 1, Gtk::FILL, Gtk::FILL, 5, 0)
     table.attach(Gtk::Label.new.set_markup(utf8(_("<b>Action to perform:</b>"))).set_justify(Gtk::Justification::CENTER), 3, 4, 0, 1, Gtk::FILL, Gtk::FILL, 5, 0)
@@ -900,7 +963,15 @@ def execute
             if truthproc.call(entry)
                 counter += 1
                 if counter < 4
-                    examples.pack_start(Gtk::Image.new(entry.pixbuf_thumbnail), false, false)
+                    thumbnail = Gtk::Image.new(entry.pixbuf_thumbnail)
+                    if entry.type == 'video'
+                        thumbnail = Gtk::HBox.new.pack_start(da1 = Gtk::DrawingArea.new.set_size_request($videoborder_pixbuf.width, -1), false, false).
+                                                  pack_start(thumbnail).
+                                                  pack_start(da2 = Gtk::DrawingArea.new.set_size_request($videoborder_pixbuf.width, -1), false, false)
+                        da1.signal_connect('realize') { da1.window.set_back_pixmap($videoborder_pixmap, false) }
+                        da2.signal_connect('realize') { da2.window.set_back_pixmap($videoborder_pixmap, false) }
+                    end
+                    examples.pack_start(thumbnail, false, false)
                 elsif counter == 4
                     examples.pack_start(Gtk::Label.new.set_markup("<b>...</b>"), false, false)
                 end
@@ -962,11 +1033,12 @@ def execute
     }
     stuff = {}
     stuff['toremove'] = add_row.call(1, utf8(_("<i>to remove</i>")), Gdk::Color.new(65535, 0, 0), proc { |entry| entry.removed }, false)
-    $tags.values.each_with_index { |tag, row| stuff[tag] = add_row.call(row + 2, tag.name, tag.color, proc { |entry| entry.tagged == tag }, true) }
+    $labels.values.each_with_index { |label, row| stuff[label] = add_row.call(row + 2, label.name, label.color, proc { |entry| entry.labeled == label }, true) }
     vb1.pack_start(sw = Gtk::ScrolledWindow.new(nil, nil).add_with_viewport(table).set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC), true, true)
 
     toremove_amount = $allentries.find_all { |entry| entry.removed }.size
-    check_removal = Gtk::CheckButton.new(utf8(_("I have noticed I am about to permanently remove the %d above mentioned pictures.") % toremove_amount))
+    toremove_size = commify($allentries.find_all { |entry| entry.removed }.collect { |entry| file_size(entry.path) }.sum / 1024)
+    check_removal = Gtk::CheckButton.new(utf8(_("I have noticed I am about to permanently remove the %d above mentioned pictures (total %s kB).") % [ toremove_amount, toremove_size ]))
     if toremove_amount > 0
         vb1.pack_start(check_removal, false, false)
         stuff['toremove'][:combo].signal_connect('changed') { |widget|
@@ -987,32 +1059,32 @@ def execute
     while true
         dialog.run { |response|        
             if response == Gtk::Dialog::RESPONSE_OK
-                if toremove_amount > 0 && ! check_removal.active? && check_removal.sensitive?
+                if toremove_amount > 0 && ! check_removal.active? && stuff['toremove'][:combo].active == 0
                     show_popup(dialog, utf8(_("You have not confirmed that you noticed the permanent removal of the pictures marked for deletion.")))
                     break
                 end
                 problem = false
-                tag2entries = {}
-                $tags.values.each { |tag| tag2entries[tag] = [] }
-                $allentries.each { |entry| entry.tagged and tag2entries[entry.tagged] << entry }
+                label2entries = {}
+                $labels.values.each { |label| label2entries[label] = [] }
+                $allentries.each { |entry| entry.labeled and label2entries[entry.labeled] << entry }
                 stuff.keys.each { |key|
-                    if key.is_a?(Tag) && stuff[key][:combo].active == 0
-                        path = stuff[key][:pathlabel].text
-                        if path[0] != ?/
+                    if key.is_a?(Label) && stuff[key][:combo].active == 0
+                        destination = stuff[key][:pathlabel].text
+                        if destination[0] != ?/
                             show_popup(dialog, utf8(_("You have not selected a directory where to move %s.") % key.name))
                             problem = true
                             break
                         end
-                        st = File.stat(path)
+                        st = File.stat(destination)
                         if ! st.directory? || ! st.writable?
                             show_popup(dialog, utf8(_("Directory where to move %s is not valid or not writable.") % key.name))
                             problem = true
                             break
                         end
-                        tag2entries[key].each { |entry|
+                        label2entries[key].each { |entry|
                             begin
-                                File.stat(File.join(path, File.basename(entry.path)))
-                                show_popup(dialog, utf8(_("Sorry, a file '%s' already exists in '%s'.") % [ File.basename(entry.path), path ]))
+                                File.stat(File.join(destination, File.basename(entry.path)))
+                                show_popup(dialog, utf8(_("Sorry, a file '%s' already exists in '%s'.") % [ File.basename(entry.path), destination ]))
                                 problem = true
                                 break
                             rescue
@@ -1024,8 +1096,33 @@ def execute
                     end
                 }
                 if ! problem
-                    puts "execute!"
+                    begin
+                        moved = 0
+                        stuff.keys.each { |key|
+                            if key.is_a?(Label) && stuff[key][:combo].active == 0
+                                destination = stuff[key][:pathlabel].text
+                                label2entries[key].each { |entry|
+                                    File.rename(entry.path, File.join(destination, File.basename(entry.path)))
+                                    moved += 1
+                                }
+                            end
+                        }
+                        removed = 0
+                        if stuff['toremove'][:combo].active == 0
+                            $allentries.each { |entry|
+                                if entry.removed
+                                    File.delete(entry.path)
+                                    removed += 1
+                                end
+                            }
+                        end
+                    rescue
+                        msg 1, "woops: #{$!}"
+                        show_popup(dialog, utf8(_("Unexpected system call error: '%s'.") % $!))
+                    end
+                    show_popup(dialog, utf8(_("Successfully moved %d files and removed %d files.") % [ moved, removed ]))
                     dialog.destroy
+                    reset_all
                     return
                 end
 
@@ -1103,6 +1200,7 @@ def preferences
     dialog.run { |response|
         if response == Gtk::Dialog::RESPONSE_OK
             $config['video-viewer'] = from_utf8(video_viewer_entry.text)
+            $config['browser'] = from_utf8(browser_entry.text)
             $config['preload-distance'] = preload_distance.value
             $config['rotate-set-exif'] = update_exif_orientation_check.active?
             if cache_memfree_radio.active?
@@ -1111,7 +1209,6 @@ def preferences
                 $config['cache-memory-use'] = cache_specify_spin.value
             end
             set_cache_memory_use_figure
-            p $config
         end
     }
     dialog.destroy
@@ -1184,11 +1281,12 @@ def create_menubar
     return mb
 end
 
-def reset_tags
-    for child in $tags_vbox.children
-        $tags_vbox.remove(child)
+def reset_labels
+    for child in $labels_vbox.children
+        $labels_vbox.remove(child)
     end
-    $tags_vbox.pack_start(Gtk::Label.new(utf8(_("Tags list:"))).set_justify(Gtk::Justification::CENTER), false, false).show_all
+    $labels_vbox.pack_start(Gtk::Label.new(utf8(_("Labels list:"))).set_justify(Gtk::Justification::CENTER), false, false).show_all
+    $labels = {}
 end
 
 def reset_thumbnails
@@ -1200,13 +1298,16 @@ end
 
 def create_main_window
 
+    $videoborder_pixbuf = Gdk::Pixbuf.new("#{$FPATH}/images/video_border.png")
+    $videoborder_pixmap, = $videoborder_pixbuf.render_pixmap_and_mask(0)
+
     mb = create_menubar
 
     main_vbox = Gtk::VBox.new(false, 0)
     main_vbox.pack_start(mb, false, false)
     mainview_hbox = Gtk::HBox.new
-    mainview_hbox.pack_start(Gtk::Alignment.new(0.5, 0, 0, 0).add($tags_vbox = Gtk::VBox.new(false, 5)), false, true)
-    reset_tags
+    mainview_hbox.pack_start(Gtk::Alignment.new(0.5, 0, 0, 0).add($labels_vbox = Gtk::VBox.new(false, 5)), false, true)
+    reset_labels
     mainview_hbox.pack_start($mainview = MainView.new, true, true)
     main_vbox.pack_start(mainview_hbox, true, true)
     $imagesline_sw = Gtk::ScrolledWindow.new(nil, nil)
@@ -1249,15 +1350,11 @@ def create_main_window
         true
     }
 
-    Gtk.timeout_add(10000) {
-        show_mem
-        true
-    }
     $main_window.show_all
 end
 
 
+handle_options
 Thread.abort_on_exception = true
 read_config
 Gtk.init
@@ -1276,7 +1373,6 @@ Gtk.init
 #    exit 1
 #end
 
-
 create_main_window
 check_config
 
index b56449e..84f7b8e 100644 (file)
@@ -301,6 +301,33 @@ module Booh
         gen_thumbnails(orig, allow_background, dests, xmldirorelem, type + '-')
     end
 
+    def gen_video_thumbnail(orig, dest_dir, orig_base, colorswap, frame_offset)
+        transcode_options = ''
+        if colorswap
+            transcode_options += '-k '
+        end
+        cmd = "mencoder '#{orig}' -nosound -ovc lavc -lavcopts vcodec=mjpeg -o '#{dest_dir}/#{orig_base}.avi' -frames #{frame_offset+26} -fps 25 >/dev/null 2>/dev/null"
+        msg 2, cmd
+        system cmd
+        if File.exists?("#{dest_dir}/#{orig_base}.avi")
+            cmd = "transcode -a 0 -c #{frame_offset}-#{frame_offset+1} -i '#{dest_dir}/#{orig_base}.avi' -y jpg -o '#{dest_dir}/#{orig_base}.jpg' #{transcode_options} 2>&1"
+            msg 2, cmd
+            results = subproc_runaway_aware(cmd)
+            File.delete(File.join(dest_dir, "#{orig_base}.avi"))
+            if results =~ /skipping frames/ && results =~ /encoded 0 frames/
+                msg 0, _("specified frame-offset too large? max frame was: %s. that may also be another probleme. try another value.") % results.scan(/skipping frames \[000000-(\d+)\]/)[-1]
+                return false
+            elsif results =~ /V: import format.*unknown/ || !File.exists?("#{dest_dir}/#{orig_base}.jpg000000.jpg")
+                msg 0, _("could not extract first image of video %s encoded by mencoder") % "#{dest_dir}/#{orig_base}.avi"
+                return false
+            end
+        else
+            msg 0, _("could not make mencoder to encode %s to mjpeg") % orig
+            return false
+        end
+        return true
+    end
+
     def gen_thumbnails(orig, allow_background, dests, felem, attributes_prefix)
         if !dests.detect { |dest| !File.exists?(dest['filename']) } 
             return true
@@ -351,7 +378,7 @@ module Booh
                 if allow_background
                     waitjobs
                 end
-                system("rm -f '#{neworig}'")
+                File.delete(neworig)
             end
             return true
 
@@ -372,33 +399,10 @@ module Booh
             end
             orig_base = File.basename(dests[0]['filename']) + File.basename(orig)
             orig_image = "#{dest_dir}/#{orig_base}.jpg000000.jpg"
-            system("rm -f '#{orig_image}'")
+            File.delete(orig_image)
             for dest in dests
-                if !File.exists?(orig_image)
-                    transcode_options = ''
-                    if felem
-                        if felem.attributes["#{attributes_prefix}color-swap"]
-                            transcode_options += '-k '
-                        end
-                    end
-                    cmd = "mencoder '#{orig}' -nosound -ovc lavc -lavcopts vcodec=mjpeg -o '#{dest_dir}/#{orig_base}.avi' -frames #{frame_offset+26} -fps 25 >/dev/null 2>/dev/null"
-                    msg 2, cmd
-                    system cmd
-                    if File.exists?("#{dest_dir}/#{orig_base}.avi")
-                        cmd = "transcode -a 0 -c #{frame_offset}-#{frame_offset+1} -i '#{dest_dir}/#{orig_base}.avi' -y jpg -o '#{dest_dir}/#{orig_base}.jpg' #{transcode_options} 2>&1"
-                        msg 2, cmd
-                        results = subproc_runaway_aware(cmd)
-                        system("rm -f '#{dest_dir}/#{orig_base}.avi'")
-                        if results =~ /skipping frames/ && results =~ /encoded 0 frames/
-                            msg 0, _("specified frame-offset too large? max frame was: %s. that may also be another probleme. try another value.") %
-                                results.scan(/skipping frames \[000000-(\d+)\]/)[-1]
-                            return false
-                        elsif results =~ /V: import format.*unknown/ || !File.exists?(orig_image)
-                            msg 0, _("could not extract first image of video %s encoded by mencoder") % "#{dest_dir}/#{orig_base}.avi"
-                            return false
-                        end
-                    else
-                        msg 0, _("could not make mencoder to encode %s to mjpeg") % orig
+                if ! File.exists?(orig_image)
+                    if ! gen_video_thumbnail(orig, dest_dir, orig_base, felem && felem.attributes["#{attributes_prefix}color-swap"], frame_offset)
                         return false
                     end
                     if felem && whitebalance = felem.attributes["#{attributes_prefix}white-balance"]
@@ -427,7 +431,7 @@ module Booh
                 end
             end
             if neworig
-                system("rm -f '#{neworig}'")
+                File.delete(neworig)
             end
             return true
         end
@@ -818,6 +822,14 @@ module Enumerable
     end
 end
 
+class Array
+    def sum
+        retval = 0
+        each { |v| retval += v.to_i }
+        return retval
+    end
+end
+
 class REXML::Element
     def previous_element_byname(name)
         n = self