mirror of
https://github.com/gryf/pygtktalog.git
synced 2025-12-17 11:30:19 +01:00
2003 lines
74 KiB
Python
2003 lines
74 KiB
Python
# 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
|
|
|
|
# -------------------------------------------------------------------------
|
|
|
|
import os
|
|
import sys
|
|
import shutil
|
|
import bz2
|
|
import math
|
|
import sqlite3 as sqlite
|
|
from tempfile import mkstemp
|
|
from datetime import datetime
|
|
import threading as _threading
|
|
|
|
import gtk
|
|
import gobject
|
|
|
|
from gtkmvc.model_mt import ModelMT
|
|
from m_config import ConfigModel
|
|
|
|
try:
|
|
from lib.thumbnail import Thumbnail
|
|
from lib.img import Img
|
|
except:
|
|
pass
|
|
from lib.parse_exif import ParseExif
|
|
from lib.gthumb import GthumbCommentParser
|
|
|
|
from lib.no_thumb import no_thumb as no_thumb_img
|
|
from lib.video import Video
|
|
|
|
class MainModel(ModelMT):
|
|
"""Create, load, save, manipulate db file which is container for data"""
|
|
|
|
__properties__ = {'busy': False,
|
|
'statusmsg': '',
|
|
'progress': 0,
|
|
# point from search controller - changes while user activate specified
|
|
# file on search
|
|
'point': None,}
|
|
|
|
# constants instead of dictionary tables
|
|
# type of files
|
|
LAB = 0 # root of the tree - label/collection name
|
|
DIR = 1 # directory
|
|
FIL = 2 # file
|
|
LIN = 3 # symbolic link
|
|
|
|
CD = 1 # sorce: cd/dvd
|
|
DR = 2 # source: filesystem
|
|
|
|
EXIF_DICT = {0: 'Camera',
|
|
1: 'Date',
|
|
2: 'Aperture',
|
|
3: 'Exposure program',
|
|
4: 'Exposure bias',
|
|
5: 'ISO',
|
|
6: 'Focal length',
|
|
7: 'Subject distance',
|
|
8: 'Metering mode',
|
|
9: 'Flash',
|
|
10: 'Light source',
|
|
11: 'Resolution',
|
|
12: 'Orientation'}
|
|
|
|
# images extensions - only for PIL and EXIF
|
|
IMG = ['jpg', 'jpeg', 'gif', 'png', 'tif', 'tiff', 'tga', 'pcx', 'bmp',
|
|
'xbm', 'xpm', 'jp2', 'jpx', 'pnm']
|
|
MOV = ['avi', 'mpg', 'mpeg', 'mkv', 'wmv', 'ogm', 'mov']
|
|
|
|
def __init__(self):
|
|
"""initialize"""
|
|
ModelMT.__init__(self)
|
|
self.unsaved_project = False
|
|
self.filename = None # catalog saved/opened filename
|
|
self.internal_dirname = None
|
|
self.image_path = None
|
|
self.db_connection = None
|
|
self.db_cursor = None
|
|
self.abort = False
|
|
self.source = self.CD
|
|
self.config = ConfigModel()
|
|
self.config.load()
|
|
self.path = None
|
|
self.label = None
|
|
self.currentid = None
|
|
self.thread = None
|
|
self.busy = False
|
|
self.statusmsg = "Idle"
|
|
self.selected_tags = {}
|
|
self.search_created = False
|
|
self.db_tmp_path = False
|
|
|
|
# Directory tree: id, name, icon, type
|
|
self.discs_tree = gtk.TreeStore(gobject.TYPE_INT,
|
|
gobject.TYPE_STRING,
|
|
str,
|
|
gobject.TYPE_INT)
|
|
# File list of selected directory: id, disc, filename, path, size,
|
|
# date, type, icon
|
|
self.files_list = gtk.ListStore(gobject.TYPE_INT,
|
|
gobject.TYPE_STRING,
|
|
gobject.TYPE_STRING,
|
|
gobject.TYPE_STRING,
|
|
gobject.TYPE_UINT64,
|
|
gobject.TYPE_STRING,
|
|
gobject.TYPE_INT,
|
|
str)
|
|
# Search list. Exactly the same as file list above.
|
|
self.search_list = gtk.ListStore(gobject.TYPE_INT,
|
|
gobject.TYPE_STRING,
|
|
gobject.TYPE_STRING,
|
|
gobject.TYPE_STRING,
|
|
gobject.TYPE_UINT64,
|
|
gobject.TYPE_STRING,
|
|
gobject.TYPE_INT,
|
|
str)
|
|
# iconview store - id, pixbuffer
|
|
self.images_store = gtk.ListStore(gobject.TYPE_INT, gtk.gdk.Pixbuf)
|
|
|
|
# exif liststore - id, exif key, exif value
|
|
self.exif_list = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING,
|
|
gobject.TYPE_STRING)
|
|
# search combobox liststore - entry
|
|
self.search_history = gtk.ListStore(str)
|
|
|
|
# fill it
|
|
self.__fill_history_model()
|
|
|
|
# tag cloud array element is a dict with 5 keys:
|
|
# elem = {'id': str(id), 'name': tagname, 'size': size,
|
|
# 'count': cout, 'color': color}
|
|
# where color is in one of format:
|
|
# - named (i.e. red, blue, black and so on)
|
|
# - #rgb
|
|
# - #rrggbb
|
|
self.tag_cloud = []
|
|
|
|
try:
|
|
path = os.path.join(os.environ['HOME'], ".pygtktalog")
|
|
imgpath = os.path.join(path, "images")
|
|
except KeyError:
|
|
raise KeyError, "Cannot stat path for current user home!"
|
|
|
|
if os.path.exists(path):
|
|
if not os.path.isdir(path):
|
|
raise RuntimeError, "There is regular file \"%s\" on the way. Please remove it." % \
|
|
path
|
|
else:
|
|
os.mkdir(path)
|
|
|
|
|
|
if os.path.exists(imgpath):
|
|
if not os.path.isdir(imgpath):
|
|
print "Warning:",
|
|
"There is regular file \"%s\" on the way. Please remove it, otherwise images cannot be used" % imgpath
|
|
else:
|
|
os.mkdir(imgpath)
|
|
|
|
self.image_path = imgpath
|
|
|
|
self.new()
|
|
return
|
|
|
|
def add_search_history(self, txt):
|
|
"""add txt into search history, update search_history model"""
|
|
self.config.add_search_history(txt)
|
|
self.__fill_history_model()
|
|
return
|
|
|
|
def add_tags(self, fid, tags):
|
|
"""add tag (if not exists) and connect it with file"""
|
|
for tag in tags.split(','):
|
|
tag = tag.strip()
|
|
|
|
# SQL: first, chek if we already have tag in tags table; get id
|
|
sql = """SELECT id FROM tags WHERE tag = ?"""
|
|
self.db_cursor.execute(sql, (tag, ))
|
|
res = self.db_cursor.fetchone()
|
|
if not res:
|
|
# SQL: insert new tag
|
|
sql = """INSERT INTO tags(tag, group_id)
|
|
VALUES(?, ?)"""
|
|
self.db_cursor.execute(sql, (tag, 1))
|
|
self.db_connection.commit()
|
|
# SQL: get tag id
|
|
sql = """SELECT id FROM tags WHERE tag = ?"""
|
|
self.db_cursor.execute(sql, (tag, ))
|
|
res = self.db_cursor.fetchone()
|
|
|
|
tag_id = res[0]
|
|
|
|
# SQL: 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, (fid, tag_id))
|
|
res = self.db_cursor.fetchone()
|
|
if not res:
|
|
# SQL: connect tag with file
|
|
sql = """INSERT INTO tags_files(file_id, tag_id)
|
|
VALUES(?, ?)"""
|
|
self.db_cursor.execute(sql, (fid, tag_id))
|
|
self.db_connection.commit()
|
|
self.get_tags()
|
|
return
|
|
|
|
def get_tags_by_file_id(self, file_id_list):
|
|
"""return dictionary of tags by connected files"""
|
|
# SQL: get tags by file_ids
|
|
if len(file_id_list) == 1:
|
|
sql = "(%d)" % file_id_list[0]
|
|
else:
|
|
sql = str(tuple(file_id_list))
|
|
sql = """SELECT DISTINCT t.id, t.tag FROM tags_files f
|
|
LEFT JOIN tags t on t.id = f.tag_id
|
|
WHERE f.file_id in """ + sql + """
|
|
ORDER BY t.tag"""
|
|
self.db_cursor.execute(sql)
|
|
res = self.db_cursor.fetchall()
|
|
|
|
retval = {}
|
|
for tag in res:
|
|
retval[tag[0]] = tag[1]
|
|
return retval
|
|
|
|
def get_tag_by_id(self, tag_id):
|
|
"""get tag (string) by its id"""
|
|
# SQL: get tag by id
|
|
sql = """SELECT tag FROM tags WHERE id = ?"""
|
|
self.db_cursor.execute(sql, (int(tag_id), ))
|
|
res = self.db_cursor.fetchone()
|
|
if not res:
|
|
return None
|
|
return res[0]
|
|
|
|
def get_file_tags(self, file_id):
|
|
"""get tags of file"""
|
|
|
|
# SQL: get tag by id
|
|
sql = """SELECT t.id, t.tag FROM tags t
|
|
LEFT JOIN tags_files f ON t.id=f.tag_id
|
|
WHERE f.file_id = ?
|
|
ORDER BY t.tag"""
|
|
self.db_cursor.execute(sql, (int(file_id), ))
|
|
res = self.db_cursor.fetchall()
|
|
|
|
tmp = {}
|
|
if len(res) == 0:
|
|
return None
|
|
|
|
for row in res:
|
|
tmp[row[0]] = row[1]
|
|
|
|
return tmp
|
|
|
|
def delete_tags(self, file_id_list, tag_id_list):
|
|
"""remove tags from selected files"""
|
|
for file_id in file_id_list:
|
|
# SQL: remove tags for selected file
|
|
if len(tag_id_list) == 1:
|
|
sql = "(%d)" % tag_id_list[0]
|
|
else:
|
|
sql = str(tuple(tag_id_list))
|
|
sql = """DELETE FROM tags_files WHERE file_id = ?
|
|
AND tag_id IN """ + sql
|
|
self.db_cursor.execute(sql, (int(file_id), ))
|
|
self.db_connection.commit()
|
|
|
|
for tag_id in tag_id_list:
|
|
sql = """SELECT count(*) FROM tags_files WHERE tag_id=?"""
|
|
self.db_cursor.execute(sql, (int(tag_id),))
|
|
res = self.db_cursor.fetchone()
|
|
if res[0] == 0:
|
|
sql = """DELETE FROM tags WHERE id=?"""
|
|
self.db_cursor.execute(sql, (int(tag_id),))
|
|
self.db_connection.commit()
|
|
|
|
def get_tags(self):
|
|
"""fill tags dict with values from db"""
|
|
if not self.selected_tags:
|
|
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"""
|
|
else:
|
|
id_filter = self.__filter()
|
|
sql = """SELECT COUNT(f.file_id), t.id, t.tag FROM tags_files f
|
|
LEFT JOIN tags t ON f.tag_id = t.id
|
|
WHERE f.file_id in """ + str(tuple(id_filter)) + \
|
|
"""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],
|
|
'count': row[0],
|
|
'color':'black'})
|
|
|
|
def tag_weight(initial_value):
|
|
"""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 tagged files."""
|
|
if not initial_value:
|
|
initial_value = 1
|
|
return 4 * math.log(initial_value, math.e)
|
|
|
|
# correct font sizes with tag_weight function.
|
|
count = 0
|
|
for tag0 in self.tag_cloud:
|
|
tmp = int(tag_weight(tag0['size']))
|
|
if tmp == 0:
|
|
tmp = 1
|
|
self.tag_cloud[count]['size'] = tmp + 8
|
|
count += 1
|
|
|
|
def add_tag_to_path(self, tag_id):
|
|
"""add tag to filter"""
|
|
temp = {}
|
|
tag_name = self.get_tag_by_id(tag_id)
|
|
for i in self.selected_tags:
|
|
temp[i] = self.selected_tags[i]
|
|
|
|
temp[int(tag_id)] = tag_name
|
|
self.selected_tags = temp
|
|
|
|
def add_image(self, image, file_id, only_thumbs=False):
|
|
"""add single image to file/directory"""
|
|
imp = Img(image, self.image_path).save()
|
|
if imp:
|
|
# check if there is that image already
|
|
sql = """SELECT filename FROM images WHERE file_id=? and filename=?"""
|
|
self.db_cursor.execute(sql, (file_id, imp))
|
|
res = self.db_cursor.fetchone()
|
|
if res and res[0]:
|
|
# there is such an image. going back.
|
|
if __debug__:
|
|
print res[0]
|
|
return
|
|
|
|
# check if file have have thumbnail. if not, make it with first
|
|
# image
|
|
sql = """SELECT id FROM thumbnails WHERE file_id=?"""
|
|
self.db_cursor.execute(sql, (file_id,))
|
|
res = self.db_cursor.fetchone()
|
|
thumb = 1
|
|
if not(res and res[0]):
|
|
sql = """INSERT INTO thumbnails(filename, file_id) VALUES(?, ?)"""
|
|
self.db_cursor.execute(sql, (imp, file_id))
|
|
|
|
# insert picture into db
|
|
sql = """INSERT INTO images(file_id, filename)
|
|
VALUES(?, ?)"""
|
|
self.db_cursor.execute(sql, (file_id, imp))
|
|
self.db_connection.commit()
|
|
|
|
## check if file have have thumbnail. if not, make it with image
|
|
#sql = """SELECT id from thumbnails where file_id=?"""
|
|
#self.db_cursor.execute(sql, (file_id,))
|
|
#res = self.db_cursor.fetchone()
|
|
#if not res:
|
|
# sql = """insert into thumbnails(file_id, filename)
|
|
# values (?, ?)"""
|
|
# self.db_cursor.execute(sql, (file_id, thp))
|
|
# self.db_connection.commit()
|
|
#
|
|
self.db_connection.commit()
|
|
|
|
def del_images(self, file_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, (file_id,))
|
|
#res = self.db_cursor.fetchall()
|
|
#if len(res) > 0:
|
|
# for filen in res:
|
|
# if filen[0]:
|
|
# os.unlink(os.path.join(self.internal_dirname, filen[0]))
|
|
# os.unlink(os.path.join(self.internal_dirname, filen[1]))
|
|
|
|
# remove images records
|
|
sql = """DELETE FROM images WHERE file_id = ?"""
|
|
self.db_cursor.execute(sql, (file_id,))
|
|
self.db_connection.commit()
|
|
|
|
def save_image(self, image_id, file_path):
|
|
"""save image with specified id into file path (directory)"""
|
|
sql = """SELECT i.filename, f.filename FROM images i
|
|
LEFT JOIN files f on i.file_id=f.id
|
|
WHERE i.id=?"""
|
|
self.db_cursor.execute(sql, (image_id,))
|
|
res = self.db_cursor.fetchone()
|
|
if res and res[0]:
|
|
source = os.path.join(self.image_path, res[0])
|
|
count = 1
|
|
dest = os.path.join(file_path, res[1] + "_%04d." % count + 'jpg')
|
|
|
|
while os.path.exists(dest):
|
|
count += 1
|
|
dest = os.path.join(file_path, res[1] + "_%04d." %\
|
|
count + 'jpg')
|
|
if not os.path.exists(source):
|
|
return False
|
|
shutil.copy(source, dest)
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def delete_images_wth_thumbs(self, image_id):
|
|
"""removes image (without thumbnail) on specified image id"""
|
|
print "method removed"
|
|
#sql = """SELECT filename FROM images WHERE id=?"""
|
|
#self.db_cursor.execute(sql, (image_id,))
|
|
#res = self.db_cursor.fetchone()
|
|
#if res:
|
|
# if res[0]:
|
|
# os.unlink(os.path.join(self.internal_dirname, res[0]))
|
|
#
|
|
# if __debug__:
|
|
# print "m_main.py: delete_image(): removed images:"
|
|
# print res[0]
|
|
|
|
# remove images records
|
|
#sql = """UPDATE images set filename=NULL WHERE id = ?"""
|
|
#self.db_cursor.execute(sql, (image_id,))
|
|
#self.db_connection.commit()
|
|
|
|
def delete_all_images_wth_thumbs(self):
|
|
"""removes all images (without thumbnails) from collection"""
|
|
print "method removed"
|
|
#sql = """SELECT filename FROM images"""
|
|
#self.db_cursor.execute(sql)
|
|
#res = self.db_cursor.fetchall()
|
|
#for row in res:
|
|
# if row[0]:
|
|
# os.unlink(os.path.join(self.internal_dirname, row[0]))
|
|
# if __debug__:
|
|
# print "m_main.py: delete_all_images(): removed image:",
|
|
# print row[0]
|
|
|
|
# remove images records
|
|
#sql = """UPDATE images set filename=NULL"""
|
|
#self.db_cursor.execute(sql)
|
|
#self.db_connection.commit()
|
|
|
|
def delete_image(self, image_id):
|
|
"""removes image on specified image id"""
|
|
#sql = """SELECT filename, thumbnail FROM images WHERE id=?"""
|
|
#self.db_cursor.execute(sql, (image_id,))
|
|
#res = self.db_cursor.fetchone()
|
|
#if res:
|
|
# 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, (image_id,))
|
|
self.db_connection.commit()
|
|
|
|
def set_image_as_thumbnail(self, image_id):
|
|
"""set image as file thumbnail"""
|
|
sql = """SELECT file_id, filename FROM images WHERE id=?"""
|
|
self.db_cursor.execute(sql, (image_id,))
|
|
res = self.db_cursor.fetchone()
|
|
if res and res[0]:
|
|
sql = """DELETE FROM thumbnails WHERE file_id=?"""
|
|
self.db_cursor.execute(sql, (res[0],))
|
|
sql = """INSERT INTO thumbnails(file_id, filename) VALUES(?, ?)"""
|
|
self.db_cursor.execute(sql, (res[0], res[1]))
|
|
return True
|
|
return False
|
|
|
|
def delete_all_images(self):
|
|
"""removes all images from collection"""
|
|
# remove images records
|
|
sql = """DELETE FROM images"""
|
|
self.db_cursor.execute(sql)
|
|
self.db_connection.commit()
|
|
#try:
|
|
# shutil.rmtree(os.path.join(self.internal_dirname, 'images'))
|
|
#except:
|
|
# pass
|
|
|
|
def add_thumbnail(self, img_fn, file_id):
|
|
"""generate and add thumbnail to selected file/dir"""
|
|
if self.config.confd['thumbs']:
|
|
self.del_thumbnail(file_id)
|
|
im, exif = Thumbnail(img_fn, self.image_path).save()
|
|
|
|
sql = """INSERT INTO thumbnails(file_id, filename) values (?, ?)"""
|
|
self.db_cursor.execute(sql, (file_id, im))
|
|
self.db_connection.commit()
|
|
return True
|
|
return False
|
|
|
|
def del_thumbnail(self, file_id):
|
|
"""removes thumbnail from selected file/dir"""
|
|
# remove thumbnail files
|
|
#sql = """SELECT filename FROM thumbnails WHERE file_id=?"""
|
|
#self.db_cursor.execute(sql, (file_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, (file_id,))
|
|
self.db_connection.commit()
|
|
|
|
def del_all_thumbnail(self):
|
|
"""removes thumbnail from selected file/dir"""
|
|
# remove thumbs records
|
|
sql = """DELETE FROM thumbnails"""
|
|
self.db_cursor.execute(sql)
|
|
self.db_connection.commit()
|
|
#try:
|
|
# shutil.rmtree(os.path.join(self.internal_dirname, 'thumbnails'))
|
|
#except:
|
|
# pass
|
|
|
|
def cleanup(self):
|
|
"""remove temporary directory tree from filesystem"""
|
|
self.__close_db_connection()
|
|
try:
|
|
os.unlink(self.db_tmp_path)
|
|
except:
|
|
if __debug__:
|
|
print "Exception in removing temporary db file!"
|
|
pass
|
|
|
|
#if self.internal_dirname != None:
|
|
# try:
|
|
# shutil.rmtree(self.internal_dirname)
|
|
# except OSError:
|
|
# pass
|
|
return
|
|
|
|
def new(self):
|
|
"""create new project"""
|
|
self.unsaved_project = False
|
|
self.filename = None
|
|
self.__create_temporary_db_file()
|
|
self.__connect_to_db()
|
|
self.__create_database()
|
|
self.__clear_trees()
|
|
self.clear_search_tree()
|
|
self.tag_cloud = []
|
|
self.selected_tags = {}
|
|
return
|
|
|
|
def save(self, filename=None):
|
|
"""save tared directory at given catalog fielname"""
|
|
|
|
# flush all changes
|
|
self.db_connection.commit()
|
|
|
|
if not filename and not self.filename:
|
|
if __debug__:
|
|
return False, "no filename detected!"
|
|
return
|
|
|
|
if filename:
|
|
if not '.sqlite' in filename:
|
|
filename += '.sqlite'
|
|
else:
|
|
filename = filename[:filename.rindex('.sqlite')] + '.sqlite'
|
|
|
|
if self.config.confd['compress']:
|
|
filename += '.bz2'
|
|
|
|
self.filename = filename
|
|
val, err = self.__compress_and_save()
|
|
if not val:
|
|
self.filename = None
|
|
return val, err
|
|
|
|
def open(self, filename=None):
|
|
"""try to open db file"""
|
|
self.unsaved_project = False
|
|
self.__create_temporary_db_file()
|
|
self.filename = filename
|
|
self.tag_cloud = []
|
|
self.selected_tags = {}
|
|
self.clear_search_tree()
|
|
|
|
try:
|
|
test_file = open(filename).read(15)
|
|
except IOError:
|
|
self.filename = None
|
|
self.internal_dirname = None
|
|
return False
|
|
|
|
if test_file == "SQLite format 3":
|
|
db_tmp = open(self.db_tmp_path, "wb")
|
|
db_tmp.write(open(filename).read())
|
|
db_tmp.close()
|
|
elif test_file[0:10] == "BZh91AY&SY":
|
|
open_file = bz2.BZ2File(filename)
|
|
try:
|
|
curdb = open(self.db_tmp_path, "w")
|
|
curdb.write(open_file.read())
|
|
curdb.close()
|
|
open_file.close()
|
|
except IOError:
|
|
# file is not bz2
|
|
self.filename = None
|
|
self.internal_dirname = None
|
|
return False
|
|
else:
|
|
self.filename = None
|
|
self.internal_dirname = None
|
|
return False
|
|
#try:
|
|
# tar = tarfile.open(filename, "r:gz")
|
|
#except:
|
|
# try:
|
|
# tar = tarfile.open(filename, "r")
|
|
# except:
|
|
# self.filename = None
|
|
# self.internal_dirname = None
|
|
# return
|
|
#
|
|
#os.chdir(self.internal_dirname)
|
|
#try:
|
|
# tar.extractall()
|
|
# if __debug__:
|
|
# print "m_main.py: extracted tarfile into",
|
|
# print self.internal_dirname
|
|
#except AttributeError:
|
|
# # python 2.4 tarfile module lacks of method extractall()
|
|
# directories = []
|
|
# for tarinfo in tar:
|
|
# if tarinfo.isdir():
|
|
# # Extract directory with a safe mode, so that
|
|
# # all files below can be extracted as well.
|
|
# try:
|
|
# os.makedirs(os.path.join('.', tarinfo.name), 0700)
|
|
# except EnvironmentError:
|
|
# pass
|
|
# directories.append(tarinfo)
|
|
# else:
|
|
# tar.extract(tarinfo, '.')
|
|
#
|
|
# # Reverse sort directories.
|
|
# directories.sort(lambda a, b: cmp(a.name, b.name))
|
|
# directories.reverse()
|
|
#
|
|
# # Set correct owner, mtime and filemode on directories.
|
|
# for tarinfo in directories:
|
|
# try:
|
|
# os.chown(os.path.join('.', tarinfo.name),
|
|
# tarinfo.uid, tarinfo.gid)
|
|
# os.utime(os.path.join('.', tarinfo.name),
|
|
# (0, tarinfo.mtime))
|
|
# except OSError:
|
|
# if __debug__:
|
|
# print "m_main.py: open(): setting corrext owner,",
|
|
# print "mtime etc"
|
|
#tar.close()
|
|
|
|
self.__connect_to_db()
|
|
self.__fetch_db_into_treestore()
|
|
self.config.add_recent(filename)
|
|
self.get_tags()
|
|
return True
|
|
|
|
def scan(self, path, label, currentid):
|
|
"""scan files in separated thread"""
|
|
|
|
# flush buffer to release db lock.
|
|
self.db_connection.commit()
|
|
|
|
self.path = path
|
|
self.label = label
|
|
self.currentid = currentid
|
|
|
|
if self.busy:
|
|
return
|
|
self.thread = _threading.Thread(target=self.__scan)
|
|
self.thread.start()
|
|
return
|
|
|
|
def search(self, string):
|
|
"""Get all children down from sepcified root"""
|
|
self.clear_search_tree()
|
|
id_filter = None
|
|
sql_con = ""
|
|
found = 0
|
|
|
|
if len(string) > 0:
|
|
args = self.__postgresize(string)
|
|
args = args.split()
|
|
for arg in args:
|
|
arg = "%" + arg + "%"
|
|
sql_con += "AND (LOWER(filename) LIKE LOWER('%s')" % arg
|
|
sql_con += " ESCAPE '\\' "
|
|
sql_con += "OR LOWER(description) LIKE LOWER('%s')" % arg
|
|
sql_con += " ESCAPE '\\' ) "
|
|
|
|
# directories
|
|
if self.selected_tags:
|
|
# we have tags selected, live with that
|
|
id_filter = self.__filter2()
|
|
if id_filter != None:
|
|
if len(id_filter) == 1:
|
|
id_filter = "(%d)" % id_filter[0]
|
|
else:
|
|
id_filter = str(tuple(id_filter))
|
|
sql = """SELECT id, filename, size, date FROM files
|
|
WHERE parent_id!=id
|
|
AND parent_id!=1
|
|
AND type=1
|
|
AND id in """ + id_filter + sql_con + """
|
|
ORDER BY filename"""
|
|
|
|
else:
|
|
# alright, search throught all records
|
|
sql = """SELECT id, filename, size, date FROM files
|
|
WHERE parent_id!=id
|
|
AND parent_id!=1
|
|
AND type=1 """ + sql_con + """
|
|
ORDER BY filename"""
|
|
|
|
if sql:
|
|
self.db_cursor.execute(sql)
|
|
data = self.db_cursor.fetchall()
|
|
for row in data:
|
|
found += 1
|
|
myiter = self.search_list.insert_before(None, None)
|
|
self.search_list.set_value(myiter, 0, row[0])
|
|
self.search_list.set_value(myiter, 1,
|
|
self.__get_file_root(row[0]))
|
|
self.search_list.set_value(myiter, 2, row[1])
|
|
self.search_list.set_value(myiter, 3,
|
|
self.__get_file_path(row[0]))
|
|
self.search_list.set_value(myiter, 4, row[2])
|
|
self.search_list.set_value(myiter, 5,
|
|
datetime.fromtimestamp(row[3]))
|
|
self.search_list.set_value(myiter, 6, 1)
|
|
self.search_list.set_value(myiter, 7, gtk.STOCK_DIRECTORY)
|
|
|
|
# files and links
|
|
if self.selected_tags:
|
|
if id_filter:
|
|
# we have tags selected, live with that
|
|
sql = """SELECT f.id, f.filename, f.size, f.date, f.type
|
|
FROM files f
|
|
WHERE f.type!=1
|
|
AND parent_id!=1 AND id IN """ + id_filter + sql_con + """
|
|
ORDER BY f.filename"""
|
|
else:
|
|
# alright, search throught all records
|
|
sql = """SELECT f.id, f.filename, f.size, f.date, f.type
|
|
FROM files f
|
|
WHERE f.type!=1
|
|
AND parent_id!=1 """ + sql_con + """
|
|
ORDER BY f.filename"""
|
|
|
|
if sql:
|
|
self.db_cursor.execute(sql)
|
|
|
|
data = self.db_cursor.fetchall()
|
|
for row in data:
|
|
found += 1
|
|
myiter = self.search_list.insert_before(None, None)
|
|
self.search_list.set_value(myiter, 0, row[0])
|
|
self.search_list.set_value(myiter, 1,
|
|
self.__get_file_root(row[0]))
|
|
self.search_list.set_value(myiter, 2, row[1])
|
|
self.search_list.set_value(myiter, 3,
|
|
self.__get_file_path(row[0]))
|
|
self.search_list.set_value(myiter, 4, row[2])
|
|
self.search_list.set_value(myiter, 5,
|
|
datetime.fromtimestamp(row[3]))
|
|
self.search_list.set_value(myiter, 6, row[4])
|
|
if row[4] == self.FIL:
|
|
self.search_list.set_value(myiter, 7, gtk.STOCK_FILE)
|
|
elif row[4] == self.LIN:
|
|
self.search_list.set_value(myiter, 7, gtk.STOCK_INDEX)
|
|
|
|
return found
|
|
|
|
def rename(self, file_id, new_name=None):
|
|
"""change name of selected object id"""
|
|
if new_name:
|
|
# do it in DB
|
|
self.db_cursor.execute("update files set filename=? \
|
|
WHERE id=?", (new_name, file_id))
|
|
self.db_connection.commit()
|
|
|
|
for row in self.files_list:
|
|
if row[0] == file_id:
|
|
row[1] = new_name
|
|
break
|
|
|
|
def foreach_discs_tree(model, path, iterator, data):
|
|
if model.get_value(iterator, 0) == data[0]:
|
|
model.set_value(iterator, 1, data[1])
|
|
|
|
self.discs_tree.foreach(foreach_discs_tree, (file_id, new_name))
|
|
|
|
#self.__fetch_db_into_treestore()
|
|
self.unsaved_project = True
|
|
else:
|
|
if __debug__:
|
|
print "m_main.py: rename(): no label defined"
|
|
return
|
|
|
|
def refresh_discs_tree(self):
|
|
"""re-fetch discs tree"""
|
|
self.__fetch_db_into_treestore()
|
|
|
|
def get_root_entries(self, parent_id=None):
|
|
"""Get all children down from sepcified root"""
|
|
self.__clear_files_tree()
|
|
# if we are in "tag" mode, do the boogie
|
|
# directories first
|
|
if not parent_id and self.selected_tags:
|
|
# no parent_id, get all the tagged dirs
|
|
id_filter = self.__filter2()
|
|
if id_filter != None:
|
|
if len(id_filter) == 1:
|
|
id_filter = "(%d)" % id_filter[0]
|
|
else:
|
|
id_filter = str(tuple(id_filter))
|
|
sql = """SELECT id, filename, size, date FROM files
|
|
WHERE parent_id!=id AND type=1 AND id in """ + \
|
|
id_filter + """ ORDER BY filename"""
|
|
else:
|
|
# we have parent_id, get all the tagged dirs with parent_id
|
|
if not self.selected_tags:
|
|
sql = """SELECT id, filename, size, date FROM files
|
|
WHERE parent_id=? AND type=1
|
|
ORDER BY filename"""
|
|
else:
|
|
id_filter = self.__filter()
|
|
if id_filter != None:
|
|
sql = """SELECT id, filename, size, date FROM files
|
|
WHERE parent_id=? AND type=1 AND id in """ + \
|
|
str(tuple(id_filter)) + """ ORDER BY filename"""
|
|
else:
|
|
sql="""SELECT id, filename, size, date FROM files
|
|
WHERE 1=0"""
|
|
|
|
if not parent_id and self.selected_tags:
|
|
self.db_cursor.execute(sql)
|
|
else:
|
|
self.db_cursor.execute(sql, (parent_id,))
|
|
|
|
data = self.db_cursor.fetchall()
|
|
for row in data:
|
|
myiter = self.files_list.insert_before(None, None)
|
|
self.files_list.set_value(myiter, 0, row[0])
|
|
self.files_list.set_value(myiter, 1, self.__get_file_root(row[0]))
|
|
self.files_list.set_value(myiter, 2, row[1])
|
|
self.files_list.set_value(myiter, 3, self.__get_file_path(row[0]))
|
|
self.files_list.set_value(myiter, 4, row[2])
|
|
self.files_list.set_value(myiter, 5,
|
|
datetime.fromtimestamp(row[3]))
|
|
self.files_list.set_value(myiter, 6, 1)
|
|
self.files_list.set_value(myiter, 7, gtk.STOCK_DIRECTORY)
|
|
|
|
# all the rest
|
|
if not parent_id and self.selected_tags:
|
|
# no parent_id, get all the tagged files
|
|
if id_filter != None:
|
|
sql = """SELECT f.id, f.filename, f.size, f.date, f.type
|
|
FROM files f
|
|
WHERE f.type!=1 AND id IN """ + id_filter + \
|
|
""" ORDER BY f.filename"""
|
|
else:
|
|
# we have parent_id, get all the tagged files with parent_id
|
|
if not self.selected_tags:
|
|
sql = """SELECT f.id, f.filename, f.size, f.date, f.type
|
|
FROM files f
|
|
WHERE f.parent_id=? AND f.type!=1
|
|
ORDER BY f.filename"""
|
|
else:
|
|
if id_filter != None:
|
|
sql = """SELECT f.id, f.filename, f.size, f.date, f.type
|
|
FROM files f
|
|
WHERE f.parent_id=? AND f.type!=1 AND id IN """ + \
|
|
str(tuple(id_filter)) + """ ORDER BY f.filename"""
|
|
else:
|
|
sql="""SELECT f.id, f.filename, f.size, f.date, f.type
|
|
FROM files f
|
|
WHERE 1=0"""
|
|
|
|
if not parent_id and self.selected_tags:
|
|
self.db_cursor.execute(sql)
|
|
else:
|
|
self.db_cursor.execute(sql, (parent_id,))
|
|
|
|
data = self.db_cursor.fetchall()
|
|
for row in data:
|
|
myiter = self.files_list.insert_before(None, None)
|
|
self.files_list.set_value(myiter, 0, row[0])
|
|
self.files_list.set_value(myiter, 1, self.__get_file_root(row[0]))
|
|
self.files_list.set_value(myiter, 2, row[1])
|
|
self.files_list.set_value(myiter, 3, self.__get_file_path(row[0]))
|
|
self.files_list.set_value(myiter, 4, row[2])
|
|
self.files_list.set_value(myiter, 5,
|
|
datetime.fromtimestamp(row[3]))
|
|
self.files_list.set_value(myiter, 6, row[4])
|
|
if row[4] == self.FIL:
|
|
self.files_list.set_value(myiter, 7, gtk.STOCK_FILE)
|
|
elif row[4] == self.LIN:
|
|
self.files_list.set_value(myiter, 7, gtk.STOCK_INDEX)
|
|
return
|
|
|
|
def get_parent_id(self, child_id):
|
|
"""get root id from specified child"""
|
|
if child_id:
|
|
sql = """SELECT parent_id FROM files WHERE id=?"""
|
|
self.db_cursor.execute(sql, (child_id,))
|
|
res = self.db_cursor.fetchone()
|
|
if res:
|
|
return res[0]
|
|
return None
|
|
|
|
def get_file_info(self, file_id):
|
|
"""get file info from database"""
|
|
retval = {}
|
|
sql = """SELECT f.filename, f.date, f.size, f.type,
|
|
f.description, f.note, t.filename
|
|
FROM files f
|
|
LEFT JOIN thumbnails t on f.id = t.file_id
|
|
WHERE f.id = ?"""
|
|
self.db_cursor.execute(sql, (file_id,))
|
|
res = self.db_cursor.fetchone()
|
|
if res:
|
|
retval['fileinfo'] = {'id': file_id,
|
|
'date': datetime.fromtimestamp(res[1]),
|
|
'size': res[2], 'type': res[3]}
|
|
|
|
retval['fileinfo']['disc'] = self.__get_file_root(file_id)
|
|
|
|
retval['filename'] = res[0]
|
|
|
|
if res[4]:
|
|
retval['description'] = res[4]
|
|
|
|
if res[5]:
|
|
retval['note'] = res[5]
|
|
|
|
if res[6]:
|
|
thumbfile = os.path.join(self.image_path, res[6] + "_t")
|
|
if os.path.exists(thumbfile):
|
|
pix = gtk.gdk.pixbuf_new_from_file(thumbfile)
|
|
retval['thumbnail'] = thumbfile
|
|
|
|
sql = """SELECT id, filename FROM images
|
|
WHERE file_id = ?"""
|
|
self.db_cursor.execute(sql, (file_id,))
|
|
res = self.db_cursor.fetchall()
|
|
if res:
|
|
self.images_store = gtk.ListStore(gobject.TYPE_INT, gtk.gdk.Pixbuf)
|
|
for im_id, filename in res:
|
|
thumbfile = os.path.join(self.image_path, filename + "_t")
|
|
if os.path.exists(thumbfile):
|
|
pix = gtk.gdk.pixbuf_new_from_file(thumbfile)
|
|
else:
|
|
pix = gtk.gdk.pixbuf_new_from_inline(len(no_thumb_img),
|
|
no_thumb_img, False)
|
|
self.images_store.append([im_id, pix])
|
|
retval['images'] = True
|
|
|
|
sql = """SELECT camera, date, aperture, exposure_program,
|
|
exposure_bias, iso, focal_length, subject_distance, metering_mode,
|
|
flash, light_source, resolution, orientation
|
|
FROM exif
|
|
WHERE file_id = ?"""
|
|
self.db_cursor.execute(sql, (file_id,))
|
|
res = self.db_cursor.fetchone()
|
|
|
|
if res:
|
|
self.exif_list = gtk.ListStore(gobject.TYPE_STRING,
|
|
gobject.TYPE_STRING)
|
|
for key in self.EXIF_DICT:
|
|
myiter = self.exif_list.insert_before(None, None)
|
|
self.exif_list.set_value(myiter, 0, self.EXIF_DICT[key])
|
|
self.exif_list.set_value(myiter, 1, res[key])
|
|
retval['exif'] = True
|
|
|
|
# gthumb
|
|
sql = """SELECT note, place, date FROM gthumb WHERE file_id = ?"""
|
|
self.db_cursor.execute(sql, (file_id,))
|
|
res = self.db_cursor.fetchone()
|
|
|
|
if res:
|
|
retval['gthumb'] = {'note': res[0],
|
|
'place': res[1],
|
|
'date': res[2]}
|
|
|
|
return retval
|
|
|
|
def get_source(self, path):
|
|
"""get source of top level directory"""
|
|
bid = self.discs_tree.get_value(self.discs_tree.get_iter(path[0]), 0)
|
|
sql = """SELECT source FROM files WHERE id = ?"""
|
|
self.db_cursor.execute(sql,
|
|
(bid,))
|
|
res = self.db_cursor.fetchone()
|
|
if res == None:
|
|
return False
|
|
return int(res[0])
|
|
|
|
def get_label_and_filepath(self, path):
|
|
"""get source of top level directory"""
|
|
bid = self.discs_tree.get_value(self.discs_tree.get_iter(path), 0)
|
|
sql = """SELECT filepath, filename FROM files
|
|
WHERE id = ? AND parent_id = 1"""
|
|
self.db_cursor.execute(sql, (bid,))
|
|
res = self.db_cursor.fetchone()
|
|
if res == None:
|
|
return None, None
|
|
return res[0], res[1]
|
|
|
|
def delete(self, root_id, db_cursor=None, db_connection=None):
|
|
"""Remove subtree (item and its children) from main tree, remove tags
|
|
from database remove all possible data, like thumbnails, images, gthumb
|
|
info, exif etc"""
|
|
|
|
fids = []
|
|
|
|
if not db_cursor:
|
|
db_cursor = self.db_cursor
|
|
|
|
if not db_connection:
|
|
db_connection = self.db_connection
|
|
|
|
sql = """SELECT parent_id FROM files WHERE id = ?"""
|
|
db_cursor.execute(sql, (root_id,))
|
|
res = db_cursor.fetchone()
|
|
parent_id = res[0]
|
|
|
|
def get_children(fid):
|
|
"""get children of specified id"""
|
|
fids.append(fid)
|
|
sql = """SELECT id FROM files where parent_id = ?"""
|
|
db_cursor.execute(sql, (fid,))
|
|
res = db_cursor.fetchall()
|
|
if len(res)>0:
|
|
for i in res:
|
|
get_children(i[0])
|
|
|
|
get_children(root_id)
|
|
|
|
def generator():
|
|
"""simple generator for use in executemany() function"""
|
|
for field in fids:
|
|
yield (field,)
|
|
|
|
# remove files records
|
|
sql = """DELETE FROM files WHERE id = ?"""
|
|
db_cursor.executemany(sql, generator())
|
|
|
|
# remove tags records
|
|
sql = """DELETE FROM tags_files WHERE file_id = ?"""
|
|
db_cursor.executemany(sql, generator())
|
|
|
|
if __debug__:
|
|
print "m_main.py: delete(): deleting:", fids
|
|
|
|
if len(fids) == 1:
|
|
arg = "(%d)" % fids[0]
|
|
else:
|
|
arg = str(tuple(fids))
|
|
|
|
# remove thumbnails
|
|
#sql = """SELECT filename FROM thumbnails WHERE file_id IN %s""" % arg
|
|
#db_cursor.execute(sql)
|
|
#res = db_cursor.fetchall()
|
|
#if len(res) > 0:
|
|
# for row in res:
|
|
# os.unlink(os.path.join(self.image_path, row[0]))
|
|
|
|
# remove images
|
|
#sql = """SELECT filename, thumbnail FROM images
|
|
# WHERE file_id IN %s""" % arg
|
|
#db_cursor.execute(sql)
|
|
#res = db_cursor.fetchall()
|
|
#if len(res) > 0:
|
|
# for row in res:
|
|
# if row[0]:
|
|
# os.unlink(os.path.join(self.internal_dirname, row[0]))
|
|
# os.unlink(os.path.join(self.internal_dirname, row[1]))
|
|
|
|
# remove thumbs records
|
|
sql = """DELETE FROM thumbnails WHERE file_id = ?"""
|
|
db_cursor.executemany(sql, generator())
|
|
|
|
# remove images records
|
|
sql = """DELETE FROM images WHERE file_id = ?"""
|
|
db_cursor.executemany(sql, generator())
|
|
|
|
# remove gthumb info
|
|
sql = """DELETE FROM gthumb WHERE file_id = ?"""
|
|
db_cursor.executemany(sql, generator())
|
|
|
|
# correct parent direcotry sizes
|
|
# get size and parent of deleting object
|
|
while parent_id:
|
|
sql = """UPDATE files SET size =
|
|
(SELECT CASE WHEN
|
|
SUM(size) IS null
|
|
THEN
|
|
0
|
|
ELSE
|
|
SUM(size)
|
|
END
|
|
FROM files WHERE parent_id=?)
|
|
WHERE id=?"""
|
|
db_cursor.execute(sql, (parent_id, parent_id))
|
|
|
|
sql = """SELECT parent_id FROM files
|
|
WHERE id = ? AND parent_id!=id"""
|
|
db_cursor.execute(sql, (parent_id,))
|
|
res = db_cursor.fetchone()
|
|
if res:
|
|
parent_id = res[0]
|
|
else:
|
|
parent_id = False
|
|
|
|
db_connection.commit()
|
|
|
|
# part two: remove items from treestore/liststores
|
|
def foreach_treestore(model, path, iterator, d):
|
|
if d[0] == model.get_value(iterator, 0):
|
|
d[1].append(path)
|
|
return False
|
|
|
|
paths = []
|
|
self.discs_tree.foreach(foreach_treestore, (root_id, paths))
|
|
for path in paths:
|
|
self.discs_tree.remove(self.discs_tree.get_iter(path))
|
|
|
|
paths = []
|
|
self.files_list.foreach(foreach_treestore, (root_id, paths))
|
|
for path in paths:
|
|
self.files_list.remove(self.files_list.get_iter(path))
|
|
|
|
paths = []
|
|
self.search_list.foreach(foreach_treestore, (root_id, paths))
|
|
for path in paths:
|
|
self.search_list.remove(self.search_list.get_iter(path))
|
|
return
|
|
|
|
def get_stats(self, selected_id):
|
|
"""get statistic information"""
|
|
retval = {}
|
|
if selected_id:
|
|
sql = """SELECT id, type, parent_id FROM files WHERE id=?"""
|
|
self.db_cursor.execute(sql, (selected_id,))
|
|
res = self.db_cursor.fetchone()
|
|
if not res:
|
|
return retval
|
|
|
|
selected_item = {'id':res[0], 'type':res[1], 'parent': res[2]}
|
|
|
|
# collect all parent_id's
|
|
parents = []
|
|
|
|
def _recurse(fid):
|
|
"""recursive gather direcotories ids and store it in list"""
|
|
parents.append(fid)
|
|
sql = """SELECT id FROM files
|
|
WHERE type=? AND parent_id=? AND parent_id!=1"""
|
|
self.db_cursor.execute(sql, (self.DIR, fid))
|
|
res = self.db_cursor.fetchall()
|
|
if res:
|
|
for row in res:
|
|
_recurse(row[0])
|
|
_recurse(selected_id)
|
|
|
|
if selected_item['parent'] == 1:
|
|
parents.pop(0)
|
|
retval['discs'] = 1
|
|
retval['dirs'] = len(parents)
|
|
|
|
parents.append(selected_id)
|
|
|
|
files_count = 0
|
|
|
|
for parent in parents:
|
|
sql = """SELECT count(id) FROM files
|
|
WHERE type!=0 AND type!=1 AND parent_id=?"""
|
|
self.db_cursor.execute(sql, (parent,))
|
|
res = self.db_cursor.fetchone()
|
|
if res:
|
|
files_count += res[0]
|
|
retval['files'] = files_count
|
|
sql = """SELECT size FROM files WHERE id=?"""
|
|
self.db_cursor.execute(sql, (selected_id,))
|
|
res = self.db_cursor.fetchone()
|
|
if res:
|
|
retval['size'] = self.__bytes_to_human(res[0])
|
|
else:
|
|
sql = """SELECT count(id) FROM files
|
|
WHERE parent_id=1 AND type=1"""
|
|
self.db_cursor.execute(sql)
|
|
res = self.db_cursor.fetchone()
|
|
if res:
|
|
retval['discs'] = res[0]
|
|
|
|
sql = """SELECT count(id) FROM files
|
|
WHERE parent_id!=1 AND type=1"""
|
|
self.db_cursor.execute(sql)
|
|
res = self.db_cursor.fetchone()
|
|
if res:
|
|
retval['dirs'] = res[0]
|
|
|
|
sql = """SELECT count(id) FROM files
|
|
WHERE parent_id!=1 AND type!=1"""
|
|
self.db_cursor.execute(sql)
|
|
res = self.db_cursor.fetchone()
|
|
if res:
|
|
retval['files'] = res[0]
|
|
|
|
sql = """SELECT sum(size) FROM files
|
|
WHERE parent_id=1 AND type=1"""
|
|
self.db_cursor.execute(sql)
|
|
res = self.db_cursor.fetchone()
|
|
if res:
|
|
retval['size'] = self.__bytes_to_human(res[0])
|
|
return retval
|
|
|
|
def get_image_path(self, img_id):
|
|
"""return image location"""
|
|
sql = """SELECT filename FROM images WHERE id=?"""
|
|
self.db_cursor.execute(sql, (img_id,))
|
|
res = self.db_cursor.fetchone()
|
|
if res and res[0]:
|
|
path = os.path.join(self.image_path, res[0])
|
|
if os.path.exists(path):
|
|
return path
|
|
return None
|
|
|
|
def update_desc_and_note(self, file_id, desc='', note=''):
|
|
"""update note and description"""
|
|
sql = """UPDATE files SET description=?, note=? WHERE id=?"""
|
|
self.db_cursor.execute(sql, (desc, note, file_id))
|
|
self.db_connection.commit()
|
|
return
|
|
|
|
def clear_search_tree(self):
|
|
"""try to clear store for search"""
|
|
try:
|
|
self.search_list.clear()
|
|
except:
|
|
pass
|
|
|
|
# private class functions
|
|
def __fill_history_model(self):
|
|
"""fill search history model with config dict"""
|
|
try:
|
|
self.search_history.clear()
|
|
except:
|
|
pass
|
|
|
|
for entry in self.config.search_history:
|
|
myiter = self.search_history.insert_before(None, None)
|
|
self.search_history.set_value(myiter, 0, entry)
|
|
return
|
|
|
|
def __get_file_root(self, file_id):
|
|
"""return string with root (disc name) of selected banch (file_id)"""
|
|
sql = """SELECT parent_id FROM files WHERE id=? and parent_id!=1"""
|
|
self.db_cursor.execute(sql, (file_id,))
|
|
res = self.db_cursor.fetchone()
|
|
|
|
root_id = None
|
|
while res:
|
|
root_id = res[0]
|
|
self.db_cursor.execute(sql, (res[0],))
|
|
res = self.db_cursor.fetchone()
|
|
|
|
sql = """SELECT filename FROM files WHERE id=?"""
|
|
self.db_cursor.execute(sql, (root_id,))
|
|
res = self.db_cursor.fetchone()
|
|
|
|
if res:
|
|
return res[0]
|
|
else:
|
|
return None
|
|
|
|
def __get_file_path(self, file_id):
|
|
"""return string with path from the root of the disc"""
|
|
#SQL: get parent id and filename to concatenate path
|
|
path = ""
|
|
sql = """SELECT parent_id FROM files WHERE id=? AND parent_id!=1"""
|
|
self.db_cursor.execute(sql, (file_id,))
|
|
res = self.db_cursor.fetchone()
|
|
if not res:
|
|
return "/"
|
|
|
|
while res:
|
|
sql = """SELECT id, filename FROM files
|
|
WHERE id=? AND parent_id!=1"""
|
|
self.db_cursor.execute(sql, (res[0],))
|
|
res = self.db_cursor.fetchone()
|
|
if res:
|
|
path = res[1] + "/" + path
|
|
sql = """SELECT parent_id FROM files
|
|
WHERE id=? AND id!=parent_id"""
|
|
self.db_cursor.execute(sql, (res[0],))
|
|
res = self.db_cursor.fetchone()
|
|
|
|
return "/" + path
|
|
|
|
def __bytes_to_human(self, integer):
|
|
"""return integer digit in human readable string representation"""
|
|
if integer <= 0 or integer < 1024:
|
|
return "%d bytes" % integer
|
|
|
|
## convert integer into string with thousands' separator
|
|
#for i in range(len(str(integer))/3+1):
|
|
# if i == 0:
|
|
# s_int = str(integer)[-3:]
|
|
# else:
|
|
# s_int = str(integer)[-(3*int(i)+3):-(3*int(i))] + " " + s_int
|
|
power = None
|
|
temp = integer
|
|
for power in ['kB', 'MB', 'GB', 'TB']:
|
|
temp = temp /1024.0
|
|
if temp < 1 or temp < 1024:
|
|
break
|
|
return "%0.2f %s (%d bytes)" % (temp, power, integer)
|
|
|
|
def __clear_trees(self):
|
|
"""clears treemodel and treestore of files and discs tree"""
|
|
self.__clear_files_tree()
|
|
self.__clear_discs_tree()
|
|
self.clear_search_tree()
|
|
|
|
def __clear_discs_tree(self):
|
|
"""try to clear model for discs"""
|
|
try:
|
|
self.discs_tree.clear()
|
|
except:
|
|
pass
|
|
|
|
def __clear_files_tree(self):
|
|
"""try to clear store for files/directories"""
|
|
try:
|
|
self.files_list.clear()
|
|
except:
|
|
pass
|
|
|
|
def __connect_to_db(self):
|
|
"""initialize db connection and store it in class attributes"""
|
|
self.db_connection = sqlite.connect(self.db_tmp_path,
|
|
detect_types=sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES)
|
|
self.db_cursor = self.db_connection.cursor()
|
|
return
|
|
|
|
def __close_db_connection(self):
|
|
"""close db conection"""
|
|
|
|
if self.db_cursor != None:
|
|
self.db_cursor.close()
|
|
self.db_cursor = None
|
|
if self.db_connection != None:
|
|
self.db_connection.close()
|
|
self.db_connection = None
|
|
return
|
|
|
|
def __create_temporary_db_file(self):
|
|
"""create temporary db file"""
|
|
self.cleanup()
|
|
self.db_tmp_path = mkstemp()[1]
|
|
return
|
|
|
|
def __compress_and_save(self):
|
|
"""create (and optionaly compress) tar archive from working directory
|
|
and write it to specified file"""
|
|
|
|
# flush all changes
|
|
self.db_connection.commit()
|
|
|
|
try:
|
|
if self.config.confd['compress']:
|
|
output_file = bz2.BZ2File(self.filename, "w")
|
|
else:
|
|
output_file = open(self.filename, "w")
|
|
if __debug__:
|
|
print "m_main.py: __compress_and_save(): tar open successed"
|
|
|
|
except IOError, (errno, strerror):
|
|
return False, strerror
|
|
|
|
dbpath = open(self.db_tmp_path)
|
|
output_file.write(dbpath.read())
|
|
dbpath.close()
|
|
output_file.close()
|
|
|
|
self.unsaved_project = False
|
|
return True, None
|
|
|
|
def __create_database(self):
|
|
"""make all necessary tables in db file
|
|
|
|
|
|
,------------. ,------------.
|
|
|files | |tags |
|
|
+------------+ +------------+
|
|
|→|pk id | |pk id |
|
|
|_|fk parent_id| |fk group_id |
|
|
|filename | |tag |
|
|
|filepath | +------------+
|
|
|date |
|
|
|size | ,------------
|
|
|source | |tags_files
|
|
|note | |
|
|
|description | |
|
|
+------------+ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
self.db_cursor.execute("""create table
|
|
files(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
parent_id INTEGER,
|
|
filename TEXT,
|
|
filepath TEXT,
|
|
date datetime,
|
|
size INTEGER,
|
|
type INTEGER,
|
|
source INTEGER,
|
|
note TEXT,
|
|
description TEXT);""")
|
|
self.db_cursor.execute("""create table
|
|
tags(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
group_id INTEGER,
|
|
tag TEXT);""")
|
|
self.db_cursor.execute("""create table
|
|
tags_files(file_id INTEGER,
|
|
tag_id INTEGER);""")
|
|
self.db_cursor.execute("""create table
|
|
groups(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT,
|
|
color TEXT);""")
|
|
self.db_cursor.execute("""create table
|
|
thumbnails(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
file_id INTEGER,
|
|
filename TEXT);""")
|
|
self.db_cursor.execute("""create table
|
|
images(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
file_id INTEGER,
|
|
filename TEXT);""")
|
|
self.db_cursor.execute("""create table
|
|
exif(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
file_id INTEGER,
|
|
camera TEXT,
|
|
date TEXT,
|
|
aperture TEXT,
|
|
exposure_program TEXT,
|
|
exposure_bias TEXT,
|
|
iso TEXT,
|
|
focal_length TEXT,
|
|
subject_distance TEXT,
|
|
metering_mode TEXT,
|
|
flash TEXT,
|
|
light_source TEXT,
|
|
resolution TEXT,
|
|
orientation TEXT);""")
|
|
self.db_cursor.execute("""create table
|
|
gthumb(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
file_id INTEGER,
|
|
note TEXT,
|
|
place TEXT,
|
|
date datetime);""")
|
|
sql = """INSERT INTO files
|
|
VALUES(1, 1, 'root', null, 0, 0, 0, 0, null, null)"""
|
|
self.db_cursor.execute(sql)
|
|
sql = """INSERT INTO groups VALUES(1, 'default', 'black')"""
|
|
self.db_cursor.execute(sql)
|
|
self.db_connection.commit()
|
|
|
|
def __filter(self):
|
|
"""return list of ids of files (AND their parent, even if they have no
|
|
assigned tags) that corresponds to tags"""
|
|
|
|
filtered_ids = []
|
|
count = 0
|
|
for tid in self.selected_tags:
|
|
temp1 = []
|
|
sql = """SELECT file_id
|
|
FROM tags_files
|
|
WHERE tag_id=? """
|
|
self.db_cursor.execute(sql, (tid, ))
|
|
data = self.db_cursor.fetchall()
|
|
for row in data:
|
|
temp1.append(row[0])
|
|
|
|
if count > 0:
|
|
filtered_ids = list(set(filtered_ids).intersection(temp1))
|
|
else:
|
|
filtered_ids = temp1
|
|
count += 1
|
|
|
|
parents = []
|
|
for i in filtered_ids:
|
|
sql = """SELECT parent_id
|
|
FROM files
|
|
WHERE id = ?"""
|
|
self.db_cursor.execute(sql, (i, ))
|
|
data = self.db_cursor.fetchone()
|
|
if data:
|
|
parents.append(data[0])
|
|
while True:
|
|
sql = """SELECT parent_id
|
|
FROM files
|
|
WHERE id = ? and id!=parent_id"""
|
|
self.db_cursor.execute(sql, (data[0], ))
|
|
data = self.db_cursor.fetchone()
|
|
if not data:
|
|
break
|
|
else:
|
|
parents.append(data[0])
|
|
|
|
return list(set(parents).union(filtered_ids))
|
|
|
|
def __filter2(self):
|
|
"""return list of ids of files (WITHOUT their parent) that
|
|
corresponds to tags"""
|
|
|
|
filtered_ids = []
|
|
count = 0
|
|
for tid in self.selected_tags:
|
|
temp1 = []
|
|
sql = """SELECT file_id
|
|
FROM tags_files
|
|
WHERE tag_id=? """
|
|
self.db_cursor.execute(sql, (tid, ))
|
|
data = self.db_cursor.fetchall()
|
|
for row in data:
|
|
temp1.append(row[0])
|
|
|
|
if count > 0:
|
|
filtered_ids = list(set(filtered_ids).intersection(temp1))
|
|
else:
|
|
filtered_ids = temp1
|
|
count += 1
|
|
|
|
return filtered_ids
|
|
|
|
def __scan(self):
|
|
"""scan content of the given path"""
|
|
self.busy = True
|
|
|
|
# new conection for this task, because it's running in separate thread
|
|
db_connection = sqlite.connect(self.db_tmp_path,
|
|
detect_types=sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES,
|
|
isolation_level="EXCLUSIVE")
|
|
db_cursor = db_connection.cursor()
|
|
|
|
timestamp = datetime.now()
|
|
|
|
# count files in directory tree
|
|
count = 0
|
|
self.statusmsg = "Calculating number of files in directory tree..."
|
|
|
|
count = 0
|
|
try:
|
|
for root, dirs, files in os.walk(self.path):
|
|
count += len(files)
|
|
except:
|
|
if __debug__:
|
|
print 'm_main.py: os.walk in %s' % self.path
|
|
pass
|
|
|
|
if count > 0:
|
|
step = 1.0/count
|
|
else:
|
|
step = 1.0
|
|
|
|
self.count = 0
|
|
|
|
# guess filesystem encoding
|
|
self.fsenc = sys.getfilesystemencoding()
|
|
|
|
self.fresh_disk_iter = None
|
|
|
|
def __recurse(parent_id, name, path, date, size, filetype,
|
|
discs_tree_iter=None):
|
|
"""recursive scans given path"""
|
|
if self.abort:
|
|
return -1
|
|
|
|
_size = size
|
|
|
|
myit = self.discs_tree.append(discs_tree_iter, None)
|
|
|
|
if parent_id == 1:
|
|
self.fresh_disk_iter = myit
|
|
self.discs_tree.set_value(myit, 2, gtk.STOCK_CDROM)
|
|
sql = """INSERT INTO
|
|
files(parent_id, filename, filepath, date,
|
|
size, type, source)
|
|
VALUES(?,?,?,?,?,?,?)"""
|
|
db_cursor.execute(sql, (parent_id, name, path, date, size,
|
|
filetype, self.source))
|
|
else:
|
|
self.discs_tree.set_value(myit, 2, gtk.STOCK_DIRECTORY)
|
|
sql = """INSERT INTO
|
|
files(parent_id, filename, filepath, date, size, type)
|
|
VALUES(?,?,?,?,?,?)"""
|
|
db_cursor.execute(sql, (parent_id, name, path,
|
|
date, size, filetype))
|
|
|
|
sql = """SELECT seq FROM sqlite_sequence WHERE name='files'"""
|
|
db_cursor.execute(sql)
|
|
currentid = db_cursor.fetchone()[0]
|
|
|
|
self.discs_tree.set_value(myit, 0, currentid)
|
|
self.discs_tree.set_value(myit, 1, name)
|
|
self.discs_tree.set_value(myit, 3, parent_id)
|
|
|
|
try:
|
|
root, dirs, files = os.walk(path).next()
|
|
except:
|
|
if __debug__:
|
|
print "m_main.py: cannot access ", path
|
|
#return -1
|
|
return 0
|
|
|
|
#############
|
|
# directories
|
|
for i in dirs:
|
|
j = self.__decode_filename(i)
|
|
current_dir = os.path.join(root, i)
|
|
|
|
try:
|
|
st = os.stat(current_dir)
|
|
st_mtime = st.st_mtime
|
|
except OSError:
|
|
st_mtime = 0
|
|
|
|
# do NOT follow symbolic links
|
|
if os.path.islink(current_dir):
|
|
l = self.__decode_filename(os.readlink(current_dir))
|
|
|
|
sql = """INSERT INTO
|
|
files(parent_id, filename, filepath, date, size, type)
|
|
VALUES(?,?,?,?,?,?)"""
|
|
db_cursor.execute(sql, (currentid, j + " -> " + l,
|
|
current_dir, st_mtime, 0,
|
|
self.LIN))
|
|
dirsize = 0
|
|
else:
|
|
dirsize = __recurse(currentid, j, current_dir,
|
|
st_mtime, 0, self.DIR, myit)
|
|
|
|
if dirsize == -1:
|
|
break
|
|
else:
|
|
_size = _size + dirsize
|
|
|
|
########
|
|
# files:
|
|
for i in files:
|
|
if self.abort:
|
|
break
|
|
|
|
self.count = self.count + 1
|
|
current_file = os.path.join(root, i)
|
|
|
|
try:
|
|
st = os.stat(current_file)
|
|
st_mtime = st.st_mtime
|
|
st_size = st.st_size
|
|
except OSError:
|
|
st_mtime = 0
|
|
st_size = 0
|
|
|
|
_size = _size + st_size
|
|
j = self.__decode_filename(i)
|
|
|
|
# do NOT follow symbolic links
|
|
if os.path.islink(current_file):
|
|
l = self.__decode_filename(os.readlink(current_file))
|
|
sql = """INSERT INTO
|
|
files(parent_id, filename, filepath, date, size, type)
|
|
VALUES(?,?,?,?,?,?)"""
|
|
db_cursor.execute(sql, (currentid, j + " -> " + l,
|
|
current_file, st_mtime, 0,
|
|
self.LIN))
|
|
else:
|
|
sql = """INSERT INTO
|
|
files(parent_id, filename, filepath, date, size, type)
|
|
VALUES(?,?,?,?,?,?)"""
|
|
db_cursor.execute(sql, (currentid, j, current_file,
|
|
st_mtime, st_size, self.FIL))
|
|
|
|
if self.count % 32 == 0:
|
|
update = True
|
|
else:
|
|
update = False
|
|
|
|
###########################
|
|
# fetch details about files
|
|
if self.config.confd['retrive']:
|
|
update = True
|
|
exif = None
|
|
|
|
sql = """SELECT seq FROM sqlite_sequence
|
|
WHERE name='files'"""
|
|
db_cursor.execute(sql)
|
|
fileid = db_cursor.fetchone()[0]
|
|
|
|
ext = i.split('.')[-1].lower()
|
|
|
|
# Video
|
|
if ext in self.MOV:
|
|
#import rpdb2; rpdb2.start_embedded_debugger('pass')
|
|
v = Video(current_file)
|
|
cfn = v.capture()
|
|
img = Img(cfn, self.image_path)
|
|
th = img.save()
|
|
if th:
|
|
sql = """INSERT INTO
|
|
thumbnails(file_id, filename)
|
|
VALUES(?, ?)"""
|
|
db_cursor.execute(sql, (fileid, th+"_t"))
|
|
sql = """INSERT INTO images(file_id, filename)
|
|
VALUES(?, ?)"""
|
|
db_cursor.execute(sql, (fileid, th))
|
|
os.unlink(cfn)
|
|
|
|
# Images - thumbnails and exif data
|
|
if self.config.confd['thumbs'] and ext in self.IMG:
|
|
thumb = Thumbnail(current_file, self.image_path)
|
|
th, exif = thumb.save()
|
|
if th:
|
|
sql = """INSERT INTO
|
|
thumbnails(file_id, filename)
|
|
VALUES(?, ?)"""
|
|
db_cursor.execute(sql, (fileid, th))
|
|
|
|
# exif - store data in exif table
|
|
jpg = ['jpg', 'jpeg']
|
|
if self.config.confd['exif'] and ext in jpg:
|
|
p = None
|
|
if self.config.confd['thumbs'] and exif:
|
|
p = ParseExif(exif_dict=exif)
|
|
else:
|
|
p = ParseExif(exif_file=current_file)
|
|
if not p.exif_dict:
|
|
p = None
|
|
if p:
|
|
p = p.parse()
|
|
p = list(p)
|
|
p.insert(0, fileid)
|
|
sql = """INSERT INTO exif (file_id,
|
|
camera,
|
|
date,
|
|
aperture,
|
|
exposure_program,
|
|
exposure_bias,
|
|
iso,
|
|
focal_length,
|
|
subject_distance,
|
|
metering_mode,
|
|
flash,
|
|
light_source,
|
|
resolution,
|
|
orientation)
|
|
values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)"""
|
|
db_cursor.execute(sql, (tuple(p)))
|
|
|
|
# gthumb - save comments from gThumb program
|
|
if self.config.confd['gthumb']:
|
|
gt = GthumbCommentParser(root, i)
|
|
cmnts = gt.parse()
|
|
if cmnts:
|
|
sql = """insert into gthumb(file_id,
|
|
note,
|
|
place,
|
|
date)
|
|
values(?,?,?,?)"""
|
|
db_cursor.execute(sql, (fileid,
|
|
cmnts['note'],
|
|
cmnts['place'],
|
|
cmnts['date']))
|
|
if 'keywords' in cmnts:
|
|
# TODO: add gthumb keywords to tags
|
|
pass
|
|
|
|
# Extensions - user defined actions
|
|
if ext in self.config.confd['extensions'].keys():
|
|
cmd = self.config.confd['extensions'][ext]
|
|
arg = current_file.replace('"', '\\"')
|
|
output = os.popen(cmd % arg).readlines()
|
|
desc = ''
|
|
for line in output:
|
|
desc += line
|
|
|
|
sql = """UPDATE files SET description=?
|
|
WHERE id=?"""
|
|
db_cursor.execute(sql, (desc, fileid))
|
|
|
|
### end of scan
|
|
if update:
|
|
self.statusmsg = "Scannig: %s" % current_file
|
|
self.progress = step * self.count
|
|
|
|
sql = """UPDATE files SET size=? WHERE id=?"""
|
|
db_cursor.execute(sql, (_size, currentid))
|
|
if self.abort:
|
|
return -1
|
|
else:
|
|
return _size
|
|
|
|
if __recurse(1, self.label, self.path, 0, 0, self.DIR) == -1:
|
|
if __debug__:
|
|
print "m_main.py: __scan() __recurse()",
|
|
print "interrupted self.abort = True"
|
|
self.discs_tree.remove(self.fresh_disk_iter)
|
|
db_cursor.close()
|
|
db_connection.rollback()
|
|
else:
|
|
if __debug__:
|
|
print "m_main.py: __scan() __recurse() goes without interrupt"
|
|
if self.currentid:
|
|
if __debug__:
|
|
print "m_main.py: __scan() removing old branch"
|
|
self.statusmsg = "Removing old branch..."
|
|
self.delete(self.currentid, db_cursor, db_connection)
|
|
|
|
self.currentid = None
|
|
|
|
db_cursor.close()
|
|
db_connection.commit()
|
|
db_connection.close()
|
|
if __debug__:
|
|
print "m_main.py: __scan() time: ", (datetime.now() - timestamp)
|
|
|
|
self.busy = False
|
|
|
|
# refresh discs tree
|
|
self.__fetch_db_into_treestore()
|
|
self.statusmsg = "Idle"
|
|
self.progress = 0
|
|
self.abort = False
|
|
|
|
def __fetch_db_into_treestore(self):
|
|
"""load data from DB to tree model"""
|
|
# cleanup treeStore
|
|
self.__clear_discs_tree()
|
|
|
|
#connect
|
|
detect_types = sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES
|
|
db_connection = sqlite.connect(self.db_tmp_path,
|
|
detect_types = detect_types)
|
|
db_cursor = db_connection.cursor()
|
|
|
|
# fetch all the directories
|
|
if not self.selected_tags:
|
|
sql = """SELECT id, parent_id, filename FROM files
|
|
WHERE type=1 ORDER BY parent_id, filename"""
|
|
else:
|
|
id_filter = self.__filter()
|
|
if id_filter != None:
|
|
sql = """SELECT id, parent_id, filename FROM files
|
|
WHERE type=1 and id in """ + str(tuple(id_filter)) \
|
|
+ """ ORDER BY parent_id, filename"""
|
|
else:
|
|
sql="""SELECT id, parent_id, filename FROM files
|
|
WHERE 1=0"""
|
|
db_cursor.execute(sql)
|
|
data = db_cursor.fetchall()
|
|
|
|
def get_children(parent_id = 1, iterator = None):
|
|
"""fetch all children and place them in model"""
|
|
for row in data:
|
|
if row[1] == parent_id:
|
|
myiter = self.discs_tree.insert_before(iterator, None)
|
|
self.discs_tree.set_value(myiter, 0, row[0]) # id
|
|
self.discs_tree.set_value(myiter, 1, row[2]) # name
|
|
self.discs_tree.set_value(myiter, 3, row[1]) # parent_id
|
|
get_children(row[0], myiter)
|
|
|
|
# isroot?
|
|
if iterator == None:
|
|
self.discs_tree.set_value(myiter, 2, gtk.STOCK_CDROM)
|
|
else:
|
|
self.discs_tree.set_value(myiter, 2,
|
|
gtk.STOCK_DIRECTORY)
|
|
return
|
|
|
|
if __debug__:
|
|
start_date = datetime.now()
|
|
# launch scanning.
|
|
get_children()
|
|
if __debug__:
|
|
print "m_main.py: __fetch_db_into_treestore()",
|
|
print "tree generation time: ", (datetime.now() - start_date)
|
|
db_connection.close()
|
|
return
|
|
|
|
def __append_added_volume(self):
|
|
"""append branch from DB to existing tree model"""
|
|
#connect
|
|
detect_types = sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES
|
|
db_connection = sqlite.connect(self.db_tmp_path,
|
|
detect_types = detect_types)
|
|
db_cursor = db_connection.cursor()
|
|
|
|
sql = """SELECT id, parent_id, filename FROM files
|
|
WHERE type=1 ORDER BY parent_id, filename"""
|
|
db_cursor.execute(sql)
|
|
data = db_cursor.fetchall()
|
|
|
|
def get_children(parent_id = 1, iterator = None):
|
|
"""fetch all children and place them in model"""
|
|
for row in data:
|
|
if row[1] == parent_id:
|
|
myiter = self.discs_tree.insert_before(iterator, None)
|
|
self.discs_tree.set_value(myiter, 0, row[0])
|
|
self.discs_tree.set_value(myiter, 1, row[2])
|
|
self.discs_tree.set_value(myiter, 3, row[1])
|
|
get_children(row[0], myiter)
|
|
|
|
# isroot?
|
|
if iterator == None:
|
|
self.discs_tree.set_value(myiter, 2, gtk.STOCK_CDROM)
|
|
else:
|
|
self.discs_tree.set_value(myiter, 2,
|
|
gtk.STOCK_DIRECTORY)
|
|
return
|
|
|
|
if __debug__:
|
|
start_date = datetime.now()
|
|
# launch scanning.
|
|
get_children()
|
|
if __debug__:
|
|
print "m_main.py: __append_added_volume() tree generation time: ",
|
|
print datetime.now() - start_date
|
|
db_connection.close()
|
|
return
|
|
|
|
def __decode_filename(self, txt):
|
|
"""decode filename with encoding taken form ENV, returns unicode
|
|
string"""
|
|
if self.fsenc:
|
|
return txt.decode(self.fsenc)
|
|
else:
|
|
return txt
|
|
|
|
def __postgresize(self, string):
|
|
"""escape sql characters, return escaped string"""
|
|
name = string.replace("\\","\\\\")
|
|
name = name.replace('%','\%')
|
|
name = name.replace('_','\_')
|
|
name = name.replace("'","''")
|
|
|
|
# special characters ? and * convert to sql sepcial characters _ and %
|
|
#name = name.replace('*','%')
|
|
#name = name.replace('?','_')
|
|
|
|
return name
|
|
|