Nightly update. There's some cleanup on the bottom pane.

On 9/18/06, Edward Duffy <[EMAIL PROTECTED]> wrote:
On 9/18/06, Jamie McCracken <[EMAIL PROTECTED]> wrote:
> Edward Duffy wrote:
> > Just another quick addition...does this interface for adding tags make
> > sense?  I kinda like it, but I can see it being confusing at first....
> >
> > On 9/17/06, Edward Duffy <[EMAIL PROTECTED]> wrote:
> >> Here's an update where I've started some work on the bottom pane.
> >> It's still going to need some serious love, but some of the idea's in
> >> Jamie's Sep 14 email are starting to be incorporated.
> >>
>
> hey that rocks :)
>
> love the tags + button too
>
Thanks. Now it just needs a recent pop-under that shows available tags
(like Epiphany)

> There are a few minor things
>
> There should be 3 columns as follows:
>
I was thinking about having this dynamic based on the size of the
window and the size of the columns, but this sounds much cleaner (and
easier!).

> 1)  as now + include all basic matadata here like tags, rank, file size
> etc (I dont think we need to display permissions). The column should
> wrap so that tags dont infringe on other cols
I gave the entire bottom row to tags because I wasn't sure how many
tags most people associate with a file.  I don't think I've used
anymore than 2, but I thought it might look funny if it wrapped...even
more so now with a text entry and two buttons (when you're adding a
tag).

>
> 2) The middle column should be for service specific metadata (like Music
> stuff for music files). For plain files this column should be invisible
>
easy
> 3) The last column should show a few lines of the so text contents in a
> scrollable fashion. If no contents then this column will be invsible
>
Sure..there's a method to do this already, I beleive.

> also we should have a button to view/edit all metadata for a file in a grid
that shouldn't be too bad..there's enough introspection information in
there that should make this pretty straight forward.  Is there any
error checking on tracker's end? ie, does it make sure that File.Rank
is an integer from 1 to 10?

>
> Going to be fun converting that to C.
yeah, i feel sorry for that poor bastard. ;)

>
>
>
> --
> Mr Jamie McCracken
> http://jamiemcc.livejournal.com/
>

#!/usr/bin/env python

import os
import os.path
import sys

import gtk
import pango
import gconf
import dbus

import md5
import urllib

from getopt import getopt

SERVICES = [
      ( 'Files',             'system-file-manager'      ),
      ( 'Folders',           'folder'                   ),
      ( 'Applications',      'application-x-executable' ),
      ( 'Conversations',     'face-smile-big'           ),
      ( 'Contacts',          'x-office-address-book'    ),
      ( 'Development Files', 'applications-development' ),
      ( 'Documents',         'x-office-document'        ),
      ( 'Emails',            'email'                    ),
      ( 'Images',            'image-x-generic'          ),
      ( 'Music',             'audio-x-generic'          ),
      ( 'Text Files',        'text-x-generic'           ),
      ( 'Videos',            'video-x-generic'          ),
   ]

DISPLAY_METADATA = {
      'Files'     : [ 'file.name', 'file.format', 'file.path', 'file.size', 'file.rank', ],
      'Music'     : [ 'audio.artist', 'audio.album', 'audio.trackno', 'audio.title', 'audio.codec' ],
      'Documents' : [ 'doc.title', 'doc.author', 'doc.subject' ],
      'Images'    : [ 'image.title', 'image.height', 'image.width' ],
   }

def FileSizeFormat(hbox, size):
   label = gtk.Label()
   size = int(size)
   if size < 2**10:
      label.set_text('%d bytes' % size)
   elif size < 2**20:
      label.set_text('%3.1f KB' % (size / 2.**10))
   elif size < 2**30:
      label.set_text('%3.1f MB' % (size / 2.**20))
   elif size < 2**40:
      label.set_text('%3.1f GB' % (size / 2.**30))
   hbox.pack_start(label, expand=False, fill=False)

