diff --git a/README b/README
index ea1f820..12ffc97 100644
--- a/README
+++ b/README
@@ -60,13 +60,14 @@ For version 1.0 following aims have to be done:
- file details:
- files properties
x thumbnail
- - description
- - file information (date, size, etc) (50%)
+ x description
- exif information
- keywords (tags)
+ - gthumb integration
- adding images (60% done)
x generating/saving thumbnails
x moving hardcoded files extensions into config
+x statistics
Legend: [-] not done, [x] done.
@@ -74,7 +75,6 @@ For version 2.0:
- Icon grid in files view
- command line support: query, adding media to collection etc
- internationalization support
-- statistics
Removed:
- filetypes handling (movies, images, archives, documents etc). Now it have
@@ -92,7 +92,7 @@ Removed:
- anidb link/imdb link
Maybe in future versions. Now text file descriptions and tags have to be
enough for good and fast information search.
-
+- file information (date, size, etc) (50%) (no need for?)
NOTES
=====
diff --git a/resources/glade/config.glade b/resources/glade/config.glade
index c08eadd..21e7f0c 100644
--- a/resources/glade/config.glade
+++ b/resources/glade/config.glade
@@ -259,12 +259,14 @@
True
True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
Compress collection
+ True
0
True
+ False
+ False
3
diff --git a/resources/glade/dialogs.glade b/resources/glade/dialogs.glade
index d570f03..1966cb1 100644
--- a/resources/glade/dialogs.glade
+++ b/resources/glade/dialogs.glade
@@ -1,373 +1,398 @@
-
-
-
+
+
+
-
-
- True
- Disk label - pyGTKtalog
- GTK_WINDOW_TOPLEVEL
- GTK_WIN_POS_NONE
- False
- True
- False
- True
- False
- False
- GDK_WINDOW_TYPE_HINT_DIALOG
- GDK_GRAVITY_NORTH_WEST
- True
-
-
-
- True
- False
- 0
-
-
-
- True
- GTK_BUTTONBOX_END
-
-
-
- True
- True
- True
- gtk-cancel
- True
- GTK_RELIEF_NORMAL
- True
- -6
-
-
-
-
-
- True
- True
- True
- True
- True
- gtk-ok
- True
- GTK_RELIEF_NORMAL
- True
- -5
-
-
-
-
- 0
- False
- True
- GTK_PACK_END
-
-
-
-
-
- True
- False
- 0
-
-
-
- True
- Disk label
- False
- False
- GTK_JUSTIFY_LEFT
- False
- False
- 0.5
- 0.5
- 3
- 0
-
-
- 0
- False
- False
-
-
-
-
-
- True
- True
- True
- True
- True
- 0
-
- True
- *
- True
-
-
-
- 0
- True
- True
-
-
-
-
- 0
- True
- True
-
-
-
-
-
-
-
- True
- dialog1
- GTK_WINDOW_TOPLEVEL
- GTK_WIN_POS_NONE
- False
- True
- False
- True
- False
- False
- GDK_WINDOW_TYPE_HINT_DIALOG
- GDK_GRAVITY_NORTH_WEST
- True
-
-
-
- True
- False
- 0
-
-
-
- True
- GTK_BUTTONBOX_END
-
-
-
- True
- True
- True
- gtk-cancel
- True
- GTK_RELIEF_NORMAL
- True
- -6
-
-
-
-
-
- True
- True
- True
- gtk-ok
- True
- GTK_RELIEF_NORMAL
- True
- -5
-
-
-
-
- 0
- False
- True
- GTK_PACK_END
-
-
-
-
-
- 3
- True
- False
- 0
-
-
-
- 3
- True
- 0
- 0.5
- GTK_SHADOW_ETCHED_IN
-
-
-
- 3
- True
- 0.5
- 0.5
- 1
- 1
- 0
- 0
- 12
- 0
-
-
-
- True
- 2
- 3
- False
- 3
- 3
-
-
-
- True
- True
- True
- True
- 0
- New
- True
- *
- False
-
-
- 1
- 2
- 0
- 1
-
-
-
-
-
-
- True
- True
- True
- True
- 0
-
- True
- *
- False
-
-
- 1
- 2
- 1
- 2
-
-
-
-
-
-
- True
- Disk Label:
- False
- False
- GTK_JUSTIFY_LEFT
- False
- False
- 0
- 0.5
- 0
- 0
-
-
- 0
- 1
- 0
- 1
- fill
-
-
-
-
-
-
- True
- Select directory:
- False
- False
- GTK_JUSTIFY_LEFT
- False
- False
- 0
- 0.5
- 0
- 0
-
-
- 0
- 1
- 1
- 2
- fill
-
-
-
-
-
-
- True
- True
- Browse...
- True
- GTK_RELIEF_NORMAL
- True
-
-
-
- 2
- 3
- 1
- 2
- fill
-
-
-
-
-
-
-
-
-
-
- True
- <b>Select directory and enter label</b>
- False
- True
- GTK_JUSTIFY_LEFT
- False
- False
- 0.5
- 0.5
- 0
- 0
-
-
- label_item
-
-
-
-
- 0
- True
- True
-
-
-
-
- 0
- True
- True
-
-
-
-
-
-
+
+ True
+ Disk label - pyGTKtalog
+ GDK_WINDOW_TYPE_HINT_DIALOG
+
+
+ True
+
+
+ True
+
+
+ True
+ 3
+ Disk label
+
+
+ False
+ False
+
+
+
+
+ True
+ True
+ True
+ True
+
+
+
+ 1
+
+
+
+
+ 2
+
+
+
+
+ True
+ GTK_BUTTONBOX_END
+
+
+ True
+ True
+ True
+ gtk-cancel
+ True
+ -6
+
+
+
+
+ True
+ True
+ True
+ True
+ True
+ gtk-ok
+ True
+ -5
+
+
+ 1
+
+
+
+
+ False
+ GTK_PACK_END
+
+
+
+
+
+
+ True
+ dialog1
+ GDK_WINDOW_TYPE_HINT_DIALOG
+
+
+ True
+
+
+ True
+ 3
+
+
+ True
+ 3
+ 0
+
+
+ True
+ 3
+ 12
+
+
+ True
+ 2
+ 3
+ 3
+ 3
+
+
+
+
+
+ True
+ True
+ Browse...
+ True
+ 0
+
+
+
+ 2
+ 3
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+
+ True
+ 0
+ Select directory:
+
+
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+
+ True
+ 0
+ Disk Label:
+
+
+ GTK_FILL
+
+
+
+
+
+ True
+ True
+
+
+ 1
+ 2
+ 1
+ 2
+
+
+
+
+
+ True
+ True
+ New
+
+
+ 1
+ 2
+
+
+
+
+
+
+
+
+
+ True
+ <b>Select directory and enter label</b>
+ True
+
+
+ label_item
+
+
+
+
+
+
+ 2
+
+
+
+
+ True
+ GTK_BUTTONBOX_END
+
+
+ True
+ True
+ True
+ gtk-cancel
+ True
+ -6
+
+
+
+
+ True
+ True
+ True
+ gtk-ok
+ True
+ -5
+
+
+ 1
+
+
+
+
+ False
+ GTK_PACK_END
+
+
+
+
+
+
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 5
+ pyGTKtalog - stats
+ GTK_WIN_POS_CENTER_ON_PARENT
+ GDK_WINDOW_TYPE_HINT_DIALOG
+ False
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 2
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 4
+ 2
+ 2
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ Total size:
+ GTK_JUSTIFY_RIGHT
+
+
+ 3
+ 4
+ GTK_FILL
+
+
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ Number of files:
+ GTK_JUSTIFY_RIGHT
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ Number of directories:
+ GTK_JUSTIFY_RIGHT
+
+
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ Number of discs:
+ GTK_JUSTIFY_RIGHT
+
+
+ GTK_FILL
+
+
+
+
+ True
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ False
+ GTK_SHADOW_ETCHED_IN
+
+
+ 1
+ 2
+ 3
+ 4
+ GTK_FILL
+
+
+
+
+ True
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ False
+ GTK_SHADOW_ETCHED_IN
+
+
+ 1
+ 2
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ False
+ GTK_SHADOW_ETCHED_IN
+
+
+ 1
+ 2
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ False
+ GTK_SHADOW_ETCHED_IN
+
+
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ False
+ 1
+
+
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ GTK_BUTTONBOX_END
+
+
+ True
+ True
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ gtk-close
+ True
+ 0
+
+
+
+
+ False
+ GTK_PACK_END
+
+
+
+
+
diff --git a/resources/glade/main.glade b/resources/glade/main.glade
index 3f3029c..625c9bb 100644
--- a/resources/glade/main.glade
+++ b/resources/glade/main.glade
@@ -141,6 +141,7 @@
True
True
+
@@ -171,7 +172,7 @@
+
+
+
+
+
+
diff --git a/src/ctrls/c_main.py b/src/ctrls/c_main.py
index 2baa4fe..1caf3f6 100644
--- a/src/ctrls/c_main.py
+++ b/src/ctrls/c_main.py
@@ -50,13 +50,13 @@ class MainController(Controller):
widgets = (
"discs","files",
'save1','save_as1','cut1','copy1','paste1','delete1','add_cd','add_directory1',
- 'tb_save','tb_addcd','tb_find','nb_dirs','description',
+ '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','tb_new','tb_open','tb_quit',
- 'nb_dirs','description',
+ 'nb_dirs','description','stat1',
)
widgets_cancel = ('cancel','cancel1')
@@ -146,22 +146,22 @@ class MainController(Controller):
self.__do_quit()
return True
- def on_tb_quit_clicked(self,widget):
+ def on_tb_quit_clicked(self, widget):
self.__do_quit()
- def on_quit1_activate(self,widget):
+ def on_quit1_activate(self, widget):
self.__do_quit()
- def on_new1_activate(self,widget):
+ def on_new1_activate(self, widget):
self.__new_db()
- def on_tb_new_clicked(self,widget):
+ def on_tb_new_clicked(self, widget):
self.__new_db()
- def on_add_cd_activate(self,widget):
+ def on_add_cd_activate(self, widget):
self.__add_cd()
- def on_tb_addcd_clicked(self,widget):
+ def on_tb_addcd_clicked(self, widget):
self.__add_cd()
def on_add_directory1_activate(self, widget):
@@ -169,7 +169,7 @@ class MainController(Controller):
self.__add_directory()
return
- def on_about1_activate(self,widget):
+ def on_about1_activate(self, widget):
"""Show about dialog"""
Dialogs.Abt("pyGTKtalog", __version__, "About",
["Roman 'gryf' Dobosz"], licence)
@@ -207,6 +207,20 @@ class MainController(Controller):
def on_save_as1_activate(self, widget):
self.__save_as()
+ def on_stat1_activate(self, menu_item):
+ self.__show_stats()
+
+ def on_statistics1_activate(self, menu_item):
+ model = self.view['discs'].get_model()
+ try:
+ path, column = self.view['discs'].get_cursor()
+ selected_iter = self.model.discs_tree.get_iter(path)
+ except:
+ return
+
+ selected_id = self.model.discs_tree.get_value(selected_iter, 0)
+ self.__show_stats(selected_id)
+
def on_tb_open_clicked(self, widget):
self.__open()
@@ -242,7 +256,7 @@ class MainController(Controller):
return False
if event.button == 3:
- """show context menu"""
+ """Right mouse button. Show context menu."""
try:
selection = treeview.get_selection()
model, list_of_paths = selection.get_selected_rows()
@@ -286,26 +300,44 @@ class MainController(Controller):
self.view['discs'].collapse_all()
return
- def on_files_cursor_changed(self,treeview):
+ def on_files_button_press_event(self, tree, event):
+ try:
+ path, column, x, y = tree.get_path_at_pos(int(event.x),
+ int(event.y))
+ except TypeError:
+ tree.get_selection().unselect_all()
+ return False
+
+ if event.button == 3: # Right mouse button. Show context menu.
+ try:
+ selection = tree.get_selection()
+ model, list_of_paths = selection.get_selected_rows()
+ except TypeError:
+ list_of_paths = []
+
+ self.__popup_files_menu(event)
+ return True
+
+ def on_files_cursor_changed(self, treeview):
"""Show details of selected file"""
model, paths = treeview.get_selection().get_selected_rows()
- #try:
- itera = model.get_iter(paths[0])
- if model.get_value(itera,4) == 1:
- #directory, do nothin', just turn off view
- '''self.view['details'].hide()
- buf = self.view['details'].get_buffer()
- buf.set_text('')
- self.view['details'].set_buffer(buf)'''
- else:
- #file, show what you got.
- #self.details.get_top_widget()
- iter = model.get_iter(treeview.get_cursor()[0])
- selected_item = self.model.files_list.get_value(iter, 0)
- self.__get_item_info(selected_item)
- #except:
- # if __debug__:
- # print "c_main.py: on_files_cursor_changed() insufficient iterator"
+ try:
+ itera = model.get_iter(paths[0])
+ if model.get_value(itera,4) == 1:
+ #directory, do nothin', just turn off view
+ '''self.view['details'].hide()
+ buf = self.view['details'].get_buffer()
+ buf.set_text('')
+ self.view['details'].set_buffer(buf)'''
+ else:
+ #file, show what you got.
+ #self.details.get_top_widget()
+ iter = model.get_iter(treeview.get_cursor()[0])
+ selected_item = self.model.files_list.get_value(iter, 0)
+ self.__get_item_info(selected_item)
+ except:
+ if __debug__:
+ print "c_main.py: on_files_cursor_changed() insufficient iterator"
return
def on_files_key_release_event(self, a, event):
@@ -376,6 +408,9 @@ class MainController(Controller):
self.__open(path)
return
+ def on_add_tag1_activate(self, menu_item):
+ print self.view['discs'].get_cursor()
+
def on_update1_activate(self, menu_item):
"""Update disc under cursor position"""
@@ -411,7 +446,7 @@ class MainController(Controller):
self.__set_title(filepath=self.model.filename, modified=True)
return
- def on_debugbtn_clicked(self,widget):
+ def on_debugbtn_clicked(self, widget):
"""Debug. To remove in stable version, including button in GUI"""
if __debug__:
print "\nc_main.py: on_debugbtn_clicked()"
@@ -713,6 +748,12 @@ class MainController(Controller):
self.view['discs_popup'].show_all()
return
+ def __popup_files_menu(self, event):
+ self.view['files_popup'].popup(None, None, None, event.button,
+ event.time)
+ self.view['files_popup'].show_all()
+ return
+
def __generate_recent_menu(self):
self.recent_menu = gtk.Menu()
for i in self.model.config.recent:
@@ -786,4 +827,8 @@ class MainController(Controller):
buff.insert_with_tags(iter, cloud['name'], tag)
self.view['tag_cloud_textview'].set_buffer(buff)
+ def __show_stats(self, selected_id=None):
+ data = self.model.get_stats(selected_id)
+ label = Dialogs.StatsDialog(data).run()
+
pass # end of class
diff --git a/src/models/m_main.py b/src/models/m_main.py
index c40550f..e7fbed4 100644
--- a/src/models/m_main.py
+++ b/src/models/m_main.py
@@ -327,7 +327,97 @@ class MainModel(ModelMT):
self.discs_tree.remove(branch_iter)
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):
+ 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 p in parents:
+ sql = """select count(id) from files where type!=0 and type!=1 and parent_id=?"""
+ self.db_cursor.execute(sql, (p,))
+ 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
+
# private class functions
+ def __bytes_to_human(self, integer):
+ if integer <= 0 or integer < 1024:
+ return "%d bytes" % integer
+
+ t = integer /1024.0
+ if t < 1 or t < 1024:
+ return "%d bytes (%d kB)" % (integer, t)
+
+ t = t /1024.0
+ if t < 1 or t < 1024:
+ return "%d bytes (%d MB)" % (integer, t)
+
+ t = t /1024.0
+ if t < 1 or t < 1024:
+ return "%d bytes (%d GB)" % (integer, t)
+
+ t = t /1024.0
+ return "%d bytes (%d TB)" % (integer, t)
+
def __clear_trees(self):
self.__clear_files_tree()
self.__clear_discs_tree()
@@ -396,23 +486,28 @@ class MainModel(ModelMT):
filename TEXT,
filepath TEXT,
date datetime,
- size integer,
- type integer,
- source integer,
- size_x integer,
- size_y integer,
- filetype integer,
+ size INTEGER,
+ type INTEGER,
+ source INTEGER,
+ note TEXT,
description TEXT);""")
self.db_cursor.execute("""create table
tags(id INTEGER PRIMARY KEY AUTOINCREMENT,
- file_id INTEGER,
+ 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("insert into files values(1, 1, 'root', null, \
- 0, 0, 0, 0, null, null, null, null);")
+ self.db_cursor.execute("insert into files values(1, 1, 'root', null, 0, 0, 0, 0, null, null, null, null);")
+ self.db_cursor.execute("insert into groups values(1, 'default', 'black');")
def __scan(self):
"""scan content of the given path"""
@@ -496,36 +591,32 @@ class MainModel(ModelMT):
#return -1
return 0
+ #############
+ # directories
for i in dirs:
- if self.fsenc:
- j = i.decode(self.fsenc)
- else:
- j = i
+ j = self.__decode_filename(i)
+ current_dir = os.path.join(root, i)
try:
- st = os.stat(os.path.join(root,i))
+ st = os.stat(current_dir)
st_mtime = st.st_mtime
except OSError:
st_mtime = 0
# do NOT follow symbolic links
- if os.path.islink(os.path.join(root,i)):
- l = os.readlink(os.path.join(root,i))
- if self.fsenc:
- l = l.decode(self.fsenc)
- else:
- l = l
+ 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,
- os.path.join(path,i), st_mtime, 0,
+ ocurrent_dir, st_mtime, 0,
self.LIN))
dirsize = 0
else:
- dirsize = __recurse(currentid, j, os.path.join(path,i),
+ dirsize = __recurse(currentid, j, current_dir,
st_mtime, 0, self.DIR, myit)
if dirsize == -1:
@@ -533,13 +624,17 @@ class MainModel(ModelMT):
else:
_size = _size + dirsize
+ ########
+ # files:
for i in files:
if self.abort:
break
+
self.count = self.count + 1
- current_path = os.path.join(root,i)
+ current_file = os.path.join(root, i)
+
try:
- st = os.stat(current_path)
+ st = os.stat(current_file)
st_mtime = st.st_mtime
st_size = st.st_size
except OSError:
@@ -547,62 +642,70 @@ class MainModel(ModelMT):
st_size = 0
_size = _size + st_size
- j = i
- if self.fsenc:
- j = i.decode(self.fsenc)
+ j = self.__decode_filename(i)
- sql = """
- insert into files(parent_id, filename, filepath, date, size, type)
- values(?,?,?,?,?,?)
- """
- db_cursor.execute(sql, (currentid, j, os.path.join(path,i),
- st_mtime, st_size, self.FIL))
-
- if self.count % 32 == 0:
- update = True
+ # 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:
- update = False
+ 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))
- ###########################
- # fetch details about files
- if self.config.confd['retrive']:
- update = True
- sql = """select seq FROM sqlite_sequence WHERE name='files'"""
- db_cursor.execute(sql)
- fileid = db_cursor.fetchone()[0]
-
- ext = i.split('.')[-1].lower()
-
- # Images - thumbnails and exif data
- if self.config.confd['thumbs'] and ext in self.IMG:
- path, exif, ret_code = Thumbnail(current_path, base=self.internal_dirname).save(fileid)
- if ret_code != -1:
- sql = """insert into thumbnails(file_id, filename) values (?, ?)"""
- db_cursor.execute(sql, (fileid,
- path.split(self.internal_dirname)[1][1:]))
-
- if self.config.confd['exif']:
- # TODO: exif implementation
- pass
-
- # Extensions - user defined actions
- if ext in self.config.confd['extensions'].keys():
- cmd = self.config.confd['extensions'][ext]
- arg = string.replace(current_path, '"', '\\"')
- output = os.popen(cmd % arg).readlines()
- desc = ''
- for line in output:
- desc += line
- #desc = string.replace(desc, "\n", "\\n")
- sql = """update files set description=? where id=?"""
- db_cursor.execute(sql, (desc, fileid))
+ if self.count % 32 == 0:
+ update = True
+ else:
+ update = False
- #if i.split('.').[-1].lower() in mov_ext:
- # # video only
- # info = filetypeHelper.guess_video(os.path.join(root,i))
- ### end of scan
+ ###########################
+ # fetch details about files
+ if self.config.confd['retrive']:
+ update = True
+ sql = """select seq FROM sqlite_sequence WHERE name='files'"""
+ db_cursor.execute(sql)
+ fileid = db_cursor.fetchone()[0]
+
+ ext = i.split('.')[-1].lower()
+
+ # Images - thumbnails and exif data
+ if self.config.confd['thumbs'] and ext in self.IMG:
+ path, exif, ret_code = Thumbnail(current_file, base=self.internal_dirname).save(fileid)
+ if ret_code != -1:
+ sql = """insert into thumbnails(file_id, filename) values (?, ?)"""
+ db_cursor.execute(sql, (fileid,
+ path.split(self.internal_dirname)[1][1:]))
+
+ if self.config.confd['exif']:
+ # TODO: exif implementation
+ pass
+
+ # Extensions - user defined actions
+ if ext in self.config.confd['extensions'].keys():
+ cmd = self.config.confd['extensions'][ext]
+ arg = string.replace(current_file, '"', '\\"')
+ output = os.popen(cmd % arg).readlines()
+ desc = ''
+ for line in output:
+ desc += line
+ #desc = string.replace(desc, "\n", "\\n")
+ sql = """update files set description=? where id=?"""
+ 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
if update:
- self.statusmsg = "Scannig: %s" % current_path
+ self.statusmsg = "Scannig: %s" % current_file
self.progress = step * self.count
sql = """update files set size=? where id=?"""
@@ -695,34 +798,53 @@ class MainModel(ModelMT):
return
def __remove_branch_form_db(self, root_id):
- parent_ids = [root_id,]
- sql = """select id from files where parent_id = ? and type = 1"""
- self.db_cursor.execute(sql, (root_id,))
- ids = self.db_cursor.fetchall()
+ """Remove subtree from main tree, remove tags from database
+ remove all possible data, like thumbnails"""
+ fids = []
def get_children(fid):
- parent_ids.append(fid)
- sql = """select id from files where parent_id = ? and type = 1"""
+ fids.append(fid)
+ sql = """select id from files where parent_id = ?"""
self.db_cursor.execute(sql, (fid,))
res = self.db_cursor.fetchall()
- for i in res:
- get_children(i[0])
+ if len(res)>0:
+ for i in res:
+ get_children(i[0])
- for i in ids:
- get_children(i[0])
+ get_children(root_id)
def generator():
- for c in parent_ids:
+ for c in fids:
yield (c,)
-
- sql = """delete from files where type = 1 and parent_id = ?"""
- self.db_cursor.executemany(sql, generator())
+
+ # remove files records
sql = """delete from files where id = ?"""
self.db_cursor.executemany(sql, generator())
+
+ # remove tags records
+ sql = """delete from tags_files where file_id = ?"""
+ self.db_cursor.executemany(sql, generator())
+
+ # remove thumbnails
+ arg =''
+ for c in fids:
+ if len(arg) > 0:
+ arg+=", %d" % c
+ else:
+ arg = "%d" % c
+ sql = """select filename from thumbnails where file_id in (%s)""" % arg
+ self.db_cursor.execute(sql)
+ res = self.db_cursor.fetchall()
+ if len(res) > 0:
+ for fn in res:
+ os.unlink(os.path.join(self.internal_dirname, fn[0]))
+
+ # remove thumbs records
+ sql = """delete from thumbnails where file_id = ?"""
+ self.db_cursor.executemany(sql, generator())
self.db_connection.commit()
return
-
def __append_added_volume(self):
"""append branch from DB to existing tree model"""
#connect
@@ -762,4 +884,10 @@ class MainModel(ModelMT):
db_connection.close()
return
+ def __decode_filename(self, txt):
+ if self.fsenc:
+ return txt.decode(self.fsenc)
+ else:
+ return txt
+
pass # end of class
diff --git a/src/views/v_dialogs.py b/src/views/v_dialogs.py
index c5a0f96..fb20d98 100644
--- a/src/views/v_dialogs.py
+++ b/src/views/v_dialogs.py
@@ -109,7 +109,7 @@ class Abt(object):
self.dialog.set_authors(authors)
self.dialog.connect('response', lambda dialog, response: self.dialog.destroy())
self.dialog.show()
-
+
class InputDiskLabel(object):
"""Sepcific dialog for quering user for a disc label"""
def __init__(self, label=""):
@@ -276,3 +276,45 @@ class LoadDBFile(object):
a = Err("Error - pyGTKtalog","File doesn't exist.","The file that you choose does not exist. Choose another one, or cancel operation.")
ch = True
res,filename = self.show_dialog()
+
+class StatsDialog(object):
+ """Sepcific dialog for display stats"""
+ def __init__(self, values={}):
+ self.gladefile = os.path.join(utils.globals.GLADE_DIR, "dialogs.glade")
+ self.values = values
+
+ def run(self):
+ gladexml = gtk.glade.XML(self.gladefile, "statDialog")
+ dialog = gladexml.get_widget("statDialog")
+
+ if self.values.has_key('discs'):
+ entry = gladexml.get_widget("discs_entry")
+ entry.set_text(str(self.values['discs']))
+ else:
+ label = gladexml.get_widget("discs_label")
+ entry = gladexml.get_widget("discs_entry")
+ label.hide()
+ entry.hide()
+
+ if self.values.has_key('dirs'):
+ entry = gladexml.get_widget("dirs_entry")
+ entry.set_text(str(self.values['dirs']))
+ else:
+ label = gladexml.get_widget("dirs_label")
+ entry = gladexml.get_widget("dirs_entry")
+ label.hide()
+ entry.hide()
+
+ if self.values.has_key('files'):
+ entry = gladexml.get_widget("files_entry")
+ entry.set_text(str(self.values['files']))
+
+ if self.values.has_key('size'):
+ entry = gladexml.get_widget("size_entry")
+ entry.set_text(str(self.values['size']))
+
+ result = dialog.run()
+ dialog.destroy()
+ if result == gtk.RESPONSE_OK:
+ return entry.get_text()
+ return None