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

* Added drag and drop support from files TreeView to tags cloud.

* Added tags add.
 * Code clean up.
 * Removed unnecessary imports.
 * Adapted to PEP8.
This commit is contained in:
2008-04-16 14:07:18 +00:00
parent f98c905591
commit a98ba36a23
4 changed files with 764 additions and 612 deletions

4
README
View File

@@ -60,8 +60,8 @@ TODO
For version 1.0 following aims have to be done: For version 1.0 following aims have to be done:
- searching database - searching database
- tagging files - tagging files (40%)
- user definied group of tags (represented by color in cloud tag) - user definied group of tags (represented by color in cloud tag) (10%)
x file details: x file details:
x files properties x files properties
x thumbnail x thumbnail

View File

@@ -23,7 +23,7 @@
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
__version__ = "0.8" __version__ = "0.8"
licence = \ LICENCE = \
""" """
GPL v2 GPL v2
http://www.gnu.org/licenses/gpl.txt http://www.gnu.org/licenses/gpl.txt
@@ -34,9 +34,12 @@ from os import popen
from utils import deviceHelper from utils import deviceHelper
from gtkmvc import Controller from gtkmvc import Controller
from time import time, ctime
from c_config import ConfigController from c_config import ConfigController
from views.v_config import ConfigView from views.v_config import ConfigView
from models.m_config import ConfigModel from c_tags import TagsController
from views.v_tags import TagsView
import views.v_dialogs as Dialogs import views.v_dialogs as Dialogs
@@ -45,27 +48,22 @@ from views.v_image import ImageView
import gtk import gtk
import pango import pango
import datetime
class MainController(Controller): class MainController(Controller):
"""Controller for main application window""" """Controller for main application window"""
scan_cd = False scan_cd = False
widgets = ( widgets = ("discs", "files", 'save1', 'save_as1', 'cut1', 'copy1',
"discs","files", 'paste1', 'delete1', 'add_cd', 'add_directory1', 'tb_save',
'save1','save_as1','cut1','copy1','paste1','delete1','add_cd','add_directory1', 'tb_addcd', 'tb_find', 'nb_dirs', 'description', 'stat1')
'tb_save','tb_addcd','tb_find','nb_dirs','description','stat1', widgets_all = ("discs", "files", 'file1', 'edit1', 'add_cd',
) 'add_directory1', 'help1', 'tb_save', 'tb_addcd', 'tb_find',
widgets_all = ( 'tb_new', 'tb_open', 'tb_quit', 'nb_dirs', 'description',
"discs","files", 'stat1')
'file1','edit1','add_cd','add_directory1','help1',
'tb_save','tb_addcd','tb_find','tb_new','tb_open','tb_quit',
'nb_dirs','description','stat1',
)
widgets_cancel = ('cancel','cancel1') widgets_cancel = ('cancel','cancel1')
def __init__(self, model): def __init__(self, model):
"""Initialize controller""" """Initialize controller"""
self.DND_TARGETS = [('files_tags', 0, 69)]
Controller.__init__(self, model) Controller.__init__(self, model)
return return
@@ -88,8 +86,9 @@ class MainController(Controller):
self.view['debugbtn'].hide() self.view['debugbtn'].hide()
# load configuration/defaults and set it to properties # load configuration/defaults and set it to properties
self.view['toolbar1'].set_active(self.model.config.confd['showtoolbar']) bo = self.model.config.confd['showtoolbar']
if self.model.config.confd['showtoolbar']: self.view['toolbar1'].set_active(bo)
if bo:
self.view['maintoolbar'].show() self.view['maintoolbar'].show()
else: else:
self.view['maintoolbar'].hide() self.view['maintoolbar'].hide()
@@ -105,15 +104,24 @@ class MainController(Controller):
self.model.config.confd['wy']) self.model.config.confd['wy'])
# initialize statusbar # initialize statusbar
self.context_id = self.view['mainStatus'].get_context_id('detailed res') context = self.view['mainStatus'].get_context_id('detailed res')
self.context_id = context
self.statusbar_id = self.view['mainStatus'].push(self.context_id, self.statusbar_id = self.view['mainStatus'].push(self.context_id,
"Idle") "Idle")
# make tag_cloud_textview recive dnd signals
self.view['tag_cloud_textview'].drag_dest_set(gtk.DEST_DEFAULT_ALL,
self.DND_TARGETS,
gtk.gdk.ACTION_COPY)
#ttv.connect('drag_motion', self.on_tag_cloud_textview_drag_motion)
#ttv.connect('drag_drop', self.on_tag_cloud_textview_drag_drop)
# initialize treeviews # initialize treeviews
self.__setup_disc_treeview() self.__setup_disc_treeview()
self.__setup_files_treeview() self.__setup_files_treeview()
self.__setup_exif_treeview() self.__setup_exif_treeview()
# in case passing catalog filename in command line, unlock gui # in case passing catalog filename in command line, unlock gui
if self.model.filename != None: if self.model.filename != None:
self.__activate_ui(self.model.filename) self.__activate_ui(self.model.filename)
@@ -121,26 +129,60 @@ class MainController(Controller):
# generate recent menu # generate recent menu
self.__generate_recent_menu() self.__generate_recent_menu()
# initialoze tag cloud
self.__tag_cloud()
# Show main window # Show main window
self.view['main'].show(); self.view['main'].show();
self.view['main'].drag_dest_set(0, [], 0)
return return
######################################################################### #########################################################################
# 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_tag_cloud_textview_drag_drop(self, wid, context, x, y, time):
#print '\n'.join([str(t) for t in context.targets])
#print context.drag_get_selection()
#print context.get_source_widget()
#print x, y
#print wid
context.finish(True, False, time)
return True
def on_tag_cloud_textview_drag_motion(self, wid, context, x, y, time):
context.drag_status(gtk.gdk.ACTION_COPY, time)
return True
def on_files_drag_data_get(self, widget, context, selection,
targetType, eventTime):
# get selection, and send it to the client
if targetType == self.DND_TARGETS[0][2]:
str = "1,2,3,4,57,9,0,"
selection.set(selection.target, 8, str)
def on_tag_cloud_textview_drag_data_received(self, widget, context, x, y,
selection, targetType, time):
if targetType == self.DND_TARGETS[0][2]:
print selection.data
print "kupa"
def on_edit2_activate(self, menu_item): def on_edit2_activate(self, menu_item):
try: try:
selection = self.view['files'].get_selection() selection = self.view['files'].get_selection()
model, list_of_paths = selection.get_selected_rows() model, list_of_paths = selection.get_selected_rows()
id = model.get_value(model.get_iter(list_of_paths[0]), 0) id = model.get_value(model.get_iter(list_of_paths[0]), 0)
except TypeError: except TypeError:
if __debug__: print "c_main.py: on_edit2_activate(): 0 zaznaczonych wierszy" if __debug__:
print "c_main.py: on_edit2_activate(): 0",
print "zaznaczonych wierszy"
return return
val = self.model.get_file_info(id) val = self.model.get_file_info(id)
ret = Dialogs.EditDialog(val).run() ret = Dialogs.EditDialog(val).run()
if ret: if ret:
self.model.rename(id, ret['filename']) self.model.rename(id, ret['filename'])
self.model.update_desc_and_note(id, ret['description'], ret['note']) self.model.update_desc_and_note(id,
ret['description'], ret['note'])
self.__get_item_info(id) self.__get_item_info(id)
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)
@@ -158,7 +200,9 @@ class MainController(Controller):
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)
except: except:
if __debug__: print "c_main.py: on_add_thumb1_activate(): error on getting selected items or creating thumbnails" if __debug__:
print "c_main.py: on_add_thumb1_activate(): error on getting",
print "selected items or creating thumbnails"
return return
self.__get_item_info(id) self.__get_item_info(id)
return return
@@ -166,7 +210,8 @@ class MainController(Controller):
def on_remove_thumb1_activate(self, menu_item): def on_remove_thumb1_activate(self, menu_item):
if self.model.config.confd['delwarn']: if self.model.config.confd['delwarn']:
obj = Dialogs.Qst('Delete thumbnails', 'Delete thumbnails?', obj = Dialogs.Qst('Delete thumbnails', 'Delete thumbnails?',
'Thumbnails for selected items will be permanently removed from catalog.') "Thumbnails for selected items will be \
permanently removed from catalog.")
if not obj.run(): if not obj.run():
return return
try: try:
@@ -176,7 +221,9 @@ class MainController(Controller):
id = model.get_value(model.get_iter(path),0) id = model.get_value(model.get_iter(path),0)
self.model.del_thumbnail(id) self.model.del_thumbnail(id)
except: except:
if __debug__: print "c_main.py: on_remove_thumb1_activate(): error on getting selected items or removing thumbnails" if __debug__:
print "c_main.py: on_remove_thumb1_activate(): error on",
print "getting selected items or removing thumbnails"
return return
self.model.unsaved_project = True self.model.unsaved_project = True
@@ -187,7 +234,8 @@ class MainController(Controller):
def on_remove_image1_activate(self, menu_item): def on_remove_image1_activate(self, menu_item):
if self.model.config.confd['delwarn']: if self.model.config.confd['delwarn']:
obj = Dialogs.Qst('Delete images', 'Delete all images?', obj = Dialogs.Qst('Delete images', 'Delete all images?',
'All images for selected items will be permanently removed from catalog.') 'All images for selected items will be \
permanently removed from catalog.')
if not obj.run(): if not obj.run():
return return
try: try:
@@ -197,7 +245,9 @@ class MainController(Controller):
id = model.get_value(model.get_iter(path),0) id = model.get_value(model.get_iter(path),0)
self.model.del_images(id) self.model.del_images(id)
except: except:
if __debug__: print "c_main.py: on_remove_thumb1_activate(): error on getting selected items or removing thumbnails" if __debug__:
print "c_main.py: on_remove_thumb1_activate(): error on",
print "getting selected items or removing thumbnails"
return return
self.model.unsaved_project = True self.model.unsaved_project = True
@@ -211,12 +261,14 @@ class MainController(Controller):
id = model.get_value(iter, 0) id = model.get_value(iter, 0)
img = self.model.get_image_path(id) img = self.model.get_image_path(id)
if img: if img:
if self.model.config.confd['imgview'] and len(self.model.config.confd['imgprog'])>0: if self.model.config.confd['imgview'] and \
len(self.model.config.confd['imgprog'])>0:
popen("%s %s" % (self.model.config.confd['imgprog'], img)) popen("%s %s" % (self.model.config.confd['imgprog'], img))
else: else:
ImageView(img) ImageView(img)
else: else:
Dialogs.Inf("Image view", "No Image", "This item have no real image, only thumbnail.") Dialogs.Inf("Image view", "No Image",
"This item have no real image, only thumbnail.")
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()
@@ -224,7 +276,8 @@ 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__: 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: if new_name != None and new_name != name:
self.model.rename(id, new_name) self.model.rename(id, new_name)
@@ -246,7 +299,8 @@ 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__: 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: if new_name != None and new_name != name:
self.model.rename(fid, new_name) self.model.rename(fid, new_name)
@@ -265,20 +319,34 @@ 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__: 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) w = self.view['tag_cloud_textview'].get_window(gtk.TEXT_WINDOW_TEXT)
if w: if w:
w.set_cursor(None) w.set_cursor(None)
def on_main_destroy_event(self, window, event): def on_main_destroy_event(self, window, event):
self.__do_quit() self.on_quit1_activate(widget)
return True return True
def on_tb_quit_clicked(self, widget): def on_tb_quit_clicked(self, widget):
self.__do_quit() self.on_quit1_activate(widget)
def on_quit1_activate(self, widget): def on_quit1_activate(self, widget):
self.__do_quit() """Quit and save window parameters to config file"""
# check if any unsaved project is on go.
if self.model.unsaved_project and \
self.model.config.confd['confirmquit']:
if not Dialogs.Qst('Quit application - pyGTKtalog',
'Do you really want to quit?',
"Current database is not saved, any changes \
will be lost.").run():
return
self.__store_settings()
self.model.cleanup()
gtk.main_quit()
return False
def on_new1_activate(self, widget): def on_new1_activate(self, widget):
self.__new_db() self.__new_db()
@@ -286,11 +354,34 @@ class MainController(Controller):
def on_tb_new_clicked(self, widget): def on_tb_new_clicked(self, widget):
self.__new_db() self.__new_db()
def on_add_cd_activate(self, widget): def on_add_cd_activate(self, widget, label=None, current_id=None):
self.__add_cd() """Add directory structure from cd/dvd disc"""
mount = deviceHelper.volmount(self.model.config.confd['cd'])
if mount == 'ok':
guessed_label = deviceHelper.volname(self.model.config.confd['cd'])
if not label:
label = Dialogs.InputDiskLabel(guessed_label).run()
if label != None:
self.scan_cd = True
for widget in self.widgets_all:
self.view[widget].set_sensitive(False)
self.model.source = self.model.CD
self.model.scan(self.model.config.confd['cd'], label,
current_id)
self.model.unsaved_project = True
self.__set_title(filepath=self.model.filename, modified=True)
else:
deviceHelper.volumount(self.model.config.confd['cd'])
return True
else:
Dialogs.Wrn("Error mounting device - pyGTKtalog",
"Cannot mount device pointed to %s" %
self.model.config.confd['cd'],
"Last mount message:\n%s" % mount)
return False
def on_tb_addcd_clicked(self, widget): def on_tb_addcd_clicked(self, widget):
self.__add_cd() self.on_add_cd_activate(widget)
def on_add_directory1_activate(self, widget): def on_add_directory1_activate(self, widget):
"""Show dialog for choose drectory to add from filesystem.""" """Show dialog for choose drectory to add from filesystem."""
@@ -300,7 +391,7 @@ class MainController(Controller):
def on_about1_activate(self, widget): def on_about1_activate(self, widget):
"""Show about dialog""" """Show about dialog"""
Dialogs.Abt("pyGTKtalog", __version__, "About", Dialogs.Abt("pyGTKtalog", __version__, "About",
["Roman 'gryf' Dobosz"], licence) ["Roman 'gryf' Dobosz"], LICENCE)
return return
def on_preferences_activate(self, widget): def on_preferences_activate(self, widget):
@@ -327,13 +418,27 @@ class MainController(Controller):
self.view['maintoolbar'].hide() self.view['maintoolbar'].hide()
def on_save1_activate(self, widget): def on_save1_activate(self, widget):
self.__save() """Save catalog to file"""
if self.model.filename:
self.model.save()
self.__set_title(filepath=self.model.filename)
else:
self.on_save_as1_activate(widget)
def on_tb_save_clicked(self, widget): def on_tb_save_clicked(self, widget):
self.__save() self.on_save1_activate(widget)
def on_save_as1_activate(self, widget): def on_save_as1_activate(self, widget):
self.__save_as() """Save database to file under different filename."""
path = Dialogs.ChooseDBFilename().run()
if path:
ret, err = self.model.save(path)
if ret:
self.model.config.add_recent(path)
self.__set_title(filepath=path)
else:
Dialogs.Err("Error writing file - pyGTKtalog",
"Cannot write file %s." % path, "%s" % err)
def on_stat1_activate(self, menu_item): def on_stat1_activate(self, menu_item):
self.__show_stats() self.__show_stats()
@@ -350,10 +455,30 @@ class MainController(Controller):
self.__show_stats(selected_id) self.__show_stats(selected_id)
def on_tb_open_clicked(self, widget): def on_tb_open_clicked(self, widget):
self.__open() self.on_open1_activate(widget)
return
def on_open1_activate(self, widget): def on_open1_activate(self, widget, path=None):
self.__open() """Open catalog file"""
confirm = self.model.config.confd['confirmabandon']
if self.model.unsaved_project and confirm:
obj = Dialogs.Qst('Unsaved data - pyGTKtalog',
'There is not saved database',
'Pressing "Ok" will abandon catalog.')
if not obj.run():
return
if not path:
path = Dialogs.LoadDBFile().run()
if path:
if not self.model.open(path):
Dialogs.Err("Error opening file - pyGTKtalog",
"Cannot open file %s." % path)
else:
self.__generate_recent_menu()
self.__activate_ui(path)
return
def on_discs_cursor_changed(self, widget): def on_discs_cursor_changed(self, widget):
"""Show files on right treeview, after clicking the left disc """Show files on right treeview, after clicking the left disc
@@ -377,7 +502,8 @@ class MainController(Controller):
def on_images_button_press_event(self, iconview, event): def on_images_button_press_event(self, iconview, event):
try: try:
path_and_cell = iconview.get_item_at_pos(int(event.x), int(event.y)) path_and_cell = iconview.get_item_at_pos(int(event.x),
int(event.y))
except TypeError: except TypeError:
return False return False
@@ -487,6 +613,8 @@ class MainController(Controller):
self.view['edit2'].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
if event.button == 1:
return False
def on_files_cursor_changed(self, treeview): def on_files_cursor_changed(self, treeview):
"""Show details of selected file/directory""" """Show details of selected file/directory"""
@@ -497,7 +625,9 @@ 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__: print "c_main.py: on_files_cursor_changed() insufficient iterator" if __debug__:
print "c_main.py: on_files_cursor_changed() insufficient",
print "iterator"
return return
def on_files_key_release_event(self, a, event): def on_files_key_release_event(self, a, event):
@@ -516,8 +646,8 @@ class MainController(Controller):
first_iter = f_model.get_iter_first() first_iter = f_model.get_iter_first()
first_child_value = f_model.get_value(first_iter, 0) first_child_value = f_model.get_value(first_iter, 0)
# get two steps up # get two steps up
value = self.model.get_parent_discs_value(first_child_value) val = self.model.get_parent_discs_value(first_child_value)
parent_value = self.model.get_parent_discs_value(value) parent_value = self.model.get_parent_discs_value(val)
iter = self.model.discs_tree.get_iter_first() iter = self.model.discs_tree.get_iter_first()
while iter: while iter:
current_value = self.model.discs_tree.get_value(iter,0) current_value = self.model.discs_tree.get_value(iter,0)
@@ -565,15 +695,36 @@ class MainController(Controller):
return return
def recent_item_response(self, path): def recent_item_response(self, path):
self.__open(path) self.on_open1_activate(widget)
return return
def on_add_tag1_activate(self, menu_item): def on_add_tag1_activate(self, menu_item):
print self.view['files'].get_cursor() #try:
selection = self.view['files'].get_selection()
model, list_of_paths = selection.get_selected_rows()
tags = Dialogs.TagsDialog().run()
if not tags:
return
for path in list_of_paths:
id = model.get_value(model.get_iter(path),0)
self.model.add_tags(id, tags)
#except:
# if __debug__:
# print "c_main.py: on_remove_thumb1_activate(): error on",
# print "getting selected items or removing thumbnails"
# return
self.__tag_cloud()
self.model.unsaved_project = True
self.__set_title(filepath=self.model.filename, modified=True)
self.__get_item_info(id)
return
def on_add_image1_activate(self, menu_item): def on_add_image1_activate(self, menu_item):
dialog = Dialogs.LoadImageFile(True) dialog = Dialogs.LoadImageFile(True)
toggle = gtk.CheckButton("Don't copy images. Generate only thumbnails.") toggle = gtk.CheckButton("Don't copy images. \
Generate only thumbnails.")
toggle.show() toggle.show()
dialog.dialog.set_extra_widget(toggle) dialog.dialog.set_extra_widget(toggle)
@@ -613,8 +764,7 @@ class MainController(Controller):
fid = model.get_value(model.get_iter(path), 0) fid = model.get_value(model.get_iter(path), 0)
if self.model.get_source(path) == self.model.CD: if self.model.get_source(path) == self.model.CD:
self.__add_cd(label, fid) self.on_add_cd_activate(widget, label, fid)
elif self.model.get_source(path) == self.model.DR: elif self.model.get_source(path) == self.model.DR:
self.__add_directory(filepath, label, fid) self.__add_directory(filepath, label, fid)
@@ -672,8 +822,9 @@ class MainController(Controller):
return return
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 from catalog.') "Items will be permanently \
removed from catalog.")
if not obj.run(): if not obj.run():
return return
@@ -699,7 +850,8 @@ class MainController(Controller):
model, list_of_paths = selection.get_selected_rows() model, list_of_paths = selection.get_selected_rows()
if not list_of_paths: if not list_of_paths:
list_of_paths = [1] list_of_paths = [1]
self.model.get_root_entries(model.get_value(model.get_iter(list_of_paths[0]),0)) iter = model.get_iter(list_of_paths[0])
self.model.get_root_entries(model.get_value(iter,0))
except TypeError: except TypeError:
return return
@@ -716,7 +868,8 @@ class MainController(Controller):
def on_th_delete_activate(self, menu_item): def on_th_delete_activate(self, menu_item):
if self.model.config.confd['delwarn']: if self.model.config.confd['delwarn']:
obj = Dialogs.Qst('Delete thumbnail', 'Delete thumbnail?', obj = Dialogs.Qst('Delete thumbnail', 'Delete thumbnail?',
'Current thumbnail will be permanently removed from catalog.') "Current thumbnail will be permanently removed\
from catalog.")
if not obj.run(): if not obj.run():
return return
path, column = self.view['files'].get_cursor() path, column = self.view['files'].get_cursor()
@@ -785,73 +938,6 @@ class MainController(Controller):
######################### #########################
# private class functions # private class functions
def __open(self, path=None):
"""Open catalog file"""
confirm = self.model.config.confd['confirmabandon']
if self.model.unsaved_project and confirm:
obj = Dialogs.Qst('Unsaved data - pyGTKtalog','There is not saved database','Pressing "Ok" will abandon catalog.')
if not obj.run():
return
if not path:
path = Dialogs.LoadDBFile().run()
if path:
if not self.model.open(path):
Dialogs.Err("Error opening file - pyGTKtalog","Cannot open \
file %s." % path)
else:
self.__generate_recent_menu()
self.__activate_ui(path)
return
def __save(self):
"""Save catalog to file"""
if self.model.filename:
self.model.save()
self.__set_title(filepath=self.model.filename)
else:
self.__save_as()
pass
def __save_as(self):
"""Save database to file under different filename."""
path = Dialogs.ChooseDBFilename().run()
if path:
ret, err = self.model.save(path)
if ret:
self.model.config.add_recent(path)
self.__set_title(filepath=path)
else:
Dialogs.Err("Error writing file - pyGTKtalog","Cannot write \
file %s." % path, "%s" % err)
def __add_cd(self, label=None, current_id=None):
"""Add directory structure from cd/dvd disc"""
mount = deviceHelper.volmount(self.model.config.confd['cd'])
if mount == 'ok':
guessed_label = deviceHelper.volname(self.model.config.confd['cd'])
if not label:
label = Dialogs.InputDiskLabel(guessed_label).run()
if label != None:
self.scan_cd = True
for widget in self.widgets_all:
self.view[widget].set_sensitive(False)
self.model.source = self.model.CD
self.model.scan(self.model.config.confd['cd'], label,
current_id)
self.model.unsaved_project = True
self.__set_title(filepath=self.model.filename, modified=True)
else:
deviceHelper.volumount(self.model.config.confd['cd'])
return True
else:
Dialogs.Wrn("Error mounting device - pyGTKtalog",
"Cannot mount device pointed to %s" %
self.model.config.confd['cd'],
"Last mount message:\n%s" % mount)
return False
def __add_directory(self, path=None, label=None, current_id=None): def __add_directory(self, path=None, label=None, current_id=None):
if not label or not path: if not label or not path:
res = Dialogs.PointDirectoryToAdd().run() res = Dialogs.PointDirectoryToAdd().run()
@@ -868,30 +954,13 @@ class MainController(Controller):
self.__set_title(filepath=self.model.filename, modified=True) self.__set_title(filepath=self.model.filename, modified=True)
return True return True
def __do_quit(self):
"""Quit and save window parameters to config file"""
# check if any unsaved project is on go.
if self.model.unsaved_project and \
self.model.config.confd['confirmquit']:
if not Dialogs.Qst('Quit application - pyGTKtalog',
'Do you really want to quit?',
"Current database is not saved, any changes will be lost.").run():
return
self.__store_settings()
self.model.cleanup()
gtk.main_quit()
return False
def __new_db(self): def __new_db(self):
self.__tag_cloud()
"""Create new database file""" """Create new database file"""
if self.model.unsaved_project: if self.model.unsaved_project:
if not Dialogs.Qst('Unsaved data - pyGTKtalog', if not Dialogs.Qst('Unsaved data - pyGTKtalog',
"Current database isn't saved", "Current database isn't saved",
'All changes will be lost. Do you really want to abandon it?').run(): "All changes will be lost. Do you really \
want to abandon it?").run():
return return
self.model.new() self.model.new()
@@ -931,9 +1000,10 @@ class MainController(Controller):
def __setup_files_treeview(self): def __setup_files_treeview(self):
"""Setup TreeView files widget, as columned list.""" """Setup TreeView files widget, as columned list."""
self.view['files'].set_model(self.model.files_list) v = self.view['files']
v.set_model(self.model.files_list)
self.view['files'].get_selection().set_mode(gtk.SELECTION_MULTIPLE) v.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
c = gtk.TreeViewColumn('Filename') c = gtk.TreeViewColumn('Filename')
cellpb = gtk.CellRendererPixbuf() cellpb = gtk.CellRendererPixbuf()
@@ -956,6 +1026,12 @@ class MainController(Controller):
c.set_sort_column_id(3) c.set_sort_column_id(3)
c.set_resizable(True) c.set_resizable(True)
self.view['files'].append_column(c) self.view['files'].append_column(c)
#v.enable_model_drag_source(gtk.gdk.BUTTON1_MASK,
# self.DND_TARGETS,
# gtk.gdk.ACTION_DEFAULT)
v.drag_source_set(gtk.gdk.BUTTON1_MASK, self.DND_TARGETS,
gtk.gdk.ACTION_COPY)
return return
def __setup_exif_treeview(self): def __setup_exif_treeview(self):
@@ -1040,7 +1116,7 @@ class MainController(Controller):
set = self.model.get_file_info(item) set = self.model.get_file_info(item)
buf = gtk.TextBuffer() buf = gtk.TextBuffer()
if __debug__ and set.has_key('debug'): if __debug__ and 'debug' in set:
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(), "ID: ", tag) buf.insert_with_tags(buf.get_end_iter(), "ID: ", tag)
@@ -1054,7 +1130,7 @@ class MainController(Controller):
buf.insert_with_tags(buf.get_end_iter(), "Type: ", tag) buf.insert_with_tags(buf.get_end_iter(), "Type: ", tag)
buf.insert(buf.get_end_iter(), str(set['debug']['type']) + "\n\n") buf.insert(buf.get_end_iter(), str(set['debug']['type']) + "\n\n")
if set.has_key('gthumb'): if 'gthumb' in set:
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(), "gThumb comment:\n", tag) buf.insert_with_tags(buf.get_end_iter(), "gThumb comment:\n", tag)
@@ -1066,14 +1142,14 @@ class MainController(Controller):
buf.insert(buf.get_end_iter(), set['gthumb']['date'] + "\n") buf.insert(buf.get_end_iter(), set['gthumb']['date'] + "\n")
buf.insert(buf.get_end_iter(), "\n") buf.insert(buf.get_end_iter(), "\n")
if set.has_key('description'): if 'description' in set:
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(), "Details:\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'])
buf.insert(buf.get_end_iter(), "\n") buf.insert(buf.get_end_iter(), "\n")
if set.has_key('note'): if 'note' in set:
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(), "Note:\n", tag) buf.insert_with_tags(buf.get_end_iter(), "Note:\n", tag)
@@ -1081,42 +1157,43 @@ class MainController(Controller):
self.view['description'].set_buffer(buf) self.view['description'].set_buffer(buf)
if set.has_key('images'): if 'images' in set:
self.__setup_iconview() self.__setup_iconview()
self.view['img_container'].show() self.view['img_container'].show()
else: else:
self.view['img_container'].hide() self.view['img_container'].hide()
if set.has_key('exif'): if 'exif' in set:
self.view['exif_tree'].set_model(self.model.exif_list) self.view['exif_tree'].set_model(self.model.exif_list)
self.view['exifinfo'].show() self.view['exifinfo'].show()
else: else:
self.view['exifinfo'].hide() self.view['exifinfo'].hide()
if set.has_key('thumbnail'): if 'thumbnail' in set:
self.view['thumb'].set_from_file(set['thumbnail']) self.view['thumb'].set_from_file(set['thumbnail'])
self.view['thumb_box'].show() self.view['thumb_box'].show()
#self.view['thumb'].show()
else: else:
#self.view['thumb'].hide()
self.view['thumb_box'].hide() self.view['thumb_box'].hide()
return return
'''
def on_tag_cloud_textview_drag_motion(self, widget, context, x, y, time):
context.drag_status(gtk.gdk.ACTION_COPY, time)
print "motion", x, y
'''
def __tag_cloud(self): def __tag_cloud(self):
"""generate tag cloud""" """generate tag cloud"""
# TODO: checkit! # TODO: checkit!
v = self.view['tag_cloud_textview']
def tag_cloud_click(tag, textview, event, iter, e): def tag_cloud_click(tag, textview, event, iter, e):
"""react on click on connected tag items""" """react on click on connected tag items"""
if event.type == gtk.gdk.BUTTON_RELEASE: if event.type == gtk.gdk.BUTTON_RELEASE:
print tag.get_property('name') print tag.get_property('name')
elif event.type == gtk.gdk.MOTION_NOTIFY: elif event.type == gtk.gdk.MOTION_NOTIFY:
w = \ w = v.get_window(gtk.TEXT_WINDOW_TEXT)
self.view['tag_cloud_textview'].get_window(gtk.TEXT_WINDOW_TEXT)
if w: if w:
w.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2)) w.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
else: else:
w = \ w = v.get_window(gtk.TEXT_WINDOW_TEXT)
self.view['tag_cloud_textview'].get_window(gtk.TEXT_WINDOW_TEXT)
if w: if w:
w.set_cursor(None) w.set_cursor(None)
@@ -1129,18 +1206,22 @@ class MainController(Controller):
return iter return iter
if len(self.model.tag_cloud) > 0: if len(self.model.tag_cloud) > 0:
buff = gtk.TextBuffer() buff = v.get_buffer()
buff.set_text('')
for cloud in self.model.tag_cloud: for cloud in self.model.tag_cloud:
iter = insert_blank(buff, buff.get_end_iter()) iter = insert_blank(buff, buff.get_end_iter())
tag = buff.create_tag(cloud['id']) tag = buff.create_tag(str(cloud['id']))
tag.set_property('size-points', cloud['size']) tag.set_property('size-points', cloud['size'])
tag.set_property('foreground', cloud['color']) tag.set_property('foreground', cloud['color'])
tag.connect('event', tag_cloud_click, tag) tag.connect('event', tag_cloud_click, tag)
buff.insert_with_tags(iter, cloud['name'], tag) buff.insert_with_tags(iter, cloud['name'], tag)
self.view['tag_cloud_textview'].set_buffer(buff) v.set_buffer(buff)
def __show_stats(self, selected_id=None): def __show_stats(self, selected_id=None):
data = self.model.get_stats(selected_id) data = self.model.get_stats(selected_id)
label = Dialogs.StatsDialog(data).run() label = Dialogs.StatsDialog(data).run()
def __find_tag_in_textview(self, widget, x, y):
pass
pass # end of class pass # end of class