def FileRankFormat(hbox, rank):
   if not rank:
      rank='7'
   i = 0
   rank = float(rank) / 2.
   while rank > 0.5:
      hbox.pack_start(gtk.image_new_from_icon_name('weather-clear', gtk.ICON_SIZE_MENU), expand=False, fill=False)
      i += 1
      rank -= 1
   if rank == 0.5:
      hbox.pack_start(gtk.image_new_from_icon_name('weather-few-clouds', gtk.ICON_SIZE_MENU), expand=False, fill=False)
      i += 1
   while i < 5:
      hbox.pack_start(gtk.image_new_from_icon_name('weather-overcast', gtk.ICON_SIZE_MENU), expand=False, fill=False)
      i += 1

def ImageSizeFormat(hbox, size):
   hbox.pack_start(gtk.Label(size + ' px'), expand=False, fill=False)

METADATA_LABELS = {
      'audio.trackno':'Track #'
   }
METADATA_FORMATTERS = {
      'file.size':FileSizeFormat,
      'file.rank':FileRankFormat,
      'image.height':ImageSizeFormat,
      'image.width':ImageSizeFormat,
   }

class Tracker:
   def __init__(self):
      bus = dbus.SessionBus()
      obj = bus.get_object('org.freedesktop.Tracker',
                           '/org/freedesktop/tracker')
      self.tracker = dbus.Interface(obj, 'org.freedesktop.Tracker')
      self.files = dbus.Interface(obj, 'org.freedesktop.Tracker.Files')
      self.search = dbus.Interface(obj, 'org.freedesktop.Tracker.Search')
      self.keywords = dbus.Interface(obj, 'org.freedesktop.Tracker.Keywords')
      self.metadata = dbus.Interface(obj, 'org.freedesktop.Tracker.Metadata')

   def __getattr__(self, attr):
      return getattr(self.tracker, attr)

