1
0
mirror of https://github.com/gryf/pygtktalog.git synced 2025-12-17 19:40:21 +01:00

* Added exteranl image viewer.

* Added edit for descriptions and notes for files.
 * Added possibility for make thumbnail for any directory/file.
 * More improvements and bufixes.
This commit is contained in:
2008-04-14 13:29:50 +00:00
parent 371f702f9d
commit 3fd3b2ec19
8 changed files with 400 additions and 162 deletions

32
README
View File

@@ -10,9 +10,14 @@ which seems to be dead project for years.
FEATURES
========
- scanning for files in selected media
- generating thumbnails
- scan for files in selected media
- get/generate thumbnails from exif and other images
- most important exif tags
- add/edit description and notes
- fetch comments for images made in gThumb <http://gthumb.sourceforge.net>
- add/remove unlimited images to any file or directory
- tagging files <http://en.wikipedia.org/wiki/Tag_%28metadata%29>
- and more :)
REQUIREMENTS
============
@@ -57,13 +62,13 @@ For version 1.0 following aims have to be done:
- searching database
- tagging files
- user definied group of tags (represented by color in cloud tag)
- file details:
- files properties
x file details:
x files properties
x thumbnail
x description
x edit note and description
x exif information
- keywords (tags)
- gthumb integration
x gthumb integration
x adding images
x generating/saving thumbnails
x moving hardcoded files extensions into config
@@ -75,11 +80,12 @@ For version 2.0:
- Icon grid in files view
- command line support: query, adding media to collection etc
- internationalization support
- export to XLS
Removed:
- filetypes handling (movies, images, archives, documents etc). Now it have
common, unified external "plugin" system - simple output from command line
programs.
common, unified external "plugin" system - simple text output from command
line programs.
- anime/movie
- title
- alt title
@@ -90,16 +96,16 @@ Removed:
- sub lang
- release date (from - to)
- anidb link/imdb link
Maybe in future versions. Now text file descriptions and tags have to be
enough for good and fast information search.
Maybe in future versions. Now text file descriptions/notes and tags have to
be enough for good and fast information search.
- file information (date, size, etc) (50%) (no need for?)
NOTES
=====
Catalog file is tared and optionaly compressed sqlite database and directory
with thumbnails. If there are more images, the size of catalog file will grow.
So be carefull with adding big images in your catalog file!
Catalog file is tared and optionaly compressed sqlite database and directories
with images and thumbnails. If there are more images, the size of catalog file
will grow. So be carefull with adding big images in your catalog file!
BUGS
====

View File

@@ -59,6 +59,8 @@ class ConfigController(Controller):
self.view['ch_gthumb'].set_active(self.model.confd['gthumb'])
self.view['ch_compress'].set_active(self.model.confd['compress'])
self.view['ch_retrive'].set_active(self.model.confd['retrive'])
self.view['ch_imageviewer'].set_active(self.model.confd['imgview'])
self.view['entry_imv'].set_text(self.model.confd['imgprog'])
self.__toggle_scan_group()
@@ -118,21 +120,30 @@ class ConfigController(Controller):
self.model.confd['gthumb'] = self.view['ch_gthumb'].get_active()
self.model.confd['compress'] = self.view['ch_compress'].get_active()
self.model.confd['retrive'] = self.view['ch_retrive'].get_active()
self.model.confd['imgview'] = self.view['ch_imageviewer'].get_active()
self.model.confd['imgprog'] = self.view['entry_imv'].get_text()
self.model.save()
self.view['config'].destroy()
return
def on_button_ejt_clicked(self, button):
self.__show_filechooser()
return
fn = self.__show_filechooser("Choose eject program")
self.view['ejt_entryentry_imv'].set_text(fn)
def on_button_mnt_clicked(self, button):
self.__show_dirchooser()
return
fn = self.__show_filechooser("Choose mount point")
self.view['mnt_entry'].set_text(fn)
def on_ch_retrive_toggled(self, widget):
self.__toggle_scan_group()
return
def on_ch_imageviewer_toggled(self, checkbox):
state = self.view['ch_imageviewer'].get_active()
for i in ['label_imv', 'entry_imv', 'button_imv']:
self.view[i].set_sensitive(state)
def on_button_imv_clicked(self, widget):
fn = self.__show_filechooser("Choose image viewer")
self.view['entry_imv'].set_text(fn)
def on_ext_add_clicked(self, widget):
ext = self.view['ext_entry'].get_text().lower()
@@ -220,10 +231,11 @@ class ConfigController(Controller):
column.set_resizable(True)
category_tree.append_column(column)
def __show_filechooser(self):
def __show_filechooser(self, title):
"""dialog for choose eject"""
fn = None
dialog = gtk.FileChooserDialog(
title="Choose eject program",
title=title,
action=gtk.FILE_CHOOSER_ACTION_OPEN,
buttons=(
gtk.STOCK_CANCEL,
@@ -239,9 +251,9 @@ class ConfigController(Controller):
if response == gtk.RESPONSE_OK:
if __debug__:
print "c_config.py: __show_filechooser()", dialog.get_filename()
self.view['ejt_entry'].set_text(dialog.get_filename())
fn = dialog.get_filename()
dialog.destroy()
return fn
def __show_dirchooser(self):
"""dialog for point the mountpoint"""

View File

@@ -30,6 +30,7 @@ http://www.gnu.org/licenses/gpl.txt
"""
import os.path
from os import popen
from utils import deviceHelper
from gtkmvc import Controller
@@ -126,11 +127,83 @@ class MainController(Controller):
#########################################################################
# Connect signals from GUI, like menu objects, toolbar buttons and so on.
def on_edit2_activate(self, menu_item):
try:
selection = self.view['files'].get_selection()
model, list_of_paths = selection.get_selected_rows()
id = model.get_value(model.get_iter(list_of_paths[0]), 0)
except TypeError:
if __debug__: print "c_main.py: on_edit2_activate(): 0 zaznaczonych wierszy"
return
val = self.model.get_file_info(id)
ret = Dialogs.EditDialog(val).run()
if ret:
self.model.rename(id, ret['filename'])
self.model.update_desc_and_note(id, ret['description'], ret['note'])
self.__get_item_info(id)
def on_add_thumb1_activate(self, menu_item):
image = Dialogs.LoadImageFile().run()
if not image:
return
try:
selection = self.view['files'].get_selection()
model, list_of_paths = selection.get_selected_rows()
for path in list_of_paths:
id = model.get_value(model.get_iter(path),0)
self.model.add_thumbnail(image, id)
except:
if __debug__: print "c_main.py: on_add_thumb1_activate(): error on getting selected items or creating thumbnails"
return
self.__get_item_info(id)
return
def on_remove_thumb1_activate(self, menu_item):
if self.model.config.confd['delwarn']:
obj = Dialogs.Qst('Delete thumbnails', 'Delete thumbnails?',
'Thumbnails for selected items will be permanently removed from catalog.')
if not obj.run():
return
try:
selection = self.view['files'].get_selection()
model, list_of_paths = selection.get_selected_rows()
for path in list_of_paths:
id = model.get_value(model.get_iter(path),0)
self.model.del_thumbnail(id)
except:
if __debug__: print "c_main.py: on_remove_thumb1_activate(): error on getting selected items or removing thumbnails"
return
self.__get_item_info(id)
return
def on_remove_image1_activate(self, menu_item):
if self.model.config.confd['delwarn']:
obj = Dialogs.Qst('Delete images', 'Delete all images?',
'All images for selected items will be permanently removed from catalog.')
if not obj.run():
return
try:
selection = self.view['files'].get_selection()
model, list_of_paths = selection.get_selected_rows()
for path in list_of_paths:
id = model.get_value(model.get_iter(path),0)
self.model.del_images(id)
except:
if __debug__: print "c_main.py: on_remove_thumb1_activate(): error on getting selected items or removing thumbnails"
return
self.__get_item_info(id)
return
def on_images_item_activated(self, iconview, path):
model = iconview.get_model()
iter = model.get_iter(path)
id = model.get_value(iter, 0)
ImageView(self.model.get_image_path(id))
img = self.model.get_image_path(id)
if self.model.config.confd['imgview'] and len(self.model.config.confd['imgprog'])>0:
popen("%s %s" % (self.model.config.confd['imgprog'], img))
else:
ImageView(img)
def on_rename1_activate(self, widget):
model, iter = self.view['discs'].get_selection().get_selected()
@@ -138,8 +211,7 @@ class MainController(Controller):
id = model.get_value(iter, 0)
new_name = Dialogs.InputNewName(name).run()
if __debug__:
print "c_main.py: on_rename1_activate(): label:", new_name
if __debug__: print "c_main.py: on_rename1_activate(): label:", new_name
if new_name != None and new_name != name:
self.model.rename(id, new_name)
@@ -159,8 +231,7 @@ class MainController(Controller):
name = model.get_value(model.get_iter(list_of_paths[0]),1)
new_name = Dialogs.InputNewName(name).run()
if __debug__:
print "c_main.py: on_rename1_activate(): label:", new_name
if __debug__: print "c_main.py: on_rename1_activate(): label:", new_name
if new_name != None and new_name != name:
self.model.rename(fid, new_name)
@@ -176,8 +247,7 @@ class MainController(Controller):
return
def on_tag_cloud_textview_motion_notify_event(self, widget):
if __debug__:
print "c_main.py: on_tag_cloud_textview_motion_notify_event():"
if __debug__: print "c_main.py: on_tag_cloud_textview_motion_notify_event():"
w = self.view['tag_cloud_textview'].get_window(gtk.TEXT_WINDOW_TEXT)
if w:
w.set_cursor(None)
@@ -322,6 +392,10 @@ class MainController(Controller):
def on_img_add_activate(self, menu_item):
self.on_add_image1_activate(menu_item)
def on_thumb_box_button_press_event(self, widget, event):
if event.button == 3:
self.__popup_menu(event, 'th_popup')
def on_discs_button_press_event(self, treeview, event):
try:
path, column, x, y = treeview.get_path_at_pos(int(event.x),
@@ -379,9 +453,11 @@ class MainController(Controller):
if len(list_of_paths) > 1:
self.view['add_image1'].set_sensitive(False)
self.view['rename2'].set_sensitive(False)
self.view['edit2'].set_sensitive(False)
else:
self.view['add_image1'].set_sensitive(True)
self.view['rename2'].set_sensitive(True)
self.view['edit2'].set_sensitive(True)
self.__popup_menu(event, 'files_popup')
return True
@@ -394,8 +470,7 @@ class MainController(Controller):
selected_item = self.model.files_list.get_value(iter, 0)
self.__get_item_info(selected_item)
except:
if __debug__:
print "c_main.py: on_files_cursor_changed() insufficient iterator"
if __debug__: print "c_main.py: on_files_cursor_changed() insufficient iterator"
return
def on_files_key_release_event(self, a, event):
@@ -470,9 +545,10 @@ class MainController(Controller):
print self.view['files'].get_cursor()
def on_add_image1_activate(self, menu_item):
images = Dialogs.LoadImageFile().run()
images = Dialogs.LoadImageFile(True).run()
if not images:
return
for image in images:
try:
selection = self.view['files'].get_selection()
@@ -561,7 +637,7 @@ class MainController(Controller):
if self.model.config.confd['delwarn']:
obj = Dialogs.Qst('Delete elements', 'Delete items?',
'Items will be permanently removed.')
'Items will be permanently removed from catalog.')
if not obj.run():
return
@@ -591,10 +667,26 @@ class MainController(Controller):
except TypeError:
return
buf = gtk.TextBuffer()
self.view['description'].set_buffer(buf)
self.view['thumb_box'].hide()
self.view['exifinfo'].hide()
self.view['img_container'].hide()
self.model.unsaved_project = True
self.__set_title(filepath=self.model.filename, modified=True)
return
def on_th_delete_activate(self, menu_item):
path, column = self.view['files'].get_cursor()
model = self.view['files'].get_model()
iter = model.get_iter(path)
id = model.get_value(iter, 0)
if id:
self.model.del_thumbnail(id)
self.__get_item_info(id)
return
def on_debugbtn_clicked(self, widget):
"""Debug. To remove in stable version, including button in GUI"""
if __debug__:
@@ -762,8 +854,6 @@ class MainController(Controller):
buf = self.view['description'].get_buffer()
buf.set_text("")
self.view['description'].set_buffer(buf)
self.view['thumb'].hide()
self.__activate_ui()
return
@@ -903,17 +993,46 @@ class MainController(Controller):
def __get_item_info(self, item):
self.view['description'].show()
set = self.model.get_file_info(item)
buf = self.view['description'].get_buffer()
buf = gtk.TextBuffer()
if __debug__ and set.has_key('debug'):
tag = buf.create_tag()
tag.set_property('weight', pango.WEIGHT_BOLD)
buf.insert_with_tags(buf.get_end_iter(), "ID: ", tag)
buf.insert(buf.get_end_iter(), str(set['debug']['id']) + "\n")
buf.insert_with_tags(buf.get_end_iter(), "Filename: ", tag)
buf.insert(buf.get_end_iter(), set['filename'] + "\n")
buf.insert_with_tags(buf.get_end_iter(), "Date: ", tag)
buf.insert(buf.get_end_iter(), str(set['debug']['date']) + "\n")
buf.insert_with_tags(buf.get_end_iter(), "Size: ", tag)
buf.insert(buf.get_end_iter(), str(set['debug']['size']) + "\n")
buf.insert_with_tags(buf.get_end_iter(), "Type: ", tag)
buf.insert(buf.get_end_iter(), str(set['debug']['type']) + "\n\n")
if set.has_key('gthumb'):
tag = buf.create_tag()
tag.set_property('weight', pango.WEIGHT_BOLD)
buf.insert_with_tags(buf.get_end_iter(), "gThumb comment:\n", tag)
if set['gthumb']['note']:
buf.insert(buf.get_end_iter(), set['gthumb']['note'] + "\n")
if set['gthumb']['place']:
buf.insert(buf.get_end_iter(), set['gthumb']['place'] + "\n")
if set['gthumb']['date']:
buf.insert(buf.get_end_iter(), set['gthumb']['date'] + "\n")
buf.insert(buf.get_end_iter(), "\n")
if set.has_key('file_info'):
buf.set_text(set['file_info'])
if set.has_key('description'):
tag = buf.create_tag()
tag.set_property('weight', pango.WEIGHT_BOLD)
buf.insert_with_tags(buf.get_end_iter(), "\nDetails:\n", tag)
buf.insert_with_tags(buf.get_end_iter(), "Details:\n", tag)
buf.insert(buf.get_end_iter(), set['description'])
else:
buf.set_text('')
buf.insert(buf.get_end_iter(), "\n")
if set.has_key('note'):
tag = buf.create_tag()
tag.set_property('weight', pango.WEIGHT_BOLD)
buf.insert_with_tags(buf.get_end_iter(), "Note:\n", tag)
buf.insert(buf.get_end_iter(), set['note'])
self.view['description'].set_buffer(buf)
@@ -931,9 +1050,11 @@ class MainController(Controller):
if set.has_key('thumbnail'):
self.view['thumb'].set_from_file(set['thumbnail'])
self.view['thumb'].show()
self.view['thumb_box'].show()
#self.view['thumb'].show()
else:
self.view['thumb'].hide()
#self.view['thumb'].hide()
self.view['thumb_box'].hide()
return
def __tag_cloud(self):
@@ -954,7 +1075,6 @@ class MainController(Controller):
if w:
w.set_cursor(None)
def insert_blank(b, iter):
if iter.is_end() and iter.is_start():
return iter

View File

@@ -78,6 +78,9 @@ class ConfigModel(Model):
'cd': '/mnt/cdrom',
'ejectapp': 'eject -r',
'imgview': False,
'imgprog': 'gqview',
'retrive': False,
'thumbs': True,
@@ -122,6 +125,8 @@ class ConfigModel(Model):
'retrive extra informatin':'retrive',
'scan exif data':'exif',
'include gthumb image description':'gthumb',
'use external image viewer':'imgview',
'external image viewer program':'imgprog',
}
dbool = (
@@ -141,12 +146,13 @@ class ConfigModel(Model):
'delwarn',
'compress',
'retrive',
'imgview',
)
recent = []
RECENT_MAX = 10
dstring = ('cd','ejectapp')
dstring = ('cd','ejectapp','imgprog')
try:
path = os.environ['HOME']

View File

@@ -45,8 +45,11 @@ except ImportError:
from m_config import ConfigModel
from m_details import DetailsModel
try:
from utils.thumbnail import Thumbnail
from utils.img import Img
except:
pass
from utils.parse_exif import ParseExif
from utils.gthumb import GthumbCommentParser
@@ -131,7 +134,9 @@ class MainModel(ModelMT):
{'id': str(10), 'name': "windows", 'size': 18, 'color': '#333'},
]'''
return
def add_image(self, image, id):
"""add single image to file/directory"""
sql = """insert into images(file_id, thumbnail, filename)
values(?, null, null)"""
self.db_cursor.execute(sql, (id,))
@@ -150,6 +155,70 @@ class MainModel(ModelMT):
res[0]))
self.db_connection.commit()
def del_images(self, id):
"""removes images and their thumbnails from selected file/dir"""
# remove images
sql = """select filename, thumbnail from images where file_id =?"""
self.db_cursor.execute(sql, (id,))
res = self.db_cursor.fetchall()
if len(res) > 0:
for fn in res:
os.unlink(os.path.join(self.internal_dirname, fn[0]))
os.unlink(os.path.join(self.internal_dirname, fn[1]))
# remove images records
sql = """delete from images where file_id = ?"""
self.db_cursor.execute(sql, (id,))
self.db_connection.commit()
def delete_image(self, id):
"""removes image on specified image id"""
sql = """select filename, thumbnail from images where id=?"""
self.db_cursor.execute(sql, (id,))
res = self.db_cursor.fetchone()
if res[0]:
os.unlink(os.path.join(self.internal_dirname, res[0]))
os.unlink(os.path.join(self.internal_dirname, res[1]))
if __debug__:
print "m_main.py: delete_image(): removed images:"
print res[0]
print res[1]
# remove images records
sql = """delete from images where id = ?"""
self.db_cursor.execute(sql, (id,))
self.db_connection.commit()
def add_thumbnail(self, img_fn, id):
"""generate and add thumbnail to selected file/dir"""
if self.config.confd['thumbs']:
self.del_thumbnail(id)
p, e, ret_code = Thumbnail(img_fn,
base=self.internal_dirname).save(id)
if ret_code != -1:
sql = """insert into thumbnails(file_id, filename) values (?, ?)"""
self.db_cursor.execute(sql,
(id,
p.split(self.internal_dirname)[1][1:]))
self.db_connection.commit()
return True
return False
def del_thumbnail(self, id):
"""removes thumbnail from selected file/dir"""
# remove thumbnail files
sql = """select filename from thumbnails where file_id=?"""
self.db_cursor.execute(sql, (id,))
res = self.db_cursor.fetchone()
if res:
os.unlink(os.path.join(self.internal_dirname, res[0]))
# remove thumbs records
sql = """delete from thumbnails where file_id=?"""
self.db_cursor.execute(sql, (id,))
self.db_connection.commit()
def cleanup(self):
self.__close_db_connection()
if self.internal_dirname != None:
@@ -202,6 +271,7 @@ class MainModel(ModelMT):
os.chdir(self.internal_dirname)
try:
tar.extractall()
if __debug__:
print "m_main.py: extracted tarfile into", self.internal_dirname
except AttributeError:
# python's 2.4 tarfile module lacks of method extractall()
@@ -328,19 +398,25 @@ class MainModel(ModelMT):
"""get file info from database"""
retval = {}
sql = """SELECT f.filename, f.date, f.size, f.type,
t.filename, f.description
t.filename, f.description, f.note
FROM files f
LEFT JOIN thumbnails t ON t.file_id = f.id
WHERE f.id = ?"""
self.db_cursor.execute(sql, (id,))
set = self.db_cursor.fetchone()
if set:
string = "ID: %d\nFilename: %s\nDate: %s\nSize: %s\ntype: %s" % \
(id, set[0], datetime.fromtimestamp(set[1]), set[2], set[3])
retval['file_info'] = string
retval['debug'] = {'id': id,
'date': datetime.fromtimestamp(set[1]),
'size': set[2], 'type': set[3]}
retval['filename'] = set[0]
if set[5]:
retval['description'] = set[5]
if set[6]:
retval['note'] = set[6]
if set[4]:
retval['thumbnail'] = os.path.join(self.internal_dirname, set[4])
@@ -370,8 +446,16 @@ class MainModel(ModelMT):
myiter = self.exif_list.insert_before(None, None)
self.exif_list.set_value(myiter, 0, self.EXIF_DICT[key])
self.exif_list.set_value(myiter, 1, set[key])
retval['exif'] = True
# gthumb
sql = """SELECT note, place, date from gthumb WHERE file_id = ?"""
self.db_cursor.execute(sql, (id,))
set = self.db_cursor.fetchone()
if set:
retval['gthumb'] = {'note': set[0], 'place': set[1], 'date': set[2]}
return retval
def get_source(self, path):
@@ -396,27 +480,10 @@ class MainModel(ModelMT):
return None, None
return res[0], res[1]
def delete_image(self, id):
"""removes image on specified id"""
sql = """select filename, thumbnail from images where id=?"""
self.db_cursor.execute(sql, (id,))
res = self.db_cursor.fetchone()
if res[0]:
os.unlink(os.path.join(self.internal_dirname, res[0]))
os.unlink(os.path.join(self.internal_dirname, res[1]))
if __debug__:
print "m_main.py: delete_image(): removed images:"
print res[0]
print res[1]
# remove images records
sql = """delete from images where id = ?"""
self.db_cursor.execute(sql, (id,))
self.db_connection.commit()
def delete(self, root_id, db_cursor=None, db_connection=None):
"""Remove subtree from main tree, remove tags from database
remove all possible data, like thumbnails"""
remove all possible data, like thumbnails, images, gthumb info, exif
etc"""
fids = []
@@ -429,10 +496,8 @@ class MainModel(ModelMT):
sql = """select parent_id from files where id = ?"""
db_cursor.execute(sql, (root_id,))
res = db_cursor.fetchone()
if res:
parent_id = res[0]
def get_children(fid):
fids.append(fid)
sql = """select id from files where parent_id = ?"""
@@ -456,13 +521,9 @@ class MainModel(ModelMT):
sql = """delete from tags_files where file_id = ?"""
db_cursor.executemany(sql, generator())
arg = self.__list_to_string(fids)
# remove thumbnails
arg =''
for c in fids:
if len(arg) > 0:
arg+=", %d" % c
else:
arg = "%d" % c
sql = """select filename from thumbnails where file_id in (%s)""" % arg
db_cursor.execute(sql)
res = db_cursor.fetchall()
@@ -477,6 +538,7 @@ class MainModel(ModelMT):
if len(res) > 0:
for fn in res:
os.unlink(os.path.join(self.internal_dirname, fn[0]))
os.unlink(os.path.join(self.internal_dirname, fn[1]))
# remove thumbs records
sql = """delete from thumbnails where file_id = ?"""
@@ -486,6 +548,10 @@ class MainModel(ModelMT):
sql = """delete from images where file_id = ?"""
db_cursor.executemany(sql, generator())
# remove gthumb info
sql = """delete from gthumb where file_id = ?"""
db_cursor.executemany(sql, generator())
# correct parent direcotry sizes
# get size and parent of deleting object
while parent_id:
@@ -500,8 +566,6 @@ class MainModel(ModelMT):
from files where parent_id=?) where id=?"""
db_cursor.execute(sql, (parent_id, parent_id))
sql = """select parent_id from files where id = ? and parent_id!=id"""
db_cursor.execute(sql, (parent_id,))
res = db_cursor.fetchone()
@@ -590,9 +654,15 @@ class MainModel(ModelMT):
self.db_cursor.execute(sql, (img_id,))
res = self.db_cursor.fetchone()
if res:
return res[0]
return os.path.join(self.internal_dirname, res[0])
return None
def update_desc_and_note(self, id, desc='', note=''):
"""update note and description"""
sql = """UPDATE files SET description=?, note=? WHERE id=?"""
self.db_cursor.execute(sql, (desc, note, id))
return
# private class functions
def __bytes_to_human(self, integer):
if integer <= 0 or integer < 1024:
@@ -729,6 +799,7 @@ class MainModel(ModelMT):
date datetime);""")
self.db_cursor.execute("insert into files values(1, 1, 'root', null, 0, 0, 0, 0, null, null);")
self.db_cursor.execute("insert into groups values(1, 'default', 'black');")
self.db_connection.commit()
def __scan(self):
"""scan content of the given path"""
@@ -952,7 +1023,7 @@ class MainModel(ModelMT):
cmnts['place'],
cmnts['date']
))
if cmnts['keywords']:
if cmnts.has_key('keywords'):
# TODO: add gthumb keywords to tags and group 'gthumb'
pass
@@ -997,7 +1068,9 @@ class MainModel(ModelMT):
if self.currentid:
if __debug__:
print "m_main.py: __scan() removing old branch"
self.statusmsg = "Removing old branch..."
self.delete(self.currentid, db_cursor, db_connection)
self.currentid = None
else:
print "new directory/cd"
@@ -1120,4 +1193,12 @@ class MainModel(ModelMT):
else:
return txt
def __list_to_string(self, array):
arg =''
for c in array:
if len(arg) > 0:
arg+=", %d" % c
else:
arg = "%d" % c
return arg
pass # end of class

View File

@@ -1,3 +1,26 @@
# This Python file uses the following encoding: utf-8
#
# Author: Roman 'gryf' Dobosz gryf@elysium.pl
#
# Copyright (C) 2007 by Roman 'gryf' Dobosz
#
# This file is part of pyGTKtalog.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# -------------------------------------------------------------------------
from xml.dom.minidom import Node
from xml.dom import minidom
import gzip

View File

@@ -27,7 +27,6 @@ from shutil import move, copy
from os import path, mkdir
from datetime import datetime
from utils import EXIF
import Image
class Img(object):
@@ -40,76 +39,26 @@ class Img(object):
def save(self, image_id):
"""Save image and asociated thumbnail into specific directory structure
return full path to the file and thumbnail None"""
return full path to the file and thumbnail or None"""
base_path = self.__get_and_make_path(image_id)
ext = self.filename.split('.')[-1].lower()
image_filename = path.join(self.base, base_path + "_im." + ext)
image_filename = path.join(self.base, base_path + "." + ext)
thumbnail = path.join(self.base, base_path + "_t.jpg")
# make and save image
filepath = path.join(self.base, base_path + ".jpg")
f = open(self.filename, 'rb')
exif = None
returncode = -1
try:
exif = EXIF.process_file(f)
f.close()
if exif.has_key('JPEGThumbnail'):
thumbnail = exif['JPEGThumbnail']
f = open(filepath,'wb')
f.write(thumbnail)
f.close()
if exif.has_key('Image Orientation'):
orientation = exif['Image Orientation'].values[0]
if orientation > 1:
# TODO: replace silly datetime function with tempfile
t = path.join(gettempdir(), "thumb%d.jpg" % datetime.now().microsecond)
im_in = Image.open(filepath)
im_out = None
if orientation == 8:
# Rotated 90 CCW
im_out = im_in.transpose(Image.ROTATE_90)
elif orientation == 6:
# Rotated 90 CW
im_out = im_in.transpose(Image.ROTATE_270)
elif orientation == 3:
# Rotated 180
im_out = im_in.transpose(Image.ROTATE_180)
elif orientation == 2:
# Mirrored horizontal
im_out = im_in.transpose(Image.FLIP_LEFT_RIGHT)
elif orientation == 4:
# Mirrored vertical
im_out = im_in.transpose(Image.FLIP_TOP_BOTTOM)
elif orientation == 5:
# Mirrored horizontal then rotated 90 CCW
im_out = im_in.transpose(Image.FLIP_LEFT_RIGHT).transpose(Image.ROTATE_90)
elif orientation == 7:
# Mirrored horizontal then rotated 90 CW
im_out = im_in.transpose(Image.FLIP_LEFT_RIGHT).transpose(Image.ROTATE_270)
if im_out:
im_out.save(t, 'JPEG')
move(t, filepath)
else:
f.close()
returncode = 0
else:
im = self.__scale_image()
if im:
im.save(filepath, "JPEG")
im.save(thumbnail, "JPEG")
returncode = 1
except:
f.close()
im = self.__scale_image()
if im:
im.save(filepath, "JPEG")
returncode = 2
if returncode != -1:
# copy image
copy(self.filename, image_filename)
return filepath, image_filename, returncode
return thumbnail, image_filename, returncode
# private class functions
def __get_and_make_path(self, img_id):
@@ -146,7 +95,7 @@ class Img(object):
img = "%s" % h[2:]
return(path.join(t, fpath, img))
def __scale_image(self, factor=True):
def __scale_image(self):
"""create thumbnail. returns image object or None"""
try:
im = Image.open(self.filename).convert('RGB')

View File

@@ -177,14 +177,15 @@ class PointDirectoryToAdd(object):
dialog.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
dialog.set_default_response(gtk.RESPONSE_OK)
if self.URI:
dialog.set_current_folder_uri(self.URI)
response = dialog.run()
if response == gtk.RESPONSE_OK:
self.directory.set_text(dialog.get_filename())
self.__class__.URI = dialog.get_current_folder_uri()
dialog.destroy()
def run(self):
if self.URI:
self.dialog.set_current_folder_uri(self.URI)
dialog = self.gladexml.get_widget("addDirDialog")
ch = True
result = dialog.run()
@@ -195,7 +196,6 @@ class PointDirectoryToAdd(object):
result = dialog.run()
else:
ch = False
self.__class__.URI = self.dialog.get_current_folder_uri()
dialog.destroy()
if result == gtk.RESPONSE_OK:
return self.volname.get_text(),self.directory.get_text()
@@ -321,7 +321,7 @@ class LoadImageFile(object):
URI="file://"+os.path.abspath(os.path.curdir)
def __init__(self):
def __init__(self, multiple=False):
self.dialog = gtk.FileChooserDialog(
title="Select image",
action=gtk.FILE_CHOOSER_ACTION_OPEN,
@@ -332,7 +332,7 @@ class LoadImageFile(object):
gtk.RESPONSE_OK
)
)
self.dialog.set_select_multiple(True)
self.dialog.set_select_multiple(multiple)
self.dialog.set_default_response(gtk.RESPONSE_OK)
f = gtk.FileFilter()
@@ -357,7 +357,10 @@ class LoadImageFile(object):
if response == gtk.RESPONSE_OK:
try:
if self.dialog.get_select_multiple():
filenames = self.dialog.get_filenames()
else:
filenames = self.dialog.get_filename()
except:
pass
@@ -417,3 +420,41 @@ class StatsDialog(object):
if result == gtk.RESPONSE_OK:
return entry.get_text()
return None
class EditDialog(object):
"""Sepcific dialog for display stats"""
def __init__(self, values={}):
self.gladefile = os.path.join(utils.globals.GLADE_DIR, "dialogs.glade")
self.values = values
def run(self):
gladexml = gtk.glade.XML(self.gladefile, "file_editDialog")
dialog = gladexml.get_widget("file_editDialog")
filename = gladexml.get_widget("filename_entry")
filename.set_text(str(self.values['filename']))
description = gladexml.get_widget("description_text")
note = gladexml.get_widget("note_text")
if self.values.has_key('description'):
buff = gtk.TextBuffer()
buff.set_text(str(self.values['description']))
description.set_buffer(buff)
if self.values.has_key('note'):
buff = gtk.TextBuffer()
buff.set_text(str(self.values['note']))
note.set_buffer(buff)
result = dialog.run()
if result == gtk.RESPONSE_OK:
d = description.get_buffer()
n = note.get_buffer()
retval = {'filename': filename.get_text(),
'description': d.get_text(d.get_start_iter(),
d.get_end_iter()),
'note': n.get_text(n.get_start_iter(), n.get_end_iter())}
dialog.destroy()
return retval
dialog.destroy()
return None