View File

@@ -24,11 +24,10 @@
import os import os
import sys import sys
import base64
import shutil import shutil
import tarfile import tarfile
import tempfile
import string import string
import math
import gtk import gtk
import gobject import gobject
@@ -38,10 +37,7 @@ from gtkmvc.model_mt import ModelMT
from pysqlite2 import dbapi2 as sqlite from pysqlite2 import dbapi2 as sqlite
from datetime import datetime from datetime import datetime
try: import threading as _threading
import threading as _threading
except ImportError:
import dummy_threading as _threading
from m_config import ConfigModel from m_config import ConfigModel
try: try:
@@ -120,33 +116,91 @@ class MainModel(ModelMT):
# - #rgb # - #rgb
# - #rrggbb # - #rrggbb
self.tag_cloud = [] self.tag_cloud = []
'''{'id': str(1), 'name': "bezpieczeństwo", 'size': 10, 'color': '#666'},
{'id': str(2), 'name': "bsd", 'size': 14, 'color': '#333'},
{'id': str(3), 'name': "debian", 'size': 18, 'color': '#333'},
{'id': str(4), 'name': "fedora", 'size': 12, 'color': '#666'},
{'id': str(5), 'name': "firefox", 'size': 40, 'color': '#666'},
{'id': str(6), 'name': "gnome", 'size': 26, 'color': '#333'},
{'id': str(7), 'name': "gentoo", 'size': 30, 'color': '#000'},
{'id': str(8), 'name': "kde", 'size': 20, 'color': '#333'},
{'id': str(9), 'name': "kernel", 'size': 10, 'color': '#666'},
{'id': str(10), 'name': "windows", 'size': 18, 'color': '#333'},
]'''
return return
def add_tags(self, id, tags):
for tag in tags.split(','):
tag = tag.strip()
# first, checkerap if we already have tag in tags table
sql = """SELECT id FROM tags WHERE tag = ?"""
self.db_cursor.execute(sql, (tag, ))
res = self.db_cursor.fetchone()
if not res:
# insert new tag
sql = """INSERT INTO tags(tag, group_id)
VALUES(?, ?)"""
self.db_cursor.execute(sql, (tag, 1))
self.db_connection.commit()
sql = """SELECT id FROM tags WHERE tag = ?"""
self.db_cursor.execute(sql, (tag, ))
res = self.db_cursor.fetchone()
tag_id = res[0]
# then checkout if file have already tag assigned
sql = """SELECT file_id FROM tags_files
WHERE file_id = ? AND tag_id = ?"""
self.db_cursor.execute(sql, (id, tag_id))
res = self.db_cursor.fetchone()
if not res:
sql = """INSERT INTO tags_files(file_id, tag_id)
VALUES(?, ?)"""
self.db_cursor.execute(sql, (id, tag_id))
self.db_connection.commit()
self.get_tags()
return
def get_tags(self):
sql = """SELECT COUNT(f.file_id), t.id, t.tag FROM tags_files f
LEFT JOIN tags t ON f.tag_id = t.id
GROUP BY f.tag_id
ORDER BY t.tag"""
self.db_cursor.execute(sql)
res = self.db_cursor.fetchall()
if len(res) > 0:
self.tag_cloud = []
for row in res:
self.tag_cloud.append({'id': row[1],
'name': row[2],
'size': row[0],
'color':'black'})
def tag_weight(x):
"""Calculate 'weight' of tag.
Tags can have sizes between 9 to ~40. Upper size is calculated with
logarythm and can take in extereme situation around value 55 like
for 1 milion tags."""
if x==None or x==0:
x = 1
return 4 * math.log(x, math.e)
# correct font sizes with tag_weight function.
count = 0
for ta in self.tag_cloud:
tmp = int(tag_weight(ta['size']))
if tmp == 0:
tmp = 1
self.tag_cloud[count]['size'] = tmp + 8
count+=1
def add_image(self, image, id, only_thumbs=False): def add_image(self, image, id, only_thumbs=False):
"""add single image to file/directory""" """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,))
self.db_connection.commit() self.db_connection.commit()
sql = """select id from images where thumbnail is null and filename is null and file_id=?""" sql = """SELECT id FROM images WHERE thumbnail is null
AND filename IS null AND file_id=?"""
self.db_cursor.execute(sql, (id,)) self.db_cursor.execute(sql, (id,))
res = self.db_cursor.fetchone() res = self.db_cursor.fetchone()
if res: if res:
tp, ip, rc = Img(image, self.internal_dirname).save(res[0]) tp, ip, rc = Img(image, self.internal_dirname).save(res[0])
if rc != -1: if rc != -1:
sql = """update images set filename=?, thumbnail=? where id=?""" sql = """UPDATE images SET filename=?,
thumbnail=? WHERE id=?"""
if only_thumbs: if only_thumbs:
img = None img = None
else: else:
@@ -160,7 +214,7 @@ class MainModel(ModelMT):
def del_images(self, id): def del_images(self, id):
"""removes images and their thumbnails from selected file/dir""" """removes images and their thumbnails from selected file/dir"""
# remove images # remove images
sql = """select filename, thumbnail from images where file_id =?""" sql = """SELECT filename, thumbnail FROM images WHERE file_id =?"""
self.db_cursor.execute(sql, (id,)) self.db_cursor.execute(sql, (id,))
res = self.db_cursor.fetchall() res = self.db_cursor.fetchall()
if len(res) > 0: if len(res) > 0:
@@ -170,13 +224,13 @@ class MainModel(ModelMT):
os.unlink(os.path.join(self.internal_dirname, fn[1])) os.unlink(os.path.join(self.internal_dirname, fn[1]))
# remove images records # remove images records
sql = """delete from images where file_id = ?""" sql = """DELETE FROM images WHERE file_id = ?"""
self.db_cursor.execute(sql, (id,)) self.db_cursor.execute(sql, (id,))
self.db_connection.commit() self.db_connection.commit()
def delete_image(self, id): def delete_image(self, id):
"""removes image on specified image id""" """removes image on specified image id"""
sql = """select filename, thumbnail from images where id=?""" sql = """SELECT filename, thumbnail FROM images WHERE id=?"""
self.db_cursor.execute(sql, (id,)) self.db_cursor.execute(sql, (id,))
res = self.db_cursor.fetchone() res = self.db_cursor.fetchone()
if res: if res:
@@ -189,7 +243,7 @@ class MainModel(ModelMT):
print res[0] print res[0]
print res[1] print res[1]
# remove images records # remove images records
sql = """delete from images where id = ?""" sql = """DELETE FROM images WHERE id = ?"""
self.db_cursor.execute(sql, (id,)) self.db_cursor.execute(sql, (id,))
self.db_connection.commit() self.db_connection.commit()
@@ -200,7 +254,8 @@ class MainModel(ModelMT):
p, e, ret_code = Thumbnail(img_fn, p, e, ret_code = Thumbnail(img_fn,
base=self.internal_dirname).save(id) base=self.internal_dirname).save(id)
if ret_code != -1: if ret_code != -1:
sql = """insert into thumbnails(file_id, filename) values (?, ?)""" sql = """insert into thumbnails(file_id, filename)
values (?, ?)"""
self.db_cursor.execute(sql, self.db_cursor.execute(sql,
(id, (id,
p.split(self.internal_dirname)[1][1:])) p.split(self.internal_dirname)[1][1:]))
@@ -212,14 +267,14 @@ class MainModel(ModelMT):
"""removes thumbnail from selected file/dir""" """removes thumbnail from selected file/dir"""
# remove thumbnail files # remove thumbnail files
sql = """select filename from thumbnails where file_id=?""" sql = """SELECT filename FROM thumbnails WHERE file_id=?"""
self.db_cursor.execute(sql, (id,)) self.db_cursor.execute(sql, (id,))
res = self.db_cursor.fetchone() res = self.db_cursor.fetchone()
if res: if res:
os.unlink(os.path.join(self.internal_dirname, res[0])) os.unlink(os.path.join(self.internal_dirname, res[0]))
# remove thumbs records # remove thumbs records
sql = """delete from thumbnails where file_id=?""" sql = """DELETE FROM thumbnails WHERE file_id=?"""
self.db_cursor.execute(sql, (id,)) self.db_cursor.execute(sql, (id,))
self.db_connection.commit() self.db_connection.commit()
@@ -276,7 +331,8 @@ class MainModel(ModelMT):
try: try:
tar.extractall() tar.extractall()
if __debug__: if __debug__:
print "m_main.py: extracted tarfile into", self.internal_dirname print "m_main.py: extracted tarfile into",
print 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()
directories = [] directories = []
@@ -305,14 +361,15 @@ class MainModel(ModelMT):
os.chmod(tarinfo, '.') os.chmod(tarinfo, '.')
except: except:
if __debug__: if __debug__:
print "m_main.py: open(): setting corrext owner, mtime etc" print "m_main.py: open(): setting corrext owner,",
print "mtime etc"
pass pass
tar.close() tar.close()
self.__connect_to_db() self.__connect_to_db()
self.__fetch_db_into_treestore() self.__fetch_db_into_treestore()
self.config.add_recent(filename) self.config.add_recent(filename)
self.get_tags()
return True return True
def scan(self, path, label, currentid): def scan(self, path, label, currentid):
@@ -334,7 +391,7 @@ class MainModel(ModelMT):
def rename(self, id, new_name=None): def rename(self, id, new_name=None):
if new_name: if new_name:
self.db_cursor.execute("update files set filename=? \ self.db_cursor.execute("update files set filename=? \
where id=?", (new_name, id)) WHERE id=?", (new_name, id))
self.db_connection.commit() self.db_connection.commit()
self.__fetch_db_into_treestore() self.__fetch_db_into_treestore()
self.unsaved_project = True self.unsaved_project = True
@@ -354,9 +411,10 @@ class MainModel(ModelMT):
pass pass
# directories first # directories first
self.db_cursor.execute("SELECT id, filename, size, date FROM files \ sql = """SELECT id, filename, size, date FROM files
WHERE parent_id=? AND type=1 \ WHERE parent_id=? AND type=1
ORDER BY filename", (id,)) ORDER BY filename"""
self.db_cursor.execute(sql, (id,))
data = self.db_cursor.fetchall() data = self.db_cursor.fetchall()
for ch in data: for ch in data:
myiter = self.files_list.insert_before(None, None) myiter = self.files_list.insert_before(None, None)
@@ -370,10 +428,11 @@ class MainModel(ModelMT):
self.files_list.set_value(myiter, 6, gtk.STOCK_DIRECTORY) self.files_list.set_value(myiter, 6, gtk.STOCK_DIRECTORY)
# all the rest # all the rest
self.db_cursor.execute("SELECT f.id, f.filename, f.size, f.date, \ sql = """SELECT f.id, f.filename, f.size, f.date, f.type
f.type FROM files f \ FROM files f
WHERE f.parent_id=? AND f.type!=1 \ WHERE f.parent_id=? AND f.type!=1
ORDER BY f.filename", (id,)) ORDER BY f.filename"""
self.db_cursor.execute(sql, (id,))
data = self.db_cursor.fetchall() data = self.db_cursor.fetchall()
for ch in data: for ch in data:
myiter = self.files_list.insert_before(None, None) myiter = self.files_list.insert_before(None, None)
@@ -391,7 +450,8 @@ class MainModel(ModelMT):
def get_parent_discs_value(self, child_id): def get_parent_discs_value(self, child_id):
if child_id: if child_id:
self.db_cursor.execute("SELECT parent_id FROM files where id=?", (child_id,)) sql = """SELECT parent_id FROM files WHERE id=?"""
self.db_cursor.execute(sql, (child_id,))
set = self.db_cursor.fetchone() set = self.db_cursor.fetchone()
if set: if set:
return set[0] return set[0]
@@ -421,9 +481,11 @@ class MainModel(ModelMT):
retval['note'] = set[6] retval['note'] = set[6]
if set[4]: if set[4]:
retval['thumbnail'] = os.path.join(self.internal_dirname, set[4]) pa = os.path.join(self.internal_dirname, set[4])
retval['thumbnail'] = pa
sql = """SELECT id, filename, thumbnail from images WHERE file_id = ?""" sql = """SELECT id, filename, thumbnail FROM images
WHERE file_id = ?"""
self.db_cursor.execute(sql, (id,)) self.db_cursor.execute(sql, (id,))
set = self.db_cursor.fetchall() set = self.db_cursor.fetchall()
if set: if set:
@@ -437,7 +499,7 @@ class MainModel(ModelMT):
sql = """SELECT camera, date, aperture, exposure_program, sql = """SELECT camera, date, aperture, exposure_program,
exposure_bias, iso, focal_length, subject_distance, metering_mode, exposure_bias, iso, focal_length, subject_distance, metering_mode,
flash, light_source, resolution, orientation flash, light_source, resolution, orientation
from exif FROM exif
WHERE file_id = ?""" WHERE file_id = ?"""
self.db_cursor.execute(sql, (id,)) self.db_cursor.execute(sql, (id,))
set = self.db_cursor.fetchone() set = self.db_cursor.fetchone()
@@ -452,20 +514,22 @@ class MainModel(ModelMT):
retval['exif'] = True retval['exif'] = True
# gthumb # gthumb
sql = """SELECT note, place, date from gthumb WHERE file_id = ?""" sql = """SELECT note, place, date FROM gthumb WHERE file_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:
retval['gthumb'] = {'note': set[0], 'place': set[1], 'date': set[2]} 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):
"""get source of top level directory""" """get source of top level directory"""
bid = self.discs_tree.get_value(self.discs_tree.get_iter(path[0]), bid = self.discs_tree.get_value(self.discs_tree.get_iter(path[0]), 0)
0) sql = """SELECT source FROM files WHERE id = ?"""
self.db_cursor.execute("select source from files where id = ?", self.db_cursor.execute(sql,
(bid,)) (bid,))
res = self.db_cursor.fetchone() res = self.db_cursor.fetchone()
if res == None: if res == None:
@@ -474,10 +538,10 @@ class MainModel(ModelMT):
def get_label_and_filepath(self, path): def get_label_and_filepath(self, path):
"""get source of top level directory""" """get source of top level directory"""
bid = self.discs_tree.get_value(self.discs_tree.get_iter(path), bid = self.discs_tree.get_value(self.discs_tree.get_iter(path), 0)
0) sql = """SELECT filepath, filename FROM files
self.db_cursor.execute("select filepath, filename from files \ WHERE id = ? AND parent_id = 1"""
where id = ? and parent_id = 1", (bid,)) self.db_cursor.execute(sql, (bid,))
res = self.db_cursor.fetchone() res = self.db_cursor.fetchone()
if res == None: if res == None:
return None, None return None, None
@@ -496,14 +560,14 @@ class MainModel(ModelMT):
if not db_connection: if not db_connection:
db_connection = self.db_connection db_connection = self.db_connection
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()
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 = ?"""
db_cursor.execute(sql, (fid,)) db_cursor.execute(sql, (fid,))
res = db_cursor.fetchall() res = db_cursor.fetchall()
if len(res)>0: if len(res)>0:
@@ -517,17 +581,17 @@ class MainModel(ModelMT):
yield (c,) yield (c,)
# remove files records # remove files records
sql = """delete from files where id = ?""" sql = """DELETE FROM files WHERE id = ?"""
db_cursor.executemany(sql, generator()) db_cursor.executemany(sql, generator())
# remove tags records # remove tags records
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) arg = str(tuple(fids))
# remove thumbnails # remove thumbnails
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()
if len(res) > 0: if len(res) > 0:
@@ -535,7 +599,8 @@ class MainModel(ModelMT):
os.unlink(os.path.join(self.internal_dirname, fn[0])) os.unlink(os.path.join(self.internal_dirname, fn[0]))
# remove images # remove images
sql = """select filename, thumbnail from images where file_id in (%s)""" % arg sql = """SELECT filename, thumbnail FROM images
WHERE file_id IN %s""" % arg
db_cursor.execute(sql) db_cursor.execute(sql)
res = db_cursor.fetchall() res = db_cursor.fetchall()
if len(res) > 0: if len(res) > 0:
@@ -545,32 +610,34 @@ class MainModel(ModelMT):
os.unlink(os.path.join(self.internal_dirname, fn[1])) 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 = ?"""
db_cursor.executemany(sql, generator()) db_cursor.executemany(sql, generator())
# remove images records # remove images records
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 # remove gthumb info
sql = """delete from gthumb where file_id = ?""" sql = """DELETE FROM gthumb WHERE file_id = ?"""
db_cursor.executemany(sql, generator()) 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:
sql = """update files set size = sql = """UPDATE files SET size =
(select case when (SELECT CASE WHEN
sum(size) is null SUM(size) IS null
then THEN
0 0
else ELSE
sum(size) SUM(size)
end END
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()
if res: if res:
@@ -585,7 +652,7 @@ class MainModel(ModelMT):
"""get statistic information""" """get statistic information"""
retval = {} retval = {}
if selected_id: if selected_id:
sql = """select id, type, parent_id from files where id=?""" sql = """SELECT id, type, parent_id FROM files WHERE id=?"""
self.db_cursor.execute(sql, (selected_id,)) self.db_cursor.execute(sql, (selected_id,))
res = self.db_cursor.fetchone() res = self.db_cursor.fetchone()
if not res: if not res:
@@ -595,9 +662,11 @@ class MainModel(ModelMT):
# collect all parent_id's # collect all parent_id's
parents = [] parents = []
def _recurse(fid): def _recurse(fid):
parents.append(fid) parents.append(fid)
sql = """select id from files where type=? and parent_id=? and parent_id!=1""" sql = """SELECT id FROM files
WHERE type=? AND parent_id=? AND parent_id!=1"""
self.db_cursor.execute(sql, (self.DIR, fid)) self.db_cursor.execute(sql, (self.DIR, fid))
res = self.db_cursor.fetchall() res = self.db_cursor.fetchall()
if res: if res:
@@ -615,37 +684,42 @@ class MainModel(ModelMT):
files_count = 0 files_count = 0
for p in parents: for p in parents:
sql = """select count(id) from files where type!=0 and type!=1 and parent_id=?""" sql = """SELECT count(id) FROM files
WHERE type!=0 AND type!=1 AND parent_id=?"""
self.db_cursor.execute(sql, (p,)) self.db_cursor.execute(sql, (p,))
res = self.db_cursor.fetchone() res = self.db_cursor.fetchone()
if res: if res:
files_count+=res[0] files_count+=res[0]
retval['files'] = files_count retval['files'] = files_count
sql = """select size from files where id=?""" sql = """SELECT size FROM files WHERE id=?"""
self.db_cursor.execute(sql, (selected_id,)) self.db_cursor.execute(sql, (selected_id,))
res = self.db_cursor.fetchone() res = self.db_cursor.fetchone()
if res: if res:
retval['size'] = self.__bytes_to_human(res[0]) retval['size'] = self.__bytes_to_human(res[0])
else: else:
sql = """select count(id) from files where parent_id=1 and type=1""" sql = """SELECT count(id) FROM files
WHERE parent_id=1 AND type=1"""
self.db_cursor.execute(sql) self.db_cursor.execute(sql)
res = self.db_cursor.fetchone() res = self.db_cursor.fetchone()
if res: if res:
retval['discs'] = res[0] retval['discs'] = res[0]
sql = """select count(id) from files where parent_id!=1 and type=1""" sql = """SELECT count(id) FROM files
WHERE parent_id!=1 AND type=1"""
self.db_cursor.execute(sql) self.db_cursor.execute(sql)
res = self.db_cursor.fetchone() res = self.db_cursor.fetchone()
if res: if res:
retval['dirs'] = res[0] retval['dirs'] = res[0]
sql = """select count(id) from files where parent_id!=1 and type!=1""" sql = """SELECT count(id) FROM files
WHERE parent_id!=1 AND type!=1"""
self.db_cursor.execute(sql) self.db_cursor.execute(sql)
res = self.db_cursor.fetchone() res = self.db_cursor.fetchone()
if res: if res:
retval['files'] = res[0] retval['files'] = res[0]
sql = """select sum(size) from files where parent_id=1 and type=1""" sql = """SELECT sum(size) FROM files
WHERE parent_id=1 AND type=1"""
self.db_cursor.execute(sql) self.db_cursor.execute(sql)
res = self.db_cursor.fetchone() res = self.db_cursor.fetchone()
if res: if res:
@@ -654,7 +728,7 @@ class MainModel(ModelMT):
def get_image_path(self, img_id): def get_image_path(self, img_id):
"""return image location""" """return image location"""
sql = """select filename from images where id=?""" sql = """SELECT filename FROM images WHERE id=?"""
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:
@@ -721,7 +795,8 @@ class MainModel(ModelMT):
def __create_internal_dirname(self): def __create_internal_dirname(self):
self.cleanup() self.cleanup()
self.internal_dirname = "/tmp/pygtktalog%d" % datetime.now().microsecond self.internal_dirname = "/tmp/pygtktalog%d" % \
datetime.now().microsecond
try: try:
os.mkdir(self.internal_dirname) os.mkdir(self.internal_dirname)
except IOError, (errno, strerror): except IOError, (errno, strerror):
@@ -802,8 +877,11 @@ class MainModel(ModelMT):
note TEXT, note TEXT,
place TEXT, place TEXT,
date datetime);""") date datetime);""")
self.db_cursor.execute("insert into files values(1, 1, 'root', null, 0, 0, 0, 0, null, null);") sql = """INSERT INTO files
self.db_cursor.execute("insert into groups values(1, 'default', 'black');") VALUES(1, 1, 'root', null, 0, 0, 0, 0, null, null)"""
self.db_cursor.execute(sql)
sql = """INSERT INSERT groups VALUES(1, 'default', 'black')"""
self.db_cursor.execute(sql)
self.db_connection.commit() self.db_connection.commit()
def __scan(self): def __scan(self):
@@ -857,22 +935,21 @@ class MainModel(ModelMT):
if parent_id == 1: if parent_id == 1:
self.fresh_disk_iter = myit self.fresh_disk_iter = myit
self.discs_tree.set_value(myit,2,gtk.STOCK_CDROM) self.discs_tree.set_value(myit,2,gtk.STOCK_CDROM)
sql = """insert into sql = """INSERT INTO
files(parent_id, filename, filepath, date, size, type, source) files(parent_id, filename, filepath, date,
values(?,?,?,?,?,?,?)""" size, type, source)
VALUES(?,?,?,?,?,?,?)"""
db_cursor.execute(sql, (parent_id, name, path, date, size, db_cursor.execute(sql, (parent_id, name, path, date, size,
filetype, self.source)) filetype, self.source))
else: else:
self.discs_tree.set_value(myit,2,gtk.STOCK_DIRECTORY) self.discs_tree.set_value(myit,2,gtk.STOCK_DIRECTORY)
sql = """ sql = """INSERT INTO
insert into
files(parent_id, filename, filepath, date, size, type) files(parent_id, filename, filepath, date, size, type)
values(?,?,?,?,?,?) VALUES(?,?,?,?,?,?)"""
""" db_cursor.execute(sql, (parent_id, name, path,
db_cursor.execute(sql, date, size, filetype))
(parent_id, name, path, date, size, filetype))
sql = """select seq FROM sqlite_sequence WHERE name='files'""" sql = """SELECT seq FROM sqlite_sequence WHERE name='files'"""
db_cursor.execute(sql) db_cursor.execute(sql)
currentid=db_cursor.fetchone()[0] currentid=db_cursor.fetchone()[0]
@@ -904,12 +981,11 @@ class MainModel(ModelMT):
if os.path.islink(current_dir): if os.path.islink(current_dir):
l = self.__decode_filename(os.readlink(current_dir)) l = self.__decode_filename(os.readlink(current_dir))
sql = """ sql = """INSERT INTO
insert into files(parent_id, filename, filepath, date, size, type) files(parent_id, filename, filepath, date, size, type)
values(?,?,?,?,?,?) VALUES(?,?,?,?,?,?)"""
"""
db_cursor.execute(sql, (currentid, j + " -> " + l, db_cursor.execute(sql, (currentid, j + " -> " + l,
ocurrent_dir, st_mtime, 0, current_dir, st_mtime, 0,
self.LIN)) self.LIN))
dirsize = 0 dirsize = 0
else: else:
@@ -944,17 +1020,16 @@ class MainModel(ModelMT):
# do NOT follow symbolic links # do NOT follow symbolic links
if os.path.islink(current_file): if os.path.islink(current_file):
l = self.__decode_filename(os.readlink(current_file)) l = self.__decode_filename(os.readlink(current_file))
sql = """insert into files(parent_id, filename, filepath, sql = """INSERT INTO
date, size, type) files(parent_id, filename, filepath, date, size, type)
values(?,?,?,?,?,?)""" VALUES(?,?,?,?,?,?)"""
db_cursor.execute(sql, (currentid, j + " -> " + l, db_cursor.execute(sql, (currentid, j + " -> " + l,
current_file, st_mtime, 0, current_file, st_mtime, 0,
self.LIN)) self.LIN))
else: else:
sql = """ sql = """INSERT INTO
insert into files(parent_id, filename, filepath, date, size, type) files(parent_id, filename, filepath, date, size, type)
values(?,?,?,?,?,?) VALUES(?,?,?,?,?,?)"""
"""
db_cursor.execute(sql, (currentid, j, current_file, db_cursor.execute(sql, (currentid, j, current_file,
st_mtime, st_size, self.FIL)) st_mtime, st_size, self.FIL))
@@ -969,7 +1044,8 @@ class MainModel(ModelMT):
update = True update = True
exif = None exif = None
sql = """select seq FROM sqlite_sequence WHERE name='files'""" sql = """SELECT seq FROM sqlite_sequence
WHERE name='files'"""
db_cursor.execute(sql) db_cursor.execute(sql)
fileid = db_cursor.fetchone()[0] fileid = db_cursor.fetchone()[0]
@@ -977,14 +1053,19 @@ class MainModel(ModelMT):
# Images - thumbnails and exif data # Images - thumbnails and exif data
if self.config.confd['thumbs'] and ext in self.IMG: if self.config.confd['thumbs'] and ext in self.IMG:
tpath, exif, ret_code = Thumbnail(current_file, base=self.internal_dirname).save(fileid) t = Thumbnail(current_file,
base=self.internal_dirname)
tpath, exif, ret_code = t.save(fileid)
if ret_code != -1: if ret_code != -1:
sql = """insert into thumbnails(file_id, filename) values (?, ?)""" sql = """INSERT INTO
db_cursor.execute(sql, (fileid, thumbnails(file_id, filename)
tpath.split(self.internal_dirname)[1][1:])) VALUES(?, ?)"""
t = tpath.split(self.internal_dirname)[1][1:]
db_cursor.execute(sql, (fileid, t))
# exif - stroe data in exif table # exif - store data in exif table
if self.config.confd['exif'] and ext in ['jpg', 'jpeg']: jpg = ['jpg', 'jpeg']
if self.config.confd['exif'] and ext in jpg:
p = None p = None
if self.config.confd['thumbs'] and exif: if self.config.confd['thumbs'] and exif:
p = ParseExif(exif_dict=exif) p = ParseExif(exif_dict=exif)
@@ -1026,13 +1107,11 @@ class MainModel(ModelMT):
db_cursor.execute(sql, (fileid, db_cursor.execute(sql, (fileid,
cmnts['note'], cmnts['note'],
cmnts['place'], cmnts['place'],
cmnts['date'] cmnts['date']))
)) if 'keywords' in cmnts:
if cmnts.has_key('keywords'): # TODO: add gthumb keywords to tags
# TODO: add gthumb keywords to tags and group 'gthumb'
pass pass
# Extensions - user defined actions # Extensions - user defined actions
if ext in self.config.confd['extensions'].keys(): if ext in self.config.confd['extensions'].keys():
cmd = self.config.confd['extensions'][ext] cmd = self.config.confd['extensions'][ext]
@@ -1041,19 +1120,17 @@ class MainModel(ModelMT):
desc = '' desc = ''
for line in output: for line in output:
desc += line desc += line
#desc = string.replace(desc, "\n", "\\n")
sql = """update files set description=? where id=?""" sql = """UPDATE files SET description=?
WHERE id=?"""
db_cursor.execute(sql, (desc, fileid)) db_cursor.execute(sql, (desc, fileid))
#if i.split('.').[-1].lower() in mov_ext:
# # video only
# info = filetypeHelper.guess_video(os.path.join(root,i))
### end of scan ### end of scan
if update: if update:
self.statusmsg = "Scannig: %s" % current_file self.statusmsg = "Scannig: %s" % current_file
self.progress = step * self.count self.progress = step * self.count
sql = """update files set size=? where id=?""" sql = """UPDATE files SET size=? WHERE id=?"""
db_cursor.execute(sql,(_size, currentid)) db_cursor.execute(sql,(_size, currentid))
if self.abort: if self.abort:
return -1 return -1
@@ -1098,23 +1175,20 @@ class MainModel(ModelMT):
self.__clear_discs_tree() self.__clear_discs_tree()
#connect #connect
detect_types = sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES
db_connection = sqlite.connect("%s" % \ db_connection = sqlite.connect("%s" % \
(self.internal_dirname + '/db.sqlite'), (self.internal_dirname + '/db.sqlite'),
detect_types=sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES) detect_types = detect_types)
db_cursor = db_connection.cursor() db_cursor = db_connection.cursor()
# fetch all the directories # fetch all the directories
sql = """ sql = """SELECT id, parent_id, filename FROM files
SELECT id, parent_id, filename FROM files WHERE type=1 ORDER BY parent_id, filename"""
WHERE type=1 ORDER BY parent_id, filename
"""
db_cursor.execute(sql) db_cursor.execute(sql)
data = db_cursor.fetchall() data = db_cursor.fetchall()
try: try:
sql = """ sql = """SELECT id, parent_id, filename FROM files
SELECT id, parent_id, filename FROM files WHERE type=1 ORDER BY parent_id, filename"""
WHERE type=1 ORDER BY parent_id, filename
"""
db_cursor.execute(sql) db_cursor.execute(sql)
data = db_cursor.fetchall() data = db_cursor.fetchall()
except: except:
@@ -1148,19 +1222,22 @@ class MainModel(ModelMT):
# launch scanning. # launch scanning.
get_children() get_children()
if __debug__: if __debug__:
print "m_main.py: __fetch_db_into_treestore() tree generation time: ", (datetime.now() - start_date) print "m_main.py: __fetch_db_into_treestore()",
print "tree generation time: ", (datetime.now() - start_date)
db_connection.close() db_connection.close()
return return
def __append_added_volume(self): def __append_added_volume(self):
"""append branch from DB to existing tree model""" """append branch from DB to existing tree model"""
#connect #connect
detect_types = sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES
db_connection = sqlite.connect("%s" % db_connection = sqlite.connect("%s" %
(self.internal_dirname + '/db.sqlite'), (self.internal_dirname + '/db.sqlite'),
detect_types=sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES) detect_types = detect_types)
db_cursor = db_connection.cursor() db_cursor = db_connection.cursor()
sql = """SELECT id, parent_id, filename FROM files WHERE type=1 ORDER BY parent_id, filename""" sql = """SELECT id, parent_id, filename FROM files
WHERE type=1 ORDER BY parent_id, filename"""
db_cursor.execute(sql) db_cursor.execute(sql)
data = db_cursor.fetchall() data = db_cursor.fetchall()
@@ -1187,7 +1264,8 @@ class MainModel(ModelMT):
# launch scanning. # launch scanning.
get_children() get_children()
if __debug__: if __debug__:
print "m_main.py: __append_added_volume() tree generation time: ", (datetime.now() - start_date) print "m_main.py: __append_added_volume() tree generation time: ",
print datetime.now() - start_date
db_connection.close() db_connection.close()
return return
@@ -1197,12 +1275,3 @@ 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

View File

@@ -31,6 +31,7 @@ class MainView(View):
application. The widgets set is loaded from glade file""" application. The widgets set is loaded from glade file"""
GLADE = os.path.join(utils.globals.GLADE_DIR, "main.glade") GLADE = os.path.join(utils.globals.GLADE_DIR, "main.glade")
def __init__(self, ctrl): def __init__(self, ctrl):
View.__init__(self, ctrl, self.GLADE) View.__init__(self, ctrl, self.GLADE)
@@ -38,6 +39,7 @@ class MainView(View):
self['separatormenuitem4'].hide() self['separatormenuitem4'].hide()
self['list1'].hide() self['list1'].hide()
self['thumbnails1'].hide() self['thumbnails1'].hide()
#self['tag_cloud_textview'].drag_dest_set(0, [], 0)
return return
pass # end of class pass # end of class