diff --git a/convert_1.x_to_2.x.py b/convert_1.x_to_2.x.py
index e24da91..6ab7848 100755
--- a/convert_1.x_to_2.x.py
+++ b/convert_1.x_to_2.x.py
@@ -96,7 +96,7 @@ if __name__ == "__main__":
for id, date in dst_c.execute(sql).fetchall():
sql = "update files set date=? where id=?"
- if int(date) > 0:
+ if date and int(date) > 0:
dst_c.execute(sql, (datetime.fromtimestamp(int(date)), id))
else:
dst_c.execute(sql, (None, id))
@@ -105,10 +105,13 @@ if __name__ == "__main__":
for id, date in dst_c.execute(sql).fetchall():
sql = "update gthumb set date=? where id=?"
- if int(date) > 0:
- dst_c.execute(sql, (datetime.fromtimestamp(int(date)), id))
- else:
- dst_c.execute(sql, (None, id))
+ try:
+ if int(date) > 0:
+ dst_c.execute(sql, (datetime.fromtimestamp(int(date)), id))
+ else:
+ dst_c.execute(sql, (None, id))
+ except:
+ print id, date
dst_con.commit()
dst_c.close()
diff --git a/pygtktalog/__init__.py b/pygtktalog/__init__.py
index c34f2bb..6e94479 100644
--- a/pygtktalog/__init__.py
+++ b/pygtktalog/__init__.py
@@ -13,6 +13,16 @@ import __builtin__
import gtk.glade
+__all__ = ['controllers',
+ 'models',
+ 'views',
+ 'EXIF',
+ 'dbcommon',
+ 'dbobjects',
+ 'dialogs',
+ 'logger',
+ 'misc']
+
GETTEXT_DOMAIN = 'pygtktalog'
# There should be message catalogs in "locale" directory placed by setup.py
# script. If there is no such directory, let's assume that message catalogs are
diff --git a/pygtktalog/controllers/discs.py b/pygtktalog/controllers/discs.py
index 48ec87f..7824d64 100644
--- a/pygtktalog/controllers/discs.py
+++ b/pygtktalog/controllers/discs.py
@@ -52,6 +52,8 @@ class DiscsController(Controller):
# make cell text editabe
cell.set_property('editable', True)
cell.connect('edited', self.on_editing_done, self.model.discs)
+ # TODO: find a way how to disable default return keypress on editable
+ # fields
col.pack_start(cellpb, False)
col.pack_start(cell, True)
@@ -70,30 +72,37 @@ class DiscsController(Controller):
LOG.debug(self.on_discs_button_press_event.__doc__.strip())
pathinfo = treeview.get_path_at_pos(int(event.x), int(event.y))
- if event.button == 3 and pathinfo:
- path = pathinfo[0]
+ if event.button == 3:
+ if pathinfo:
+ path = pathinfo[0]
- # Make sure, that there is selected row
- sel = treeview.get_selection()
- sel.unselect_all()
- sel.select_path(path)
+ # Make sure, that there is selected row
+ sel = treeview.get_selection()
+ sel.unselect_all()
+ sel.select_path(path)
- self._popup_menu(sel, event, event.button)
+ self._popup_menu(sel, event, event.button)
+ else:
+ self._popup_menu(None, event, event.button)
return True
- def on_discs_cursor_changed(self, widget):
+ def on_discs_cursor_changed(self, treeview):
"""
Show files on right treeview, after clicking the left disc treeview.
"""
LOG.debug(self.on_discs_cursor_changed.__doc__.strip())
- raise NotImplementedError
+ selection = treeview.get_selection()
+ path = selection.get_selected_rows()[1][0]
+ self.model.update_files(self.model.discs.get_value(\
+ self.model.discs.get_iter(path), 0))
def on_discs_key_release_event(self, treeview, event):
"""
- Trigger popup menu by pressing 'menu' key
+ Watch for specific keys
"""
LOG.debug(self.on_discs_key_release_event.__doc__.strip())
if gtk.gdk.keyval_name(event.keyval) == 'Menu':
+ LOG.debug('Menu key pressed')
self._popup_menu(treeview.get_selection(), event, 0)
return True
return False
@@ -170,11 +179,15 @@ class DiscsController(Controller):
and trigger menu popup.
"""
LOG.debug(self._popup_menu.__doc__.strip())
- model, list_of_paths = selection.get_selected_rows()
+ if selection is None:
+ self.view.menu.set_menu_items_sensitivity(False)
+ else:
+ model, list_of_paths = selection.get_selected_rows()
- for path in list_of_paths:
- self.view.menu.set_update_sensitivity(not model.get_value(\
- model.get_iter(path), 0).parent_id == 1)
+ for path in list_of_paths:
+ self.view.menu.set_menu_items_sensitivity(True)
+ self.view.menu.set_update_sensitivity(model.get_value(\
+ model.get_iter(path), 0).parent_id == 1)
self.view.menu['discs_popup'].popup(None, None, None,
button, event.time)
diff --git a/pygtktalog/controllers/files.py b/pygtktalog/controllers/files.py
index 22d41c0..e57465e 100644
--- a/pygtktalog/controllers/files.py
+++ b/pygtktalog/controllers/files.py
@@ -15,19 +15,57 @@ class FilesController(Controller):
Controller for files TreeView list.
"""
+ def __init__(self, model, view):
+ """
+ FilesController initialization
+ """
+ Controller.__init__(self, model, view)
+ self.DND_TARGETS = [('files_tags', 0, 69)]
+
+
def register_view(self, view):
- """Default view registration stuff"""
- self.view['files'].set_model(self.model.discs)
+ """
+ Register view, and setup columns for files treeview
+ """
+ view['files'].set_model(self.model.files)
+ view['files'].get_selection().set_mode(gtk.SELECTION_MULTIPLE)
- col = gtk.TreeViewColumn('kolumna2')
+ col = gtk.TreeViewColumn(_('Disc'), gtk.CellRendererText(), text=1)
+ col.set_sort_column_id(1)
+ col.set_resizable(True)
+ col.set_visible(False)
+ view['files'].append_column(col)
+ col = gtk.TreeViewColumn(_('Filename'))
cellpb = gtk.CellRendererPixbuf()
cell = gtk.CellRendererText()
-
col.pack_start(cellpb, False)
col.pack_start(cell, True)
-
- col.set_attributes(cellpb, stock_id=0)
- col.set_attributes(cell, text=1)
+ col.set_attributes(cellpb, stock_id=7)
+ col.set_attributes(cell, text=2)
+ col.set_sort_column_id(2)
+ col.set_resizable(True)
self.view['files'].append_column(col)
+ col = gtk.TreeViewColumn(_('Path'), gtk.CellRendererText(), text=3)
+ col.set_sort_column_id(3)
+ col.set_resizable(True)
+ col.set_visible(False)
+ self.view['files'].append_column(col)
+
+ col = gtk.TreeViewColumn(_('Size'), gtk.CellRendererText(), text=4)
+ col.set_sort_column_id(4)
+ col.set_resizable(True)
+ self.view['files'].append_column(col)
+
+ col = gtk.TreeViewColumn(_('Date'), gtk.CellRendererText(), text=5)
+ col.set_sort_column_id(5)
+ col.set_resizable(True)
+ self.view['files'].append_column(col)
+ self.view['files'].set_search_column(2)
+
+ # setup d'n'd support
+ view['files'].drag_source_set(gtk.gdk.BUTTON1_MASK,
+ self.DND_TARGETS,
+ gtk.gdk.ACTION_COPY)
+
diff --git a/pygtktalog/controllers/main.py b/pygtktalog/controllers/main.py
index c085149..88fc3a9 100644
--- a/pygtktalog/controllers/main.py
+++ b/pygtktalog/controllers/main.py
@@ -11,7 +11,7 @@ from gtkmvc import Controller
#from pygtktalog.dialogs import yesno
from pygtktalog.controllers.discs import DiscsController
-#from pygtktalog.controllers.files import FilesController
+from pygtktalog.controllers.files import FilesController
#from pygtktalog.controllers.details import DetailsController
#from pygtktalog.controllers.tags import TagcloudController
#from pygtktalog.dialogs import yesno, okcancel, info, warn, error
@@ -25,36 +25,50 @@ class MainController(Controller):
"""
def __init__(self, model, view):
- """Initialize main controller"""
+ """
+ Initialize MainController, add controllers for trees and details.
+ """
+ LOG.debug(self.__init__.__doc__.strip())
Controller.__init__(self, model, view)
- # add controllers for files/tags components
+ # add controllers for files/tags/details components
self.discs = DiscsController(model, view.discs)
- #self.files = FilesController(model, view.files)
+ self.files = FilesController(model, view.files)
#self.details = DetailsController(model, view.details)
#self.tags = TagcloudController(model, view.tags)
def register_view(self, view):
- """Default view registration stuff"""
- # one row contains image and text
+ """
+ Registration view for MainController class
+ """
+ LOG.debug(self.register_view.__doc__.strip())
+ LOG.debug("replace hardcoded defaults with configured!")
+ view['main'].set_default_size(800, 600)
+ view['hpaned1'].set_position(200)
view['main'].show()
def register_adapters(self):
"""
progress bar/status bar adapters goes here
"""
+ LOG.debug(self.register_adapters.__doc__.strip())
pass
# signals
def on_main_destroy_event(self, widget, event):
- """Quit"""
+ """
+ Window destroyed. Cleanup before quit.
+ """
+ LOG.debug(self.on_main_destroy_event.__doc__.strip())
self.on_quit_activate(widget)
return True
def on_quit_activate(self, widget):
- """Quit and save window parameters to config file"""
-
+ """
+ Quit and save window parameters to config file
+ """
+ LOG.debug(self.on_quit_activate.__doc__.strip())
#if yesno(_("Do you really want to quit?"),
# _("Current database is not saved, any changes will be "
# "lost."), _("Quit application") + " - pyGTKtalog", 0):
diff --git a/pygtktalog/models/main.py b/pygtktalog/models/main.py
index 698a955..e5e2816 100644
--- a/pygtktalog/models/main.py
+++ b/pygtktalog/models/main.py
@@ -45,6 +45,8 @@ class MainModel(ModelMT):
self.cat_fname = filename
# Temporary (usually in /tmp) working database.
self.tmp_filename = None
+ # SQLAlchemy session object for internal use
+ self._session = None
# Flag indicates, that db was compressed
# TODO: make it depend on configuration
self.compressed = False
@@ -54,7 +56,14 @@ class MainModel(ModelMT):
self.discs = gtk.TreeStore(gobject.TYPE_PYOBJECT,
gobject.TYPE_STRING,
str)
-
+ self.files = gtk.ListStore(gobject.TYPE_PYOBJECT,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING,
+ gobject.TYPE_UINT64,
+ gobject.TYPE_STRING,
+ gobject.TYPE_INT,
+ str)
if self.cat_fname:
self.open(self.cat_fname)
@@ -82,12 +91,18 @@ class MainModel(ModelMT):
"""
Create new catalog
"""
- self._cleanup_and_create_temp_db_file()
+ self.cleanup()
+ self._create_temp_db_file()
def cleanup(self):
"""
Remove temporary directory tree from filesystem
"""
+
+ if self._session:
+ self._session.close()
+ self._session = None
+
if self.tmp_filename is None:
return
@@ -105,7 +120,8 @@ class MainModel(ModelMT):
"""
Create new DB
"""
- self._cleanup_and_create_temp_db_file()
+ self.cleanup()
+ self._create_temp_db_file()
def _examine_file(self, filename):
"""
@@ -143,7 +159,10 @@ class MainModel(ModelMT):
filename = os.path.abspath(self.cat_fname)
LOG.info("catalog file: %s", filename)
- self._cleanup_and_create_temp_db_file()
+ if self._session:
+ self.cleanup()
+
+ self._create_temp_db_file()
LOG.debug("tmp database file: %s", str(self.tmp_filename))
examine = self._examine_file(filename)
@@ -181,10 +200,10 @@ class MainModel(ModelMT):
return False
connect(os.path.abspath(self.tmp_filename))
+ self._session = Session()
return True
- def _cleanup_and_create_temp_db_file(self):
- self.cleanup()
+ def _create_temp_db_file(self):
fd, self.tmp_filename = mkstemp()
# close file descriptor, otherwise it can be source of app crash!
# http://www.logilab.org/blogentry/17873
@@ -195,8 +214,7 @@ class MainModel(ModelMT):
Read objects from database, fill TreeStore model with discs
information
"""
- session = Session()
- dirs = session.query(File).filter(File.type == 1)
+ dirs = self._session.query(File).filter(File.type == 1)
dirs = dirs.order_by(File.filename).all()
def get_children(parent_id=1, iterator=None):
@@ -218,9 +236,33 @@ class MainModel(ModelMT):
get_children(fileob.id, myiter)
return
get_children()
- session.close()
return True
- def get_root_entries(self, id):
- LOG.debug("not implemented!, get_root_entries, id: %s", str(id))
+ def update_files(self, fileob):
+ """
+ Update files ListStore
+ Arguments:
+ fileob - File object
+ """
+ files = self._session.query(File).filter(File.parent_id==fileob.id)\
+ .order_by(File.type, File.filename).all()
+ files = []
+ LOG.info("found %d files for root id %s" %(len(files), str(fileob)))
+
+ self.files.clear()
+
+ for fob in files:
+ myiter = self.files.insert_before(None, None)
+ self.files.set_value(myiter, 0, fob.id)
+ self.files.set_value(myiter, 1, fob.parent_id if fob.parent_id!=1 else None)
+ self.files.set_value(myiter, 2, fob.filename)
+ self.files.set_value(myiter, 3, fob.filepath)
+ self.files.set_value(myiter, 4, fob.size)
+ self.files.set_value(myiter, 5, fob.date)
+ self.files.set_value(myiter, 6, 1)
+ self.files.set_value(myiter, 7, gtk.STOCK_DIRECTORY \
+ if fob.type==1 else gtk.STOCK_FILE)
+
+
+
diff --git a/pygtktalog/views/glade/files.glade b/pygtktalog/views/glade/files.glade
index 53e5b96..e0e0d89 100644
--- a/pygtktalog/views/glade/files.glade
+++ b/pygtktalog/views/glade/files.glade
@@ -1,19 +1,122 @@
-
-
-
+
+
+
True
True
True
-
-
+
+
+
diff --git a/pygtktalog/views/glade/main.glade b/pygtktalog/views/glade/main.glade
index c486922..ee224bb 100644
--- a/pygtktalog/views/glade/main.glade
+++ b/pygtktalog/views/glade/main.glade
@@ -495,7 +495,7 @@
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
-
+
True
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
@@ -556,7 +556,7 @@
True
vertical
-
+
True
True
automatic
@@ -639,108 +639,6 @@
-
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
pyGTKtalog - Image
diff --git a/pygtktalog/views/main.py b/pygtktalog/views/main.py
index a29a83d..ea48be2 100644
--- a/pygtktalog/views/main.py
+++ b/pygtktalog/views/main.py
@@ -31,8 +31,13 @@ class MainView(View):
"""
View.__init__(self)
self['tag_path_box'].hide()
+
self.discs = DiscsView()
- self['scrolledwindow1'].add_with_viewport(self.discs.get_top_widget())
+ #self['scrolledwindow_discs'].add_with_viewport(self.discs.get_top_widget())
+ self['scrolledwindow_discs'].add(self.discs.get_top_widget())
+
+ self.files = FilesView()
+ self['scrolledwindow_files'].add_with_viewport(self.files.get_top_widget())
def set_widgets_scan_sensitivity(self, sensitive=True):
"""
@@ -71,11 +76,23 @@ class DiscsPopupView(View):
def set_update_sensitivity(self, state):
"""
- Update sensitivity for 'update' popup menu item
-
+ Set sensitivity for 'update' popup menu item
+ Arguments:
+ @state - Bool, if True update menu item will be sensitive,
+ otherwise not
"""
- self['update'].set_sensitive(not state)
+ self['update'].set_sensitive(state)
+ def set_menu_items_sensitivity(self, state):
+ """
+ Set sensitivity for couple of popup menu items, which should be
+ disabled if user right-clicks on no item in treeview.
+ Arguments:
+ @state - Bool, if True update menu item will be sensitive,
+ otherwise not
+ """
+ for item in ['update', 'rename', 'delete', 'statistics']:
+ self[item].set_sensitive(state)
class FilesView(View):
"""
@@ -90,6 +107,18 @@ class FilesView(View):
"""
View.__init__(self)
+class FilesPopupView(View):
+ """
+ Separate Files PopUp subview.
+ """
+ glade = get_glade("files.glade")
+ top = 'files_popup'
+
+ def __init__(self):
+ """
+ Initialize view
+ """
+ View.__init__(self)
class TagcloudView(View):
"""