class TrackerGUI:

   def __init__(self):
      
      self.gconf = gconf.client_get_default()
      self.icon_theme = gtk.icon_theme_get_default()
      self.tracker = Tracker()

      self.layout = 1
      self.max_results = 20
      opts,args = getopt(sys.argv[1:], '', ['layout=', 'max-hits='])
      for a,v in opts:
         if a == '--layout':
            self.layout = int(v)
         elif a == '--max-hits':
            self.max_results = int(v)

      self.window = gtk.Window()
      self.window.set_title('Tracker')

      main_vbox = gtk.VBox()
      #main_vbox.set_border_width(12)
      main_vbox.set_spacing(6)

      hbox = gtk.HBox()
      hbox.set_spacing(6)
      hbox.set_border_width(12)

      label = gtk.Label('_Search:')
      hbox.pack_start(label, expand=False, fill=False)

      self.search_entry = gtk.Entry()
      hbox.pack_start(self.search_entry, expand=True, fill=True)

      label.props.use_underline = True
      label.set_mnemonic_widget(self.search_entry)

      if self.layout == 1:
         self.service_combobox = gtk.ComboBox()
         store = gtk.ListStore(gtk.gdk.Pixbuf, str)
         self.service_combobox.set_model(store)
         cell = gtk.CellRendererPixbuf()
         self.service_combobox.pack_start(cell, False)
         self.service_combobox.add_attribute(cell, 'pixbuf', 0)
         cell = gtk.CellRendererText()
         self.service_combobox.pack_start(cell, False)
         self.service_combobox.add_attribute(cell, 'text', 1)
         for label, icon_name in SERVICES:
            pixbuf = self.icon_theme.load_icon(icon_name,
               gtk.ICON_SIZE_MENU, gtk.ICON_LOOKUP_USE_BUILTIN)
            store.append([pixbuf, label])
         self.service_combobox.set_active(0)
         hbox.pack_start(self.service_combobox, expand=False, fill=True)


      self.search_button = gtk.Button(stock='gtk-find')
      self.search_button.set_data('offset', 0)
      hbox.pack_start(self.search_button, expand=False, fill=False)

      main_vbox.pack_start(hbox, expand=False, fill=False)

      hbox = gtk.HBox()

      if self.layout == 2:
         self.service_treeview = gtk.TreeView()
         store = gtk.ListStore(gtk.gdk.Pixbuf, str)
         self.service_treeview.set_model(store)
         #self.service_treeview.set_sensitive(False)
         self.service_treeview.set_headers_visible(False)
         self.service_treeview.set_row_separator_func(lambda model,iter: model[iter][1] == '')

         cell = gtk.CellRendererPixbuf()
         col = gtk.TreeViewColumn('', cell, pixbuf=0)
         self.service_treeview.append_column(col)
         cell = gtk.CellRendererText()
         col = gtk.TreeViewColumn('', cell, text=1)
         self.service_treeview.append_column(col)

         for label, icon_name in SERVICES:
            pixbuf = self.icon_theme.load_icon(icon_name,
               gtk.ICON_SIZE_MENU, gtk.ICON_LOOKUP_USE_BUILTIN)
            store.append([pixbuf, label])
         store.append([None,''])
         tags = self.tracker.keywords.GetList('Files')
         for tag,count in tags.items():
            store.append([None, tag])
      
         selection = self.service_treeview.get_selection()
         selection.select_iter(store.get_iter_first())
         selection.connect('changed', self.on_service_selection_changed)

         sw = gtk.ScrolledWindow()
         sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
         sw.set_shadow_type(gtk.SHADOW_IN)
         sw.add(self.service_treeview)
         hbox.pack_start(sw, expand=False, fill=True)
         
      sw = gtk.ScrolledWindow()
      sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
      sw.set_shadow_type(gtk.SHADOW_IN)

      if self.layout in (1,2,3,):
         self.icon_view = gtk.IconView()
         store = gtk.ListStore(gtk.gdk.Pixbuf, str, str)
         self.icon_view.set_model(store)
         self.icon_view.set_pixbuf_column(0)
         self.icon_view.set_text_column(1)
         sw.add(self.icon_view)
      elif self.layout == 4:
         self.results_tree = gtk.TreeView()
         store = gtk.TreeStore(gtk.gdk.Pixbuf, str, str)
         self.results_tree.set_model(store)
         self.results_tree.set_headers_visible(False)

         cell = gtk.CellRendererPixbuf()
         col = gtk.TreeViewColumn('', cell, pixbuf=0)
         self.results_tree.append_column(col)
         cell = gtk.CellRendererText()
         col = gtk.TreeViewColumn('', cell, text=1)
         self.results_tree.append_column(col)

         self._fill_in_services(store)
         sw.add(self.results_tree)
         sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)

      if self.layout == 3:
         self.notebook = gtk.Notebook()
         label = gtk.Label('Files')
         self.notebook.append_page(sw, label)
         main_vbox.pack_start(self.notebook, expand=True, fill=True)
      else:
         self.result_label = gtk.Label('')
         hb = gtk.HBox()
         hb.set_border_width(6)
         hb.pack_start(self.result_label, expand=False, fill=False)
         vb = gtk.VBox()
         vb.pack_start(hb, expand=False, fill=False)
         vb.pack_start(sw, expand=True, fill=True)
         hbox.pack_start(vb, expand=True, fill=True)
         main_vbox.pack_start(hbox, expand=True, fill=True)

      if self.layout != 4:
         hbox = gtk.HBox()
         hbox.set_spacing(6)

         self.last_button = gtk.Button(stock='gtk-goto-last')
         self.last_button.set_sensitive(False)
         hbox.pack_end(self.last_button, expand=False, fill=False)

         self.next_button = gtk.Button(stock='gtk-go-forward')
         self.next_button.get_children()[0].get_children()[0].get_children()[1].set_text('Next')
         self.next_button.set_sensitive(False)
         hbox.pack_end(self.next_button, expand=False, fill=False)

         image = gtk.image_new_from_stock('gtk-go-back', gtk.ICON_SIZE_BUTTON)
         self.previous_button = gtk.Button()
         self.previous_button.add(image)
         self.previous_button.set_sensitive(False)
         hbox.pack_end(self.previous_button, expand=False, fill=False)
      
         image = gtk.image_new_from_stock('gtk-goto-first', gtk.ICON_SIZE_BUTTON)
         self.first_button = gtk.Button()
         self.first_button.add(image)
         self.first_button.set_sensitive(False)
         self.first_button.set_data('offset', 0)
         hbox.pack_end(self.first_button, expand=False, fill=False)
      
         main_vbox.pack_start(hbox, expand=False, fill=False)

      self.bottom_pane = gtk.HBox()
      self.bottom_pane_content = gtk.HBox()
      self.bottom_pane.pack_start(self.bottom_pane_content, expand=True, fill=True)

      self.hide_bottom_pane_button = gtk.Button()
      image = gtk.image_new_from_stock('gtk-close', gtk.ICON_SIZE_MENU)
      self.hide_bottom_pane_button.add(image)
      self.hide_bottom_pane_button.set_relief(gtk.RELIEF_NONE)
      vbox = gtk.VBox()
      vbox.pack_start(self.hide_bottom_pane_button, expand=False, fill=False)
      self.bottom_pane.pack_start(vbox, expand=False, fill=False)

      vbox = gtk.VBox()
      vbox.pack_start(main_vbox, expand=True, fill=True)
      vbox.pack_start(self.bottom_pane, expand=False, fill=True)
      self.statusbar = gtk.Statusbar()
      vbox.pack_start(self.statusbar, expand=False, fill=False)
      
      self.window.add(vbox)

      self.search_entry.connect('activate', lambda e: self.search_button.emit('clicked'))
      self.search_button.connect('clicked', self.get_search_stats)
      if self.layout == 3:
         self.search_button.connect('clicked', self.build_service_tabs)

      if self.layout == 4:
         self.search_button.connect('clicked', self.on_complete_search)
         self.results_tree.get_selection().connect('changed', self.on_result_selected)
      else:
         self.icon_view.connect('selection-changed', self.on_result_selected)
         self.search_button.connect('clicked', self.on_search)
         self.first_button.connect('clicked', self.on_search)
         self.next_button.connect('clicked', self.on_search)
         self.previous_button.connect('clicked', self.on_search)
         self.last_button.connect('clicked', self.on_search)
      self.hide_bottom_pane_button.connect('clicked', lambda *e: self.bottom_pane.hide())
      self.window.connect('destroy', gtk.main_quit)

      self.window.resize(640, 480)
      self.window.show_all()
      self.result_label.hide()

   def get_search_stats(self, button):
      self.search_stats = { }
      done = False
      offset = 0
      query = self.search_entry.get_text()
      while not done:
         if query.startswith('tag:'):
            results = self.tracker.keywords.Search(-1, 'Files', [query[4:]], offset, 512)
         else:
            results = self.tracker.search.Text(-1, 'Files', query, offset, 512, False)
         for r in results:
            service = self.tracker.files.GetServiceType(r)
            self.search_stats.setdefault(service, 0)
            self.search_stats[service] += 1
         offset += len(results)
         done = (len(results) < 512)
      self.search_stats['Files'] = offset
      self.last_button.set_data('offset', offset - offset % self.max_results)
      self.last_button.set_sensitive(True)
      print self.search_stats

   def on_search(self, button):
      query = self.search_entry.get_text()
      offset = button.get_data('offset')
      if self.layout == 1:
         service = SERVICES[self.service_combobox.get_active()][0]
      elif self.layout == 2:
         store, iter = self.service_treeview.get_selection().get_selected()
         service = store[iter][1]
      elif self.layout == 3:
         service = self.notebook.get_tab_label(self.icon_view.get_parent()).get_text()

      if query.startswith('tag:'):
         results = self.tracker.keywords.Search(-1, service,
                              [ query[4:] ], offset, self.max_results + 1)
      else:
         results = self.tracker.search.Text(-1, service,
                              query, offset, self.max_results + 1, False)
      self.result_label.set_markup('Showing results <b>%d</b> - <b>%d</b> of <b>%d</b>.'
                % (offset + 1,
                  offset + min(len(results), self.max_results),
                  self.search_stats[service]))
      self.result_label.show()

      if self.layout in (1,2,3,):
         store = self.icon_view.get_model()
         store.clear()
         for r in results[:self.max_results]:
            basename = os.path.basename(r)
            pixbuf = self._get_file_thumbnail_pixbuf(r) or self._get_mime_thumbnail(r)
            store.append([ pixbuf, basename, r ])
         self.icon_view.get_parent().get_vscrollbar().get_adjustment().value = 0

      self.first_button.set_sensitive(True)
      if offset > 0:
         self.previous_button.set_sensitive(True)
         self.previous_button.set_data('offset', offset - self.max_results)
      else:
         self.previous_button.set_sensitive(False)

      if len(results) == self.max_results + 1:
         self.next_button.set_sensitive(True)
         self.next_button.set_data('offset', offset + self.max_results)
      else:
         self.next_button.set_sensitive(False)

   def on_complete_search(self, button):
      query = self.search_entry.get_text()
      store = self.results_tree.get_model()
      store.clear()
      self._fill_in_services(store)
      iter = store.get_iter_first()
      while iter:
         service = store[iter][1]
         done = False
         offset = 0
         while not done:
            if query.startswith('tag:'):
               results = self.tracker.keywords.Search(-1, service,
                              [ query[4:] ], offset, self.max_results + 1)
            else:
               results = self.tracker.search.Text(-1, service, query, offset, 256, False)
            offset += len(results)
            for r in results:
               pixbuf = self._get_file_thumbnail_pixbuf(r) or self._get_mime_thumbnail(r)
               h = pixbuf.get_height()
               w = pixbuf.get_width()
               scale = max(h,w)
               h = int(h * 24. / scale)
               w = int(w * 24. / scale)
               pixbuf = pixbuf.scale_simple(w, h, gtk.gdk.INTERP_BILINEAR)
               store.append(iter, [pixbuf, r, r])
            done = (len(results) < 256)
         iter = store.iter_next(iter)

   def on_service_selection_changed(self, selection):
      self.on_search(self.search_button)
      
   def _get_file_thumbnail_pixbuf(self, f):
      uri = 'file://' + urllib.pathname2url(f)
      thumb = md5.new()
      thumb.update(uri)
      thumb = os.path.expanduser('~/.thumbnails/normal/%s.png' % thumb.hexdigest())
      try:
         return gtk.gdk.pixbuf_new_from_file(thumb)
      except:
         return None

   def _get_mime_thumbnail(self, f):
      return self.icon_theme.load_icon('image-loading', 32, gtk.ICON_LOOKUP_USE_BUILTIN)

   def _fill_in_services(self, store):
      for label, icon_name in SERVICES:
         pixbuf = self.icon_theme.load_icon(icon_name,
            gtk.ICON_SIZE_MENU, gtk.ICON_LOOKUP_USE_BUILTIN)
         store.append(None, [pixbuf, label, ''])

   def build_service_tabs(self, button):
      query = self.search_entry.get_text()
      services = set()

      done = False
      offset = 0
      while not done:
         results = self.tracker.search.Text(-1, 'Files', query, offset, 256, False)
         print len(results),'results.',results
         for r in results:
            print r, self.tracker.files.GetServiceType(r)
            #services.add(self.tracker.files.GetServiceType(r))
         offset += len(results)
         done = (len(results) < 256)
         print 'done:',done
      print services

   def on_result_selected(self, arg):
      self._clear_container(self.bottom_pane_content)
      if isinstance(arg, gtk.IconView):
         store = arg.get_model()
         selected = arg.get_selected_items()[0]
         path = store[selected][2]
      else:
         model, iter = arg.get_selected()
         path = model[iter][2]
      if not path:
         return

      service = self.tracker.files.GetServiceType(path)
      self.statusbar.push(0, '%s [%s]' % (path,service))

      main_hbox = gtk.HBox()  # 4 columns
      main_hbox.set_homogeneous(True)

      # Column #1: Thumbnail
      # TODO

      # Column #2: General File Properties
      keys = DISPLAY_METADATA['Files']
      metadata = self.tracker.metadata.Get('Files', path, keys)
      table = gtk.Table(len(keys) + 2, 2, False)
      table.set_col_spacings(6)
      table.set_row_spacings(6)
      label = gtk.Label('')
      label.set_markup('<span size="x-large">%s</span>' % metadata[0])
      label.set_selectable(True)
      label.set_ellipsize(pango.ELLIPSIZE_END)
      hbox = gtk.HBox()
      hbox.pack_start(label, expand=True, fill=True)
      table.attach(hbox, 0, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL)
      for n,(k,m) in enumerate(zip(keys,metadata)[1:]):
         # Build Key
         label = gtk.Label('')
         if k in METADATA_LABELS:
            label.set_markup('<b>%s:</b>' % METADATA_LABELS[k])
         else:
            label.set_markup('<b>%s:</b>' % k.split('.')[1].title())
         hbox = gtk.HBox()
         hbox.pack_end(label, expand=False, fill=False)
         table.attach(hbox, 0, 1, n+1, n+2, gtk.FILL, gtk.FILL)

         # Build Value
         hbox = gtk.HBox()
         if k in METADATA_FORMATTERS:
            METADATA_FORMATTERS[k](hbox, m)
         else:
            label = gtk.Label(m)
            label.set_selectable(True)
            label.set_ellipsize(pango.ELLIPSIZE_END)
            hbox.pack_start(label, fill=True, expand=True)
         table.attach(hbox, 1, 2, n+1, n+2, gtk.FILL | gtk.EXPAND, gtk.FILL)

      # Tag row widgets
      label = gtk.Label('')
      label.set_markup('<b>Tags:</b>')
      hbox = gtk.HBox()
      hbox.pack_end(label, expand=False, fill=False)
      table.attach(hbox, 0, 1, n+2, n+3, gtk.FILL, gtk.FILL)

      hbox1 = gtk.HBox()
      add_button = gtk.Button()
      image = gtk.image_new_from_stock('gtk-add', gtk.ICON_SIZE_BUTTON)
      add_button.add(image)
      add_button.set_relief(gtk.RELIEF_NONE)
      hbox1.pack_start(add_button, expand=False, fill=False)      

      tags = self.tracker.keywords.Get('Files', path)
      first = True
      for tag in tags:
         if not first:
            hbox1.pack_start(gtk.Label(','), expand=False, fill=False)
         label = gtk.Label()
         label.set_markup('<span foreground="blue"><u>%s</u></span>' % tag)
         btn = gtk.Button()
         btn.add(label)
         btn.set_relief(gtk.RELIEF_NONE)
         btn.connect('clicked', self.on_tag_selected)
         hbox1.pack_start(btn, expand=False, fill=False)
         first = False

      hbox2 = gtk.HBox()
      completion = gtk.EntryCompletion()
      completion.set_model(self._create_tag_model())
      completion.set_text_column(0)
      tag_entry = gtk.Entry()
      tag_entry.set_completion(completion)
      hbox2.pack_start(tag_entry, expand=False, fill=False)

      accept_button = gtk.Button()
      image = gtk.image_new_from_stock('gtk-apply', gtk.ICON_SIZE_BUTTON)
      accept_button.add(image)
      accept_button.set_relief(gtk.RELIEF_NONE)
      hbox2.pack_start(accept_button, expand=False, fill=False)
      
      cancel_button = gtk.Button()
      image = gtk.image_new_from_stock('gtk-cancel', gtk.ICON_SIZE_BUTTON)
      cancel_button.add(image)
      cancel_button.set_relief(gtk.RELIEF_NONE)
      hbox2.pack_start(cancel_button, expand=False, fill=False)
      
      hbox = gtk.HBox()
      hbox.pack_start(hbox1, expand=True, fill=True)
      hbox.pack_start(hbox2, expand=True, fill=True)
      table.attach(hbox, 1, 2, n+2, n+3, gtk.FILL, gtk.FILL)
      main_hbox.pack_start(table, expand=True, fill=True)

      # Tag widget signals
      tag_entry.connect('activate', lambda e: accept_button.emit('clicked'))
      add_button.connect('clicked', lambda b: (hbox1.hide(), hbox2.show(), tag_entry.grab_focus()))
      accept_button.connect('clicked', self.on_accept_tag_add, hbox1, hbox2, path, arg)
      cancel_button.connect('clicked', lambda b: (hbox1.show(), hbox2.hide(), tag_entry.set_text('')))

      # Column #3: Type specific metadata
      if service in DISPLAY_METADATA and DISPLAY_METADATA[service]:
         keys = DISPLAY_METADATA[service]
         metadata = self.tracker.metadata.Get('Files', path, keys)

         table = gtk.Table(len(keys), 2, False)
         table.set_col_spacings(6)
         table.set_row_spacings(6)
         for n,(k,m) in enumerate(zip(keys,metadata)):
            # Build Key
            label = gtk.Label('')
            if k in METADATA_LABELS:
               label.set_markup('<b>%s:</b>' % METADATA_LABELS[k])
            else:
               label.set_markup('<b>%s:</b>' % k.split('.')[1].title())
            hbox = gtk.HBox()
            hbox.pack_end(label, expand=False, fill=False)
            table.attach(hbox, 0, 1, n, n+1, gtk.FILL, gtk.FILL)

            # Build Value
            hbox = gtk.HBox()
            if k in METADATA_FORMATTERS:
               METADATA_FORMATTERS[k](hbox, m)
            else:
               label = gtk.Label(m)
               label.set_selectable(True)
               label.set_ellipsize(pango.ELLIPSIZE_END)
               hbox.pack_start(label, fill=True, expand=True)
            table.attach(hbox, 1, 2, n, n+1, gtk.FILL | gtk.EXPAND, gtk.FILL)

         main_hbox.pack_start(table, expand=True, fill=True)

      # Column #4: Sample contents
      query = self.search_entry.get_text()
      if not query.startswith('tag:'):
         contents = metadata = self.tracker.metadata.Get('Files', path, ['file.content'])
         if contents:
            contents = contents[0].replace('\n', '\\n')
            idx = contents.lower().find(query.lower())
            if idx > -1:
               start = max(0, idx - 75)
               end = min(len(contents), start + 150)
               text = gtk.TextView()
               text.get_buffer().set_text(contents[start:end])
