Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # Version 1.0 (30.01.2012)
- #
- # Copyright (c) 2012 Vladar ([email protected])
- #
- # Permission is hereby granted, free of charge, to any person
- # obtaining a copy of this software and associated documentation
- # files (the "Software"), to deal in the Software without
- # restriction, including without limitation the rights to use,
- # copy, modify, merge, publish, distribute, sublicense, and/or sell
- # copies of the Software, and to permit persons to whom the
- # Software is furnished to do so, subject to the following
- # conditions:
- #
- # The above copyright notice and this permission notice shall be
- # included in all copies or substantial portions of the Software.
- #
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- # OTHER DEALINGS IN THE SOFTWARE.
- #
- #
- # REQUIRED MODULES:
- # python-tk, python-imaging, python-imaging-tk
- #
- #
- # CONTROLS:
- # All tags list:
- # move to selected tags - Double click, Enter
- # move to excluded tags - Right click, Backspace
- # Selected tags list:
- # move to all tags - Double click, Enter
- # move to excluded tags - Right click, Backspace
- # Excluded tags list:
- # move to all tags - Double click, Enter
- # move to selected tags - Right click, Backspace
- #
- import os, sys, shutil, subprocess
- from Tkinter import *
- from tkMessageBox import showerror, askyesno
- from tkFileDialog import askdirectory, asksaveasfilename
- from PIL import Image, ImageTk
- ## CONFIG ##
- # preview sizes
- PREVIEW_SMALL = 128
- PREVIEW_MEDIUM = 256
- PREVIEW_BIG = 512
- # tag separation symbol
- SEPARATOR = "."
- # default preview size
- PREVIEW = PREVIEW_MEDIUM
- # preview filter (NEAREST, BILINEAR, BICUBIC, ANTIALIAS)
- FILTER = Image.NEAREST
- ## CONST ##
- KiB = 1024
- MiB = 1048576
- GiB = 1073741824
- ## GLOBAL ##
- _tags = list()
- _filter = list()
- ## FUNCTIONS ##
- def _tag_search(arg, dirname, names):
- if dirname != ".":
- # get tags from dirname
- dirtags = os.path.split(dirname)[1].split(SEPARATOR)
- for dirtag in dirtags:
- tag_add(dirtag)
- for name in names:
- # get tags from filename
- nametags = name.split(SEPARATOR)[1:-1]
- for nametag in nametags:
- tag_add(nametag)
- def _tag_filter(tags, dirname, names):
- inc = tags[0]
- exc = tags[1]
- # check for tags in dirname
- dirtags = list()
- for subdir in dirname.split(os.sep)[1:]:
- dirtags += os.path.split(subdir)[1].split(SEPARATOR)
- # if excluded tags in dirtags
- for item in exc:
- if item in dirtags:
- return
- for i in xrange(len(dirtags)):
- dirtags[i] = unicode(dirtags[i], "utf-8")
- match_dir = [item for item in inc if item in dirtags]
- if match_dir:
- # not-in-dirname tags
- inc_left = [item for item in inc if not item in match_dir]
- else:
- inc_left = list(inc)
- inc_left.sort()
- for name in names:
- filename = os.path.join(dirname, name)
- if os.path.isfile(filename):
- # check for tags in filename
- nametags = name.split(SEPARATOR)[1:-1]
- for i in xrange(len(nametags)):
- nametags[i] = unicode(nametags[i], "utf-8")
- # if excluded tags in nametags
- exc_in_name = [item for item in exc if item in nametags]
- if exc_in_name:
- break
- match_name = [item for item in inc_left if item in nametags]
- match_name.sort()
- if match_name == inc_left:
- _filter.append(filename)
- def tag_add(tag):
- if not tag in _tags:
- _tags.append(tag)
- def tag_search():
- del _tags[:]
- os.path.walk(".", _tag_search, None)
- _tags.sort()
- def tag_filter(tags, xtags=[]):
- del _filter[:]
- os.path.walk(".", _tag_filter, (tags, xtags))
- _filter.sort()
- ## GUI ##
- # global #
- _list_all_tags = None
- _list_sel_tags = None
- _list_exc_tags = None
- _list_filtered = None
- _edit_filename = None
- _image_preview = None
- _image_info = None
- _zoom = 1.0
- _index = -1
- _name = None
- # functions #
- def attach_scroll(listbox, scrollbar, side="left", fill="y"):
- scrollbar.pack(side=side, fill=fill)
- listbox.config(yscrollcommand=scrollbar.set)
- scrollbar.config(command=listbox.yview)
- def sort_listbox(listbox):
- temp_list = list(listbox.get(0, END))
- temp_list.sort()
- listbox.delete(0, END)
- for item in temp_list:
- listbox.insert(END, item)
- def get_all_tags():
- tag_search()
- sel_tags = _list_sel_tags.get(0, END)
- exc_tags = _list_exc_tags.get(0, END)
- _list_all_tags.delete(0, END)
- _list_sel_tags.delete(0, END)
- _list_exc_tags.delete(0, END)
- for tag in _tags:
- if tag not in sel_tags and tag not in exc_tags:
- _list_all_tags.insert(END, tag)
- for tag in sel_tags:
- if tag in _tags:
- _list_sel_tags.insert(END, tag)
- for tag in exc_tags:
- if tag in _tags:
- _list_exc_tags.insert(END, tag)
- def get_filtered():
- # clear
- _list_filtered.delete(0, END)
- _edit_filename.delete(0, END)
- _image_preview.config(image=None)
- _image_preview.image = None
- _image_info.config(text="")
- # get tags
- tags = _list_sel_tags.get(0, END)
- xtags = _list_exc_tags.get(0, END)
- # filter
- tag_filter(tags, xtags)
- for filename in _filter:
- _list_filtered.insert(END, filename)
- global _index, _name
- _index = -1
- _name = None
- def select_dir():
- dir = askdirectory()
- if dir:
- os.chdir(dir)
- _list_sel_tags.delete(0, END)
- _list_exc_tags.delete(0, END)
- get_all_tags()
- get_filtered()
- def move_tag(src, dst):
- selected = src.curselection()
- if selected:
- tag = src.selection_get()
- if tag:
- dst.insert(0, tag)
- src.delete(selected[0])
- sort_listbox(dst)
- get_filtered()
- def on_tag_from_all_to_sel(event):
- move_tag(_list_all_tags, _list_sel_tags)
- def on_tag_from_sel_to_all(event):
- move_tag(_list_sel_tags, _list_all_tags)
- def on_tag_from_all_to_exc(event):
- move_tag(_list_all_tags, _list_exc_tags)
- def on_tag_from_exc_to_all(event):
- move_tag(_list_exc_tags, _list_all_tags)
- def on_tag_from_sel_to_exc(event):
- move_tag(_list_sel_tags, _list_exc_tags)
- def on_tag_from_exc_to_sel(event):
- move_tag(_list_exc_tags, _list_sel_tags)
- def get_size_str(filename):
- """get_size_str(filename) -> str
- Return string with filename size.
- """
- try:
- sz = os.path.getsize(filename)
- except:
- return ""
- if sz < KiB:
- return "%d B" % (sz,)
- elif sz < MiB:
- return "%.3f KiB" % (float(sz)/KiB,)
- elif sz < GiB:
- return "%.3f MiB" % (float(sz)/MiB,)
- else:
- return "%.3f GiB" % (float(sz)/GiB,)
- def on_select_file(event=None):
- global _index, _name
- if _list_filtered.curselection():
- _index = _list_filtered.curselection()[0]
- _name = _list_filtered.selection_get()
- # show filename
- _edit_filename.delete(0, END)
- _edit_filename.insert(0, _name)
- # show thumbnail
- try:
- image = Image.open(_name)
- except:
- _image_preview.config(image=None)
- _image_preview.image = None
- _image_info.config(text="%s\n%s" % (
- os.path.basename(_name), get_size_str(_name),))
- return
- w, h = image.size
- image.thumbnail((PREVIEW, PREVIEW), FILTER)
- imagetk = ImageTk.PhotoImage(image)
- _image_preview.config(image=imagetk)
- _image_preview.image = imagetk
- # show image info
- info = "%dx%d\n%s" % (w, h, get_size_str(_name))
- _image_info.config(text=info)
- def preview_small():
- global PREVIEW
- PREVIEW = PREVIEW_SMALL
- _image_preview.config(width=PREVIEW, height=PREVIEW)
- on_select_file()
- def preview_medium():
- global PREVIEW
- PREVIEW = PREVIEW_MEDIUM
- _image_preview.config(width=PREVIEW, height=PREVIEW)
- on_select_file()
- def preview_big():
- global PREVIEW
- PREVIEW = PREVIEW_BIG
- _image_preview.config(width=PREVIEW, height=PREVIEW)
- on_select_file()
- def do_del(event=None):
- """Delete selected file"""
- if _index >= 0:
- if askyesno("Delete", "Are you sure?"):
- try:
- os.remove(_name)
- except:
- showerror(title="Error",
- message="Cannot remove the file")
- return
- idx = int(_index)
- get_all_tags()
- get_filtered()
- _list_filtered.focus_set()
- if idx >= _list_filtered.size(): _list_filtered.see(END)
- else: _list_filtered.see(idx)
- _list_filtered.activate(idx)
- def do_renmov(event=None):
- """Rename/move selected file"""
- if _index >= 0:
- dst = _edit_filename.get()
- if _name != dst:
- try:
- os.renames(_name, dst)
- except:
- showerror(title="Error",
- message="Cannot rename/move the file")
- return
- get_all_tags()
- get_filtered()
- _list_filtered.focus_set()
- try:
- idx = _filter.index(dst)
- except:
- idx = _index
- _list_filtered.see(idx)
- _list_filtered.activate(idx)
- def do_copy():
- """Copy selected file"""
- if _index >= 0:
- dst = asksaveasfilename(initialfile=os.path.basename(_name))
- if dst:
- try:
- shutil.copy2(_name, dst)
- except:
- showerror(title="Error",
- message="Cannot copy the file")
- return
- idx = int(_index)
- get_all_tags()
- get_filtered()
- _list_filtered.focus_set()
- _list_filtered.see(idx)
- _list_filtered.activate(idx)
- _edit_filename.delete(0, END)
- # viewer #
- def on_view(event):
- if _index >= 0:
- if os.name == "posix":
- subprocess.Popen(("xdg-open", _name))
- elif os.name == "nt":
- os.startfile(_name)
- elif os.name == "mac":
- subprocess.Popen(("open", _name))
- # gui setup function #
- def gui():
- global _list_all_tags,\
- _list_sel_tags,\
- _list_exc_tags,\
- _list_filtered,\
- _edit_filename,\
- _image_preview,\
- _image_info
- # root
- root = Tk()
- root.title("TIN")
- # root -> frame_menu
- frame_menu = Frame(root)
- frame_menu.pack(side="top", fill="x")
- # root -> frame_menu -> btn_dir
- btn_dir = Button(frame_menu,
- text="Select dir", command=select_dir)
- btn_dir.pack(side="left")
- # root -> frame_menu -> btn_reload_tags
- btn_reload_tags = Button(frame_menu,
- text="Reload tags", command=get_all_tags)
- btn_reload_tags.pack(side="left")
- # root -> frame_menu -> btn_preview_big
- btn_preview_big = Button(frame_menu,
- text="%d" % (PREVIEW_BIG,), command=preview_big)
- btn_preview_big.pack(side="right")
- # root -> frame_menu -> btn_preview_medium
- btn_preview_medium = Button(frame_menu,
- text="%d" % (PREVIEW_MEDIUM,), command=preview_medium)
- btn_preview_medium.pack(side="right")
- # root -> frame_menu -> btn_preview_small
- btn_preview_small = Button(frame_menu,
- text="%d" % (PREVIEW_SMALL,), command=preview_small)
- btn_preview_small.pack(side="right")
- # root -> frame_top
- frame_top = Frame(root)
- frame_top.pack(side="top", fill="both", expand=1)
- # root -> frame_top -> pan
- pan = PanedWindow(frame_top, orient="vertical")
- pan.pack(side="left", fill="both", expand=1)
- # root -> frame_top -> pan -> frame_tags
- frame_tags = Frame(pan)
- pan.add(frame_tags)
- # root -> frame_top -> pan -> frame_tags -> _list_all_tags
- _list_all_tags = Listbox(frame_tags, height=8)
- _list_all_tags.pack(side="left", fill="both", expand=1)
- _list_all_tags.bind("<Double-Button-1>", on_tag_from_all_to_sel)
- _list_all_tags.bind("<Return>", on_tag_from_all_to_sel)
- _list_all_tags.bind("<Button-3>", on_tag_from_all_to_exc)
- _list_all_tags.bind("<BackSpace>", on_tag_from_all_to_exc)
- scroll_list_all_tags = Scrollbar(frame_tags)
- attach_scroll(_list_all_tags, scroll_list_all_tags)
- # root -> frame_top -> pan -> frame_tags -> _list_sel_tags
- _list_sel_tags = Listbox(frame_tags, height=8)
- _list_sel_tags.pack(side="left", fill="both", expand=1)
- _list_sel_tags.bind("<Double-Button-1>", on_tag_from_sel_to_all)
- _list_sel_tags.bind("<Return>", on_tag_from_sel_to_all)
- _list_sel_tags.bind("<Button-3>", on_tag_from_sel_to_exc)
- _list_sel_tags.bind("<BackSpace>", on_tag_from_sel_to_exc)
- scroll_list_sel_tags = Scrollbar(frame_tags)
- attach_scroll(_list_sel_tags, scroll_list_sel_tags)
- # root -> frame_top -> pan -> frame_tags -> _list_exc_tags
- _list_exc_tags = Listbox(frame_tags, height=8)
- _list_exc_tags.pack(side="left", fill="both", expand=1)
- _list_exc_tags.bind("<Double-Button-1>", on_tag_from_exc_to_all)
- _list_exc_tags.bind("<Return>", on_tag_from_exc_to_all)
- _list_exc_tags.bind("<Button-3>", on_tag_from_exc_to_sel)
- _list_exc_tags.bind("<BackSpace>", on_tag_from_exc_to_sel)
- scroll_list_exc_tags = Scrollbar(frame_tags)
- attach_scroll(_list_exc_tags, scroll_list_exc_tags)
- # root -> frame_top -> pan -> frame_files
- frame_files = Frame(pan)
- pan.add(frame_files)
- # root -> frame_top -> pan -> frame_files -> _list_filtered
- _list_filtered = Listbox(frame_files, height=10)
- _list_filtered.pack(side="left", fill="both", expand=1)
- _list_filtered.bind("<ButtonRelease-1>", on_select_file)
- _list_filtered.bind("<KeyRelease>", on_select_file)
- _list_filtered.bind("<Delete>", do_del)
- scroll_list_filtered = Scrollbar(frame_files)
- attach_scroll(_list_filtered, scroll_list_filtered)
- # root -> frame_top -> _image_preview
- img = PhotoImage()
- _image_preview = Label(
- frame_top, image=img, cursor="hand2",
- width=PREVIEW, height=PREVIEW)
- _image_preview.pack(side="top")
- _image_preview.bind("<Button-1>", on_view)
- # root -> frame_top -> _image_info
- _image_info = Message(frame_top, justify=CENTER, aspect=1000000)
- _image_info.pack(side="top", fill="x")
- # root -> frame_actions
- frame_actions = Frame(root)
- frame_actions.pack(side="bottom", fill="x")
- # root -> frame_actions -> btn_del
- btn_del = Button(frame_actions,
- text="Delete", command=do_del)
- btn_del.pack(side="left")
- # root -> frame_actions -> _edit_filename
- _edit_filename = Entry(frame_actions)
- _edit_filename.pack(side="left", fill="x", expand=1)
- _edit_filename.bind("<Return>", do_renmov)
- # root -> frame_actions -> btn_copy
- btn_copy = Button(frame_actions,
- text="Copy", command=do_copy)
- btn_copy.pack(side="right")
- # root -> frame_actions -> btn_renmov
- btn_renmov = Button(frame_actions,
- text="Rename/Move", command=do_renmov)
- btn_renmov.pack(side="right")
- get_all_tags()
- get_filtered()
- root.mainloop()
- def main():
- if len(sys.argv) > 1:
- os.chdir(sys.argv[1])
- gui()
- if __name__ == '__main__':
- main()
Advertisement
Add Comment
Please, Sign In to add comment