The filetagger is the second app-a-week project and the first PyPop application. It manages files in a simple
database and formats an HTML tag cloud which can link to them. It also implements a drop target so that
files can be added to an open database with a simple operation.
It is interpreted by PyPop, which is a wxPython-based GUI interpreter still in its infancy. For more information
and links to various relevant sites, visit the homepage.
[data].filelist = {}
[data].tags = []
[data].tag_counts = {}
for f in [data].loc('.files').elements():
[data].filelist[f['path']] = f
for tag in f['tags'].split():
try:
if [data].tags.index(tag) > -1: [data].tag_counts[tag] = [data].tag_counts[tag] + 1
except:
[data].tags.append(tag)
[data].tag_counts[tag] = 1
: reindex
: find_tags
if context['starting_tags'] != "":
: set selection some
: set tags %s % context['starting_tags']
: update_list
: update_cloud
if context['startcmd']:
: %s % context['startcmd']
if context['silent']:
: exit
[data].write(context['datafile'])
set selection some
set tags $tag
set tabshown Files
update_list
if context['selection'] == 'all':
file_list = [(f, f['path']) for f in [data].loc('.files').elements()]
else:
file_list = []
for file in [data].loc('.files').elements():
keys = file['tags'].split()
try:
if keys.index(context['tags']) > -1:
file_list.append ((file, file['path']))
except:
pass
[context].getboundfield('filelist').reload(file_list)
keys = [data].tags
keys.sort()
[context].getboundfield('tags').new_listbox_values('tags', keys)
if len( [data].tags) == 0:
[context]['html'] = "There are no files in the database.[[br>Add some by switching to the Files tab below."
return True
sm = 3.0
lg = 8.0
delta = lg - sm
links = []
maxcount = 0
for key in [data].tags:
if [data].tag_counts[key] > maxcount:
maxcount = [data].tag_counts[key]
for key in [data].tags:
weight = [data].tag_counts[key] * 1.0 / maxcount
font = int(sm + delta * weight)
links.append ('[[a href="cmd:show_tag %s">[[font size="%d">%s[[/font>[[/a>' \
% (key, font, key))
[context]['html'] = '\n'.join(links)
if len(files) == 0:
dlg = wx.FileDialog(self.frame, "Choose a file or files to add to the database", ".", "", "*.*", wx.OPEN|wx.MULTIPLE)
if dlg.ShowModal() == wx.ID_OK:
for path in dlg.GetPaths():
files = files + [path]
dlg.Destroy()
if len(files) == 0:
return True
elif len(files) == 1:
filerec = wftk.xmlobj (str="[[file/>")
filerec['path'] = files[0]
filerec['name'] = os.path.basename(filerec['path'])
if context['selection'] == 'some': filerec['tags'] = context['tags']
: if dialog mod; rec=filerec, title='Add file to database'
#if wxpywf.call_dialog(defn.search('dialog', 'id', 'mod'), [context], [context], \
# rec=filerec, title='Add file to database'):
[data].loc('.files').append_pretty(filerec)
else:
filesrec = wftk.xmlobj()
filesrec['numfiles'] = `len(files)`
if context['selection'] == 'some': filesrec['tags'] = context['tags']
filesrec['edit_each'] = 'yes'
silent = False
if defn['silent'] == 'yes': silent = True
: if dialog add; rec=filesrec, title='Add multiple files to database'
silent = True
#wxpywf.call_dialog(defn.search('dialog', 'id', 'add'), [context], [context], \
# rec=filesrec, title='Add multiple files to database'):
if silent:
for file in files:
filerec = wftk.xmlobj (str="[[file/>")
filerec['path'] = file
filerec['name'] = os.path.basename(filerec['path'])
for field in ('tags', 'description'): filerec[field] = filesrec[field]
if filesrec['edit_each'] == 'yes':
: if not dialog mod; rec=filerec, title='Adding file to database'
#if not wxpywf.call_dialog(defn.search('dialog', 'id', 'mod'), [context], \
# [context], rec=filerec, \
# title='Adding file to database'):
next
[data].loc('.files').append_pretty(filerec)
: reindex
: update_list
: find_tags
: update_cloud
: save
try:
rec = [data].filelist[context['filelist']]
except KeyError:
: notify "There is no file selected in the file list."
return True
if wxpywf.call_dialog(defn.search ('dialog', 'id', 'mod'), [context], [context], rec):
: reindex
: update_list
: find_tags
: update_cloud
: save
try:
rec = [data].filelist[context['filelist']]
except KeyError:
: notify "There is no file selected in the file list."
return True
if wxpywf.ask_user("Delete file %s from the database?\n(This will not delete the file itself.)" \
% context['filelist'], title="Deleting file") == wx.ID_YES:
rec.delete()
: reindex
: update_list
: find_tags
: update_cloud
: save
Assuming you have PyPop configured as the handler for files with extension .wftk,
the filetagger is run from the command line like this:
filetagger.wftk -fcst[tag] [database name] [command]
If the filetagger is installed in PyPop's application database, you can also run it like this:
pypop filetagger -fcst[tag] [database name] [command]
The flags are as follows:
-f: show the Files tab when starting
-c: show the Cloud tab when starting (default)
-s: run silently, i.e. just execute the command given and quit
-t[tag]: in the Files tab, filter for the tag given.
The database name is recommended; if omitted, the program will use "default.ftg" in the current directory.
Finally, the command can be one of the following:
add [filename] [filename]...
(In silent mode, no dialog will appear to elicit extra info; in that case, give it a tag with -t[tag]
and that tag will be attached to the files you've just added.) If you don't give any files, a common files dialog will come up to let you pick some.