#                                   .replace('<', '&lt;')
#                                   .replace('>', '&gt;')
#                                   .replace(query, '<b>%s</b>' % query))
               text.set_wrap_mode(gtk.WRAP_WORD)

               vbox = gtk.VBox()
               vbox.pack_start(text, expand=False, fill=False)
               frame = gtk.Frame('Contents')
               frame.add(vbox)
               main_hbox.pack_start(frame, expand=True, fill=True)

      main_hbox.set_spacing(12)
      main_hbox.show_all()
      hbox2.hide()
      self.bottom_pane_content.pack_start(main_hbox, expand=True, fill=True)

   def _clear_container(self, widget, parent=None):
      if isinstance(widget, gtk.Container):
         widget.foreach(self._clear_container, widget)
      if parent:
         parent.remove(widget)

   def _create_tag_model(self):
      store = gtk.ListStore(str)
      tags = self.tracker.keywords.GetList('Files')
      for tag,count in tags.items():
         store.append([tag])
      return store
   
   def on_tag_selected(self, button):
      tag = button.get_children()[0].get_text()
      self.search_entry.set_text('tag:%s' % tag)
      self.search_button.emit('clicked')

   def on_accept_tag_add(self, accept_button, hbox1, hbox2, path, selection):
      tag = hbox2.get_children()[0].get_text()
      self.tracker.keywords.Add('Files', path, [ tag ])
      self.on_result_selected(selection)


gui = TrackerGUI()
gtk.main()
_______________________________________________
tracker-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/tracker-list

Reply via email to