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:
32
README
32
README
@@ -10,9 +10,14 @@ which seems to be dead project for years.
|
|||||||
FEATURES
|
FEATURES
|
||||||
========
|
========
|
||||||
|
|
||||||
- scanning for files in selected media
|
- scan for files in selected media
|
||||||
- generating thumbnails
|
- 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>
|
- tagging files <http://en.wikipedia.org/wiki/Tag_%28metadata%29>
|
||||||
|
- and more :)
|
||||||
|
|
||||||
REQUIREMENTS
|
REQUIREMENTS
|
||||||
============
|
============
|
||||||
@@ -57,13 +62,13 @@ For version 1.0 following aims have to be done:
|
|||||||
- searching database
|
- searching database
|
||||||
- tagging files
|
- tagging files
|
||||||
- user definied group of tags (represented by color in cloud tag)
|
- user definied group of tags (represented by color in cloud tag)
|
||||||
- file details:
|
x file details:
|
||||||
- files properties
|
x files properties
|
||||||
x thumbnail
|
x thumbnail
|
||||||
x description
|
x description
|
||||||
|
x edit note and description
|
||||||
x exif information
|
x exif information
|
||||||
- keywords (tags)
|
x gthumb integration
|
||||||
- gthumb integration
|
|
||||||
x adding images
|
x adding images
|
||||||
x generating/saving thumbnails
|
x generating/saving thumbnails
|
||||||
x moving hardcoded files extensions into config
|
x moving hardcoded files extensions into config
|
||||||
@@ -75,11 +80,12 @@ For version 2.0:
|
|||||||
- Icon grid in files view
|
- Icon grid in files view
|
||||||
- command line support: query, adding media to collection etc
|
- command line support: query, adding media to collection etc
|
||||||
- internationalization support
|
- internationalization support
|
||||||
|
- export to XLS
|
||||||
|
|
||||||
Removed:
|
Removed:
|
||||||
- filetypes handling (movies, images, archives, documents etc). Now it have
|
- filetypes handling (movies, images, archives, documents etc). Now it have
|
||||||
common, unified external "plugin" system - simple output from command line
|
common, unified external "plugin" system - simple text output from command
|
||||||
programs.
|
line programs.
|
||||||
- anime/movie
|
- anime/movie
|
||||||
- title
|
- title
|
||||||
- alt title
|
- alt title
|
||||||
@@ -90,16 +96,16 @@ Removed:
|
|||||||
- sub lang
|
- sub lang
|
||||||
- release date (from - to)
|
- release date (from - to)
|
||||||
- anidb link/imdb link
|
- anidb link/imdb link
|
||||||
Maybe in future versions. Now text file descriptions and tags have to be
|
Maybe in future versions. Now text file descriptions/notes and tags have to
|
||||||
enough for good and fast information search.
|
be enough for good and fast information search.
|
||||||
- file information (date, size, etc) (50%) (no need for?)
|
- file information (date, size, etc) (50%) (no need for?)
|
||||||
|
|
||||||
NOTES
|
NOTES
|
||||||
=====
|
=====
|
||||||
|
|
||||||
Catalog file is tared and optionaly compressed sqlite database and directory
|
Catalog file is tared and optionaly compressed sqlite database and directories
|
||||||
with thumbnails. If there are more images, the size of catalog file will grow.
|
with images and thumbnails. If there are more images, the size of catalog file
|
||||||
So be carefull with adding big images in your catalog file!
|
will grow. So be carefull with adding big images in your catalog file!
|
||||||
|
|
||||||
BUGS
|
BUGS
|
||||||
====
|
====
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ class ConfigController(Controller):
|
|||||||
self.view['ch_gthumb'].set_active(self.model.confd['gthumb'])
|
self.view['ch_gthumb'].set_active(self.model.confd['gthumb'])
|
||||||
self.view['ch_compress'].set_active(self.model.confd['compress'])
|
self.view['ch_compress'].set_active(self.model.confd['compress'])
|
||||||
self.view['ch_retrive'].set_active(self.model.confd['retrive'])
|
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()
|
self.__toggle_scan_group()
|
||||||
|
|
||||||
@@ -118,21 +120,30 @@ class ConfigController(Controller):
|
|||||||
self.model.confd['gthumb'] = self.view['ch_gthumb'].get_active()
|
self.model.confd['gthumb'] = self.view['ch_gthumb'].get_active()
|
||||||
self.model.confd['compress'] = self.view['ch_compress'].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['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.model.save()
|
||||||
self.view['config'].destroy()
|
self.view['config'].destroy()
|
||||||
return
|
|
||||||
|
|
||||||
def on_button_ejt_clicked(self, button):
|
def on_button_ejt_clicked(self, button):
|
||||||
self.__show_filechooser()
|
fn = self.__show_filechooser("Choose eject program")
|
||||||
return
|
self.view['ejt_entryentry_imv'].set_text(fn)
|
||||||
|
|
||||||
def on_button_mnt_clicked(self, button):
|
def on_button_mnt_clicked(self, button):
|
||||||
self.__show_dirchooser()
|
fn = self.__show_filechooser("Choose mount point")
|
||||||
return
|
self.view['mnt_entry'].set_text(fn)
|
||||||
|
|
||||||
def on_ch_retrive_toggled(self, widget):
|
def on_ch_retrive_toggled(self, widget):
|
||||||
self.__toggle_scan_group()
|
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):
|
def on_ext_add_clicked(self, widget):
|
||||||
ext = self.view['ext_entry'].get_text().lower()
|
ext = self.view['ext_entry'].get_text().lower()
|
||||||
@@ -220,10 +231,11 @@ class ConfigController(Controller):
|
|||||||
column.set_resizable(True)
|
column.set_resizable(True)
|
||||||
category_tree.append_column(column)
|
category_tree.append_column(column)
|
||||||
|
|
||||||
def __show_filechooser(self):
|
def __show_filechooser(self, title):
|
||||||
"""dialog for choose eject"""
|
"""dialog for choose eject"""
|
||||||
|
fn = None
|
||||||
dialog = gtk.FileChooserDialog(
|
dialog = gtk.FileChooserDialog(
|
||||||
title="Choose eject program",
|
title=title,
|
||||||
action=gtk.FILE_CHOOSER_ACTION_OPEN,
|
action=gtk.FILE_CHOOSER_ACTION_OPEN,
|
||||||
buttons=(
|
buttons=(
|
||||||
gtk.STOCK_CANCEL,
|
gtk.STOCK_CANCEL,
|
||||||
@@ -239,9 +251,9 @@ class ConfigController(Controller):
|
|||||||
if response == gtk.RESPONSE_OK:
|
if response == gtk.RESPONSE_OK:
|
||||||
if __debug__:
|
if __debug__:
|
||||||
print "c_config.py: __show_filechooser()", dialog.get_filename()
|
print "c_config.py: __show_filechooser()", dialog.get_filename()
|
||||||
self.view['ejt_entry'].set_text(dialog.get_filename())
|
fn = dialog.get_filename()
|
||||||
|
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
|
return fn
|
||||||
|
|
||||||
def __show_dirchooser(self):
|
def __show_dirchooser(self):
|
||||||
"""dialog for point the mountpoint"""
|
"""dialog for point the mountpoint"""
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ http://www.gnu.org/licenses/gpl.txt
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
from os import popen
|
||||||
from utils import deviceHelper
|
from utils import deviceHelper
|
||||||
from gtkmvc import Controller
|
from gtkmvc import Controller
|
||||||
|
|
||||||
@@ -126,11 +127,83 @@ class MainController(Controller):
|
|||||||
|
|
||||||
#########################################################################
|
#########################################################################
|
||||||
# Connect signals from GUI, like menu objects, toolbar buttons and so on.
|
# 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):
|
def on_images_item_activated(self, iconview, path):
|
||||||
model = iconview.get_model()
|
model = iconview.get_model()
|
||||||
iter = model.get_iter(path)
|
iter = model.get_iter(path)
|
||||||
id = model.get_value(iter, 0)
|
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):
|
def on_rename1_activate(self, widget):
|
||||||
model, iter = self.view['discs'].get_selection().get_selected()
|
model, iter = self.view['discs'].get_selection().get_selected()
|
||||||
@@ -138,8 +211,7 @@ class MainController(Controller):
|
|||||||
id = model.get_value(iter, 0)
|
id = model.get_value(iter, 0)
|
||||||
new_name = Dialogs.InputNewName(name).run()
|
new_name = Dialogs.InputNewName(name).run()
|
||||||
|
|
||||||
if __debug__:
|
if __debug__: print "c_main.py: on_rename1_activate(): label:", new_name
|
||||||
print "c_main.py: on_rename1_activate(): label:", new_name
|
|
||||||
|
|
||||||
if new_name != None and new_name != name:
|
if new_name != None and new_name != name:
|
||||||
self.model.rename(id, new_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)
|
name = model.get_value(model.get_iter(list_of_paths[0]),1)
|
||||||
|
|
||||||
new_name = Dialogs.InputNewName(name).run()
|
new_name = Dialogs.InputNewName(name).run()
|
||||||
if __debug__:
|
if __debug__: print "c_main.py: on_rename1_activate(): label:", new_name
|
||||||
print "c_main.py: on_rename1_activate(): label:", new_name
|
|
||||||
|
|
||||||
if new_name != None and new_name != name:
|
if new_name != None and new_name != name:
|
||||||
self.model.rename(fid, new_name)
|
self.model.rename(fid, new_name)
|
||||||
@@ -176,8 +247,7 @@ class MainController(Controller):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def on_tag_cloud_textview_motion_notify_event(self, widget):
|
def on_tag_cloud_textview_motion_notify_event(self, widget):
|
||||||
if __debug__:
|
if __debug__: print "c_main.py: on_tag_cloud_textview_motion_notify_event():"
|
||||||
print "c_main.py: on_tag_cloud_textview_motion_notify_event():"
|
|
||||||
w = self.view['tag_cloud_textview'].get_window(gtk.TEXT_WINDOW_TEXT)
|
w = self.view['tag_cloud_textview'].get_window(gtk.TEXT_WINDOW_TEXT)
|
||||||
if w:
|
if w:
|
||||||
w.set_cursor(None)
|
w.set_cursor(None)
|
||||||
@@ -322,6 +392,10 @@ class MainController(Controller):
|
|||||||
def on_img_add_activate(self, menu_item):
|
def on_img_add_activate(self, menu_item):
|
||||||
self.on_add_image1_activate(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):
|
def on_discs_button_press_event(self, treeview, event):
|
||||||
try:
|
try:
|
||||||
path, column, x, y = treeview.get_path_at_pos(int(event.x),
|
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:
|
if len(list_of_paths) > 1:
|
||||||
self.view['add_image1'].set_sensitive(False)
|
self.view['add_image1'].set_sensitive(False)
|
||||||
self.view['rename2'].set_sensitive(False)
|
self.view['rename2'].set_sensitive(False)
|
||||||
|
self.view['edit2'].set_sensitive(False)
|
||||||
else:
|
else:
|
||||||
self.view['add_image1'].set_sensitive(True)
|
self.view['add_image1'].set_sensitive(True)
|
||||||
self.view['rename2'].set_sensitive(True)
|
self.view['rename2'].set_sensitive(True)
|
||||||
|
self.view['edit2'].set_sensitive(True)
|
||||||
self.__popup_menu(event, 'files_popup')
|
self.__popup_menu(event, 'files_popup')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -394,8 +470,7 @@ class MainController(Controller):
|
|||||||
selected_item = self.model.files_list.get_value(iter, 0)
|
selected_item = self.model.files_list.get_value(iter, 0)
|
||||||
self.__get_item_info(selected_item)
|
self.__get_item_info(selected_item)
|
||||||
except:
|
except:
|
||||||
if __debug__:
|
if __debug__: print "c_main.py: on_files_cursor_changed() insufficient iterator"
|
||||||
print "c_main.py: on_files_cursor_changed() insufficient iterator"
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def on_files_key_release_event(self, a, event):
|
def on_files_key_release_event(self, a, event):
|
||||||
@@ -470,9 +545,10 @@ class MainController(Controller):
|
|||||||
print self.view['files'].get_cursor()
|
print self.view['files'].get_cursor()
|
||||||
|
|
||||||
def on_add_image1_activate(self, menu_item):
|
def on_add_image1_activate(self, menu_item):
|
||||||
images = Dialogs.LoadImageFile().run()
|
images = Dialogs.LoadImageFile(True).run()
|
||||||
if not images:
|
if not images:
|
||||||
return
|
return
|
||||||
|
|
||||||
for image in images:
|
for image in images:
|
||||||
try:
|
try:
|
||||||
selection = self.view['files'].get_selection()
|
selection = self.view['files'].get_selection()
|
||||||
@@ -561,7 +637,7 @@ class MainController(Controller):
|
|||||||
|
|
||||||
if self.model.config.confd['delwarn']:
|
if self.model.config.confd['delwarn']:
|
||||||
obj = Dialogs.Qst('Delete elements', 'Delete items?',
|
obj = Dialogs.Qst('Delete elements', 'Delete items?',
|
||||||
'Items will be permanently removed.')
|
'Items will be permanently removed from catalog.')
|
||||||
if not obj.run():
|
if not obj.run():
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -591,10 +667,26 @@ class MainController(Controller):
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
return
|
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.model.unsaved_project = True
|
||||||
self.__set_title(filepath=self.model.filename, modified=True)
|
self.__set_title(filepath=self.model.filename, modified=True)
|
||||||
return
|
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):
|
def on_debugbtn_clicked(self, widget):
|
||||||
"""Debug. To remove in stable version, including button in GUI"""
|
"""Debug. To remove in stable version, including button in GUI"""
|
||||||
if __debug__:
|
if __debug__:
|
||||||
@@ -762,8 +854,6 @@ class MainController(Controller):
|
|||||||
buf = self.view['description'].get_buffer()
|
buf = self.view['description'].get_buffer()
|
||||||
buf.set_text("")
|
buf.set_text("")
|
||||||
self.view['description'].set_buffer(buf)
|
self.view['description'].set_buffer(buf)
|
||||||
self.view['thumb'].hide()
|
|
||||||
|
|
||||||
self.__activate_ui()
|
self.__activate_ui()
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -903,17 +993,46 @@ class MainController(Controller):
|
|||||||
def __get_item_info(self, item):
|
def __get_item_info(self, item):
|
||||||
self.view['description'].show()
|
self.view['description'].show()
|
||||||
set = self.model.get_file_info(item)
|
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'):
|
if set.has_key('description'):
|
||||||
tag = buf.create_tag()
|
tag = buf.create_tag()
|
||||||
tag.set_property('weight', pango.WEIGHT_BOLD)
|
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'])
|
buf.insert(buf.get_end_iter(), set['description'])
|
||||||
else:
|
buf.insert(buf.get_end_iter(), "\n")
|
||||||
buf.set_text('')
|
|
||||||
|
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)
|
self.view['description'].set_buffer(buf)
|
||||||
|
|
||||||
@@ -931,9 +1050,11 @@ class MainController(Controller):
|
|||||||
|
|
||||||
if set.has_key('thumbnail'):
|
if set.has_key('thumbnail'):
|
||||||
self.view['thumb'].set_from_file(set['thumbnail'])
|
self.view['thumb'].set_from_file(set['thumbnail'])
|
||||||
self.view['thumb'].show()
|
self.view['thumb_box'].show()
|
||||||
|
#self.view['thumb'].show()
|
||||||
else:
|
else:
|
||||||
self.view['thumb'].hide()
|
#self.view['thumb'].hide()
|
||||||
|
self.view['thumb_box'].hide()
|
||||||
return
|
return
|
||||||
|
|
||||||
def __tag_cloud(self):
|
def __tag_cloud(self):
|
||||||
@@ -954,7 +1075,6 @@ class MainController(Controller):
|
|||||||
if w:
|
if w:
|
||||||
w.set_cursor(None)
|
w.set_cursor(None)
|
||||||
|
|
||||||
|
|
||||||
def insert_blank(b, iter):
|
def insert_blank(b, iter):
|
||||||
if iter.is_end() and iter.is_start():
|
if iter.is_end() and iter.is_start():
|
||||||
return iter
|
return iter
|
||||||
|
|||||||
@@ -78,6 +78,9 @@ class ConfigModel(Model):
|
|||||||
'cd': '/mnt/cdrom',
|
'cd': '/mnt/cdrom',
|
||||||
'ejectapp': 'eject -r',
|
'ejectapp': 'eject -r',
|
||||||
|
|
||||||
|
'imgview': False,
|
||||||
|
'imgprog': 'gqview',
|
||||||
|
|
||||||
'retrive': False,
|
'retrive': False,
|
||||||
|
|
||||||
'thumbs': True,
|
'thumbs': True,
|
||||||
@@ -122,6 +125,8 @@ class ConfigModel(Model):
|
|||||||
'retrive extra informatin':'retrive',
|
'retrive extra informatin':'retrive',
|
||||||
'scan exif data':'exif',
|
'scan exif data':'exif',
|
||||||
'include gthumb image description':'gthumb',
|
'include gthumb image description':'gthumb',
|
||||||
|
'use external image viewer':'imgview',
|
||||||
|
'external image viewer program':'imgprog',
|
||||||
}
|
}
|
||||||
|
|
||||||
dbool = (
|
dbool = (
|
||||||
@@ -141,12 +146,13 @@ class ConfigModel(Model):
|
|||||||
'delwarn',
|
'delwarn',
|
||||||
'compress',
|
'compress',
|
||||||
'retrive',
|
'retrive',
|
||||||
|
'imgview',
|
||||||
)
|
)
|
||||||
|
|
||||||
recent = []
|
recent = []
|
||||||
RECENT_MAX = 10
|
RECENT_MAX = 10
|
||||||
|
|
||||||
dstring = ('cd','ejectapp')
|
dstring = ('cd','ejectapp','imgprog')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
path = os.environ['HOME']
|
path = os.environ['HOME']
|
||||||
|
|||||||
@@ -45,8 +45,11 @@ except ImportError:
|
|||||||
|
|
||||||
from m_config import ConfigModel
|
from m_config import ConfigModel
|
||||||
from m_details import DetailsModel
|
from m_details import DetailsModel
|
||||||
from utils.thumbnail import Thumbnail
|
try:
|
||||||
from utils.img import Img
|
from utils.thumbnail import Thumbnail
|
||||||
|
from utils.img import Img
|
||||||
|
except:
|
||||||
|
pass
|
||||||
from utils.parse_exif import ParseExif
|
from utils.parse_exif import ParseExif
|
||||||
from utils.gthumb import GthumbCommentParser
|
from utils.gthumb import GthumbCommentParser
|
||||||
|
|
||||||
@@ -131,7 +134,9 @@ class MainModel(ModelMT):
|
|||||||
{'id': str(10), 'name': "windows", 'size': 18, 'color': '#333'},
|
{'id': str(10), 'name': "windows", 'size': 18, 'color': '#333'},
|
||||||
]'''
|
]'''
|
||||||
return
|
return
|
||||||
|
|
||||||
def add_image(self, image, id):
|
def add_image(self, image, id):
|
||||||
|
"""add single image to file/directory"""
|
||||||
sql = """insert into images(file_id, thumbnail, filename)
|
sql = """insert into images(file_id, thumbnail, filename)
|
||||||
values(?, null, null)"""
|
values(?, null, null)"""
|
||||||
self.db_cursor.execute(sql, (id,))
|
self.db_cursor.execute(sql, (id,))
|
||||||
@@ -150,6 +155,70 @@ class MainModel(ModelMT):
|
|||||||
res[0]))
|
res[0]))
|
||||||
self.db_connection.commit()
|
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):
|
def cleanup(self):
|
||||||
self.__close_db_connection()
|
self.__close_db_connection()
|
||||||
if self.internal_dirname != None:
|
if self.internal_dirname != None:
|
||||||
@@ -202,6 +271,7 @@ class MainModel(ModelMT):
|
|||||||
os.chdir(self.internal_dirname)
|
os.chdir(self.internal_dirname)
|
||||||
try:
|
try:
|
||||||
tar.extractall()
|
tar.extractall()
|
||||||
|
if __debug__:
|
||||||
print "m_main.py: extracted tarfile into", self.internal_dirname
|
print "m_main.py: extracted tarfile into", self.internal_dirname
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# python's 2.4 tarfile module lacks of method extractall()
|
# python's 2.4 tarfile module lacks of method extractall()
|
||||||
@@ -328,19 +398,25 @@ class MainModel(ModelMT):
|
|||||||
"""get file info from database"""
|
"""get file info from database"""
|
||||||
retval = {}
|
retval = {}
|
||||||
sql = """SELECT f.filename, f.date, f.size, f.type,
|
sql = """SELECT f.filename, f.date, f.size, f.type,
|
||||||
t.filename, f.description
|
t.filename, f.description, f.note
|
||||||
FROM files f
|
FROM files f
|
||||||
LEFT JOIN thumbnails t ON t.file_id = f.id
|
LEFT JOIN thumbnails t ON t.file_id = f.id
|
||||||
WHERE f.id = ?"""
|
WHERE f.id = ?"""
|
||||||
self.db_cursor.execute(sql, (id,))
|
self.db_cursor.execute(sql, (id,))
|
||||||
set = self.db_cursor.fetchone()
|
set = self.db_cursor.fetchone()
|
||||||
if set:
|
if set:
|
||||||
string = "ID: %d\nFilename: %s\nDate: %s\nSize: %s\ntype: %s" % \
|
retval['debug'] = {'id': id,
|
||||||
(id, set[0], datetime.fromtimestamp(set[1]), set[2], set[3])
|
'date': datetime.fromtimestamp(set[1]),
|
||||||
retval['file_info'] = string
|
'size': set[2], 'type': set[3]}
|
||||||
|
|
||||||
|
retval['filename'] = set[0]
|
||||||
|
|
||||||
if set[5]:
|
if set[5]:
|
||||||
retval['description'] = set[5]
|
retval['description'] = set[5]
|
||||||
|
|
||||||
|
if set[6]:
|
||||||
|
retval['note'] = set[6]
|
||||||
|
|
||||||
if set[4]:
|
if set[4]:
|
||||||
retval['thumbnail'] = os.path.join(self.internal_dirname, 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)
|
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, 0, self.EXIF_DICT[key])
|
||||||
self.exif_list.set_value(myiter, 1, set[key])
|
self.exif_list.set_value(myiter, 1, set[key])
|
||||||
|
|
||||||
retval['exif'] = True
|
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
|
return retval
|
||||||
|
|
||||||
def get_source(self, path):
|
def get_source(self, path):
|
||||||
@@ -396,27 +480,10 @@ class MainModel(ModelMT):
|
|||||||
return None, None
|
return None, None
|
||||||
return res[0], res[1]
|
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):
|
def delete(self, root_id, db_cursor=None, db_connection=None):
|
||||||
"""Remove subtree from main tree, remove tags from database
|
"""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 = []
|
fids = []
|
||||||
|
|
||||||
@@ -429,10 +496,8 @@ class MainModel(ModelMT):
|
|||||||
sql = """select parent_id from files where id = ?"""
|
sql = """select parent_id from files where id = ?"""
|
||||||
db_cursor.execute(sql, (root_id,))
|
db_cursor.execute(sql, (root_id,))
|
||||||
res = db_cursor.fetchone()
|
res = db_cursor.fetchone()
|
||||||
if res:
|
|
||||||
parent_id = res[0]
|
parent_id = res[0]
|
||||||
|
|
||||||
|
|
||||||
def get_children(fid):
|
def get_children(fid):
|
||||||
fids.append(fid)
|
fids.append(fid)
|
||||||
sql = """select id from files where parent_id = ?"""
|
sql = """select id from files where parent_id = ?"""
|
||||||
@@ -456,13 +521,9 @@ class MainModel(ModelMT):
|
|||||||
sql = """delete from tags_files where file_id = ?"""
|
sql = """delete from tags_files where file_id = ?"""
|
||||||
db_cursor.executemany(sql, generator())
|
db_cursor.executemany(sql, generator())
|
||||||
|
|
||||||
|
arg = self.__list_to_string(fids)
|
||||||
|
|
||||||
# remove thumbnails
|
# 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
|
sql = """select filename from thumbnails where file_id in (%s)""" % arg
|
||||||
db_cursor.execute(sql)
|
db_cursor.execute(sql)
|
||||||
res = db_cursor.fetchall()
|
res = db_cursor.fetchall()
|
||||||
@@ -477,6 +538,7 @@ class MainModel(ModelMT):
|
|||||||
if len(res) > 0:
|
if len(res) > 0:
|
||||||
for fn in res:
|
for fn in res:
|
||||||
os.unlink(os.path.join(self.internal_dirname, fn[0]))
|
os.unlink(os.path.join(self.internal_dirname, fn[0]))
|
||||||
|
os.unlink(os.path.join(self.internal_dirname, fn[1]))
|
||||||
|
|
||||||
# remove thumbs records
|
# remove thumbs records
|
||||||
sql = """delete from thumbnails where file_id = ?"""
|
sql = """delete from thumbnails where file_id = ?"""
|
||||||
@@ -486,6 +548,10 @@ class MainModel(ModelMT):
|
|||||||
sql = """delete from images where file_id = ?"""
|
sql = """delete from images where file_id = ?"""
|
||||||
db_cursor.executemany(sql, generator())
|
db_cursor.executemany(sql, generator())
|
||||||
|
|
||||||
|
# remove gthumb info
|
||||||
|
sql = """delete from gthumb where file_id = ?"""
|
||||||
|
db_cursor.executemany(sql, generator())
|
||||||
|
|
||||||
# correct parent direcotry sizes
|
# correct parent direcotry sizes
|
||||||
# get size and parent of deleting object
|
# get size and parent of deleting object
|
||||||
while parent_id:
|
while parent_id:
|
||||||
@@ -500,8 +566,6 @@ class MainModel(ModelMT):
|
|||||||
from files where parent_id=?) where id=?"""
|
from files where parent_id=?) where id=?"""
|
||||||
db_cursor.execute(sql, (parent_id, parent_id))
|
db_cursor.execute(sql, (parent_id, parent_id))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sql = """select parent_id from files where id = ? and parent_id!=id"""
|
sql = """select parent_id from files where id = ? and parent_id!=id"""
|
||||||
db_cursor.execute(sql, (parent_id,))
|
db_cursor.execute(sql, (parent_id,))
|
||||||
res = db_cursor.fetchone()
|
res = db_cursor.fetchone()
|
||||||
@@ -590,9 +654,15 @@ class MainModel(ModelMT):
|
|||||||
self.db_cursor.execute(sql, (img_id,))
|
self.db_cursor.execute(sql, (img_id,))
|
||||||
res = self.db_cursor.fetchone()
|
res = self.db_cursor.fetchone()
|
||||||
if res:
|
if res:
|
||||||
return res[0]
|
return os.path.join(self.internal_dirname, res[0])
|
||||||
return None
|
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
|
# private class functions
|
||||||
def __bytes_to_human(self, integer):
|
def __bytes_to_human(self, integer):
|
||||||
if integer <= 0 or integer < 1024:
|
if integer <= 0 or integer < 1024:
|
||||||
@@ -729,6 +799,7 @@ class MainModel(ModelMT):
|
|||||||
date datetime);""")
|
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 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_cursor.execute("insert into groups values(1, 'default', 'black');")
|
||||||
|
self.db_connection.commit()
|
||||||
|
|
||||||
def __scan(self):
|
def __scan(self):
|
||||||
"""scan content of the given path"""
|
"""scan content of the given path"""
|
||||||
@@ -952,7 +1023,7 @@ class MainModel(ModelMT):
|
|||||||
cmnts['place'],
|
cmnts['place'],
|
||||||
cmnts['date']
|
cmnts['date']
|
||||||
))
|
))
|
||||||
if cmnts['keywords']:
|
if cmnts.has_key('keywords'):
|
||||||
# TODO: add gthumb keywords to tags and group 'gthumb'
|
# TODO: add gthumb keywords to tags and group 'gthumb'
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -997,7 +1068,9 @@ class MainModel(ModelMT):
|
|||||||
if self.currentid:
|
if self.currentid:
|
||||||
if __debug__:
|
if __debug__:
|
||||||
print "m_main.py: __scan() removing old branch"
|
print "m_main.py: __scan() removing old branch"
|
||||||
|
self.statusmsg = "Removing old branch..."
|
||||||
self.delete(self.currentid, db_cursor, db_connection)
|
self.delete(self.currentid, db_cursor, db_connection)
|
||||||
|
|
||||||
self.currentid = None
|
self.currentid = None
|
||||||
else:
|
else:
|
||||||
print "new directory/cd"
|
print "new directory/cd"
|
||||||
@@ -1120,4 +1193,12 @@ class MainModel(ModelMT):
|
|||||||
else:
|
else:
|
||||||
return txt
|
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
|
pass # end of class
|
||||||
|
|||||||
@@ -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.minidom import Node
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
import gzip
|
import gzip
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ from shutil import move, copy
|
|||||||
from os import path, mkdir
|
from os import path, mkdir
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from utils import EXIF
|
|
||||||
import Image
|
import Image
|
||||||
|
|
||||||
class Img(object):
|
class Img(object):
|
||||||
@@ -40,76 +39,26 @@ class Img(object):
|
|||||||
|
|
||||||
def save(self, image_id):
|
def save(self, image_id):
|
||||||
"""Save image and asociated thumbnail into specific directory structure
|
"""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)
|
base_path = self.__get_and_make_path(image_id)
|
||||||
ext = self.filename.split('.')[-1].lower()
|
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
|
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()
|
im = self.__scale_image()
|
||||||
if im:
|
if im:
|
||||||
im.save(filepath, "JPEG")
|
im.save(thumbnail, "JPEG")
|
||||||
returncode = 1
|
returncode = 1
|
||||||
except:
|
|
||||||
f.close()
|
|
||||||
im = self.__scale_image()
|
|
||||||
if im:
|
|
||||||
im.save(filepath, "JPEG")
|
|
||||||
returncode = 2
|
|
||||||
|
|
||||||
if returncode != -1:
|
if returncode != -1:
|
||||||
# copy image
|
# copy image
|
||||||
copy(self.filename, image_filename)
|
copy(self.filename, image_filename)
|
||||||
return filepath, image_filename, returncode
|
|
||||||
|
return thumbnail, image_filename, returncode
|
||||||
|
|
||||||
# private class functions
|
# private class functions
|
||||||
def __get_and_make_path(self, img_id):
|
def __get_and_make_path(self, img_id):
|
||||||
@@ -146,7 +95,7 @@ class Img(object):
|
|||||||
img = "%s" % h[2:]
|
img = "%s" % h[2:]
|
||||||
return(path.join(t, fpath, img))
|
return(path.join(t, fpath, img))
|
||||||
|
|
||||||
def __scale_image(self, factor=True):
|
def __scale_image(self):
|
||||||
"""create thumbnail. returns image object or None"""
|
"""create thumbnail. returns image object or None"""
|
||||||
try:
|
try:
|
||||||
im = Image.open(self.filename).convert('RGB')
|
im = Image.open(self.filename).convert('RGB')
|
||||||
|
|||||||
@@ -177,14 +177,15 @@ class PointDirectoryToAdd(object):
|
|||||||
dialog.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
|
dialog.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
|
||||||
dialog.set_default_response(gtk.RESPONSE_OK)
|
dialog.set_default_response(gtk.RESPONSE_OK)
|
||||||
|
|
||||||
|
if self.URI:
|
||||||
|
dialog.set_current_folder_uri(self.URI)
|
||||||
response = dialog.run()
|
response = dialog.run()
|
||||||
if response == gtk.RESPONSE_OK:
|
if response == gtk.RESPONSE_OK:
|
||||||
self.directory.set_text(dialog.get_filename())
|
self.directory.set_text(dialog.get_filename())
|
||||||
|
self.__class__.URI = dialog.get_current_folder_uri()
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.URI:
|
|
||||||
self.dialog.set_current_folder_uri(self.URI)
|
|
||||||
dialog = self.gladexml.get_widget("addDirDialog")
|
dialog = self.gladexml.get_widget("addDirDialog")
|
||||||
ch = True
|
ch = True
|
||||||
result = dialog.run()
|
result = dialog.run()
|
||||||
@@ -195,7 +196,6 @@ class PointDirectoryToAdd(object):
|
|||||||
result = dialog.run()
|
result = dialog.run()
|
||||||
else:
|
else:
|
||||||
ch = False
|
ch = False
|
||||||
self.__class__.URI = self.dialog.get_current_folder_uri()
|
|
||||||
dialog.destroy()
|
dialog.destroy()
|
||||||
if result == gtk.RESPONSE_OK:
|
if result == gtk.RESPONSE_OK:
|
||||||
return self.volname.get_text(),self.directory.get_text()
|
return self.volname.get_text(),self.directory.get_text()
|
||||||
@@ -321,7 +321,7 @@ class LoadImageFile(object):
|
|||||||
|
|
||||||
URI="file://"+os.path.abspath(os.path.curdir)
|
URI="file://"+os.path.abspath(os.path.curdir)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, multiple=False):
|
||||||
self.dialog = gtk.FileChooserDialog(
|
self.dialog = gtk.FileChooserDialog(
|
||||||
title="Select image",
|
title="Select image",
|
||||||
action=gtk.FILE_CHOOSER_ACTION_OPEN,
|
action=gtk.FILE_CHOOSER_ACTION_OPEN,
|
||||||
@@ -332,7 +332,7 @@ class LoadImageFile(object):
|
|||||||
gtk.RESPONSE_OK
|
gtk.RESPONSE_OK
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.dialog.set_select_multiple(True)
|
self.dialog.set_select_multiple(multiple)
|
||||||
self.dialog.set_default_response(gtk.RESPONSE_OK)
|
self.dialog.set_default_response(gtk.RESPONSE_OK)
|
||||||
|
|
||||||
f = gtk.FileFilter()
|
f = gtk.FileFilter()
|
||||||
@@ -357,7 +357,10 @@ class LoadImageFile(object):
|
|||||||
|
|
||||||
if response == gtk.RESPONSE_OK:
|
if response == gtk.RESPONSE_OK:
|
||||||
try:
|
try:
|
||||||
|
if self.dialog.get_select_multiple():
|
||||||
filenames = self.dialog.get_filenames()
|
filenames = self.dialog.get_filenames()
|
||||||
|
else:
|
||||||
|
filenames = self.dialog.get_filename()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -417,3 +420,41 @@ class StatsDialog(object):
|
|||||||
if result == gtk.RESPONSE_OK:
|
if result == gtk.RESPONSE_OK:
|
||||||
return entry.get_text()
|
return entry.get_text()
|
||||||
return None
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user