mirror of
https://github.com/gryf/pygtktalog.git
synced 2025-12-17 11:30:19 +01:00
* Bug bypass with foreach method for texttagtable (it's not iterate
over all tags, no one knows why). * Added pictures export. * Added new common class for directory pick. * Clean up main model - tree models have to be updated, than destroyed and created from scratch.
This commit is contained in:
2
README
2
README
@@ -62,7 +62,7 @@ For version 1.0 following aims have to be done:
|
|||||||
- searching database
|
- searching database
|
||||||
- tagging files (90%)
|
- tagging files (90%)
|
||||||
- user definied group of tags (represented by color in cloud tag)
|
- user definied group of tags (represented by color in cloud tag)
|
||||||
- remove nasty bug in redraw of tag cloud
|
x remove nasty bug in redraw of tag cloud
|
||||||
x file details:
|
x file details:
|
||||||
x files properties
|
x files properties
|
||||||
x thumbnail
|
x thumbnail
|
||||||
|
|||||||
@@ -532,6 +532,8 @@
|
|||||||
<property name="wrap_mode">GTK_WRAP_WORD</property>
|
<property name="wrap_mode">GTK_WRAP_WORD</property>
|
||||||
<property name="cursor_visible">False</property>
|
<property name="cursor_visible">False</property>
|
||||||
<signal name="visibility_notify_event" handler="on_tag_cloud_textview_visibility_notify_event"/>
|
<signal name="visibility_notify_event" handler="on_tag_cloud_textview_visibility_notify_event"/>
|
||||||
|
<signal name="drag_leave" handler="on_tag_cloud_textview_drag_leave"/>
|
||||||
|
<signal name="event_after" handler="on_tag_cloud_textview_event_after"/>
|
||||||
<signal name="drag_motion" handler="on_tag_cloud_textview_drag_motion"/>
|
<signal name="drag_motion" handler="on_tag_cloud_textview_drag_motion"/>
|
||||||
<signal name="drag_data_received" handler="on_tag_cloud_textview_drag_data_received"/>
|
<signal name="drag_data_received" handler="on_tag_cloud_textview_drag_data_received"/>
|
||||||
<signal name="drag_drop" handler="on_tag_cloud_textview_drag_drop"/>
|
<signal name="drag_drop" handler="on_tag_cloud_textview_drag_drop"/>
|
||||||
@@ -948,15 +950,6 @@
|
|||||||
<widget class="GtkMenu" id="img_popup">
|
<widget class="GtkMenu" id="img_popup">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<child>
|
|
||||||
<widget class="GtkMenuItem" id="img_delete">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
|
||||||
<property name="label" translatable="yes">_Delete image</property>
|
|
||||||
<property name="use_underline">True</property>
|
|
||||||
<signal name="activate" handler="on_img_delete_activate"/>
|
|
||||||
</widget>
|
|
||||||
</child>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkMenuItem" id="img_add">
|
<widget class="GtkMenuItem" id="img_add">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@@ -966,6 +959,44 @@
|
|||||||
<signal name="activate" handler="on_img_add_activate"/>
|
<signal name="activate" handler="on_img_add_activate"/>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkSeparatorMenuItem" id="separator9">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="img_delete">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="label" translatable="yes">_Delete images</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<signal name="activate" handler="on_img_delete_activate"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="img_delete2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">Delete selected images, but leave thumbnails</property>
|
||||||
|
<property name="label" translatable="yes">De_lete images (keep thumbs)</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<signal name="activate" handler="on_img_delete2_activate"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkSeparatorMenuItem" id="separator10">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkMenuItem" id="img_save">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="label" translatable="yes">_Save images to...</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<signal name="activate" handler="on_img_save_activate"/>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="GtkMenu" id="th_popup">
|
<widget class="GtkMenu" id="th_popup">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ class MainController(Controller):
|
|||||||
"""Initialize controller"""
|
"""Initialize controller"""
|
||||||
self.DND_TARGETS = [('files_tags', 0, 69)]
|
self.DND_TARGETS = [('files_tags', 0, 69)]
|
||||||
Controller.__init__(self, model)
|
Controller.__init__(self, model)
|
||||||
self.tag_switched = True
|
|
||||||
self.hovering = False
|
self.hovering = False
|
||||||
self.first = True
|
self.first = True
|
||||||
return
|
return
|
||||||
@@ -125,6 +124,10 @@ class MainController(Controller):
|
|||||||
# generate recent menu
|
# generate recent menu
|
||||||
self.__generate_recent_menu()
|
self.__generate_recent_menu()
|
||||||
|
|
||||||
|
# in case model has opened file, register tags
|
||||||
|
if self.model.internal_dirname:
|
||||||
|
self.__tag_cloud()
|
||||||
|
|
||||||
# Show main window
|
# Show main window
|
||||||
self.view['main'].show();
|
self.view['main'].show();
|
||||||
self.view['main'].drag_dest_set(0, [], 0)
|
self.view['main'].drag_dest_set(0, [], 0)
|
||||||
@@ -139,21 +142,25 @@ class MainController(Controller):
|
|||||||
def on_tag_cloud_textview_drag_motion(self, filestv, context, x, y, time):
|
def on_tag_cloud_textview_drag_motion(self, filestv, context, x, y, time):
|
||||||
context.drag_status(gtk.gdk.ACTION_COPY, time)
|
context.drag_status(gtk.gdk.ACTION_COPY, time)
|
||||||
iter = filestv.get_iter_at_location(x, y)
|
iter = filestv.get_iter_at_location(x, y)
|
||||||
|
buff = filestv.get_buffer()
|
||||||
|
tag_table = buff.get_tag_table()
|
||||||
|
|
||||||
|
# clear weight of tags
|
||||||
|
def foreach_tag(texttag, user_data):
|
||||||
|
"""set every text tag's weight to normal"""
|
||||||
|
texttag.set_property("underline", pango.UNDERLINE_NONE)
|
||||||
|
tag_table.foreach(foreach_tag, None)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tag = iter.get_tags()[0]
|
tag = iter.get_tags()[0]
|
||||||
self.tag_switched = False
|
tag.set_property("underline", pango.UNDERLINE_LOW)
|
||||||
tag.set_property("weight", pango.WEIGHT_BOLD)
|
|
||||||
except:
|
except:
|
||||||
if not self.tag_switched:
|
|
||||||
self.__tag_cloud()
|
|
||||||
pass
|
pass
|
||||||
#buff = filestv.get_buffer()
|
|
||||||
|
|
||||||
#self.__find_tag_in_textview()
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def on_files_drag_data_get(self, treeview, context, selection,
|
def on_files_drag_data_get(self, treeview, context, selection,
|
||||||
targetType, eventTime):
|
targetType, eventTime):
|
||||||
|
"""responce to "data get" DnD signal"""
|
||||||
# get selection, and send it to the client
|
# get selection, and send it to the client
|
||||||
if targetType == self.DND_TARGETS[0][2]:
|
if targetType == self.DND_TARGETS[0][2]:
|
||||||
# get selection
|
# get selection
|
||||||
@@ -166,8 +173,53 @@ class MainController(Controller):
|
|||||||
string = str(tuple(ids)).replace(",)", ")")
|
string = str(tuple(ids)).replace(",)", ")")
|
||||||
selection.set(selection.target, 8, string)
|
selection.set(selection.target, 8, string)
|
||||||
|
|
||||||
|
def on_tag_cloud_textview_event_after(self, textview, event):
|
||||||
|
if event.type != gtk.gdk.BUTTON_RELEASE:
|
||||||
|
return False
|
||||||
|
if event.button != 1:
|
||||||
|
return False
|
||||||
|
|
||||||
|
buff = textview.get_buffer()
|
||||||
|
try:
|
||||||
|
(start, end) = buff.get_selection_bounds()
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if start.get_offset() != end.get_offset():
|
||||||
|
return False
|
||||||
|
|
||||||
|
# get the iter at the mouse position
|
||||||
|
(x, y) = textview.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
|
||||||
|
int(event.x), int(event.y))
|
||||||
|
iterator = textview.get_iter_at_location(x, y)
|
||||||
|
|
||||||
|
# call open_url if an URL is assigned to the iter
|
||||||
|
tags = iterator.get_tags()
|
||||||
|
|
||||||
|
if len(tags) == 1:
|
||||||
|
tag = tags[0]
|
||||||
|
self.model.add_tag_to_path(tag.get_property('name'))
|
||||||
|
self.view['tag_path_box'].show()
|
||||||
|
|
||||||
|
# fill the path of tag
|
||||||
|
self.view['tag_path'].set_text('')
|
||||||
|
temp = self.model.selected_tags.values()
|
||||||
|
self.model.refresh_discs_tree()
|
||||||
|
#self.on_discs_cursor_changed(textview)
|
||||||
|
|
||||||
|
temp.sort()
|
||||||
|
for tag1 in temp:
|
||||||
|
txt = self.view['tag_path'].get_text()
|
||||||
|
if txt == '':
|
||||||
|
self.view['tag_path'].set_text(tag1)
|
||||||
|
else:
|
||||||
|
self.view['tag_path'].set_text(txt + ", " +tag1)
|
||||||
|
self.__tag_cloud()
|
||||||
|
|
||||||
|
|
||||||
def on_tag_cloud_textview_drag_data_received(self, widget, context, x, y,
|
def on_tag_cloud_textview_drag_data_received(self, widget, context, x, y,
|
||||||
selection, targetType, time):
|
selection, targetType, time):
|
||||||
|
"""recive data from source TV"""
|
||||||
if targetType == self.DND_TARGETS[0][2]:
|
if targetType == self.DND_TARGETS[0][2]:
|
||||||
iter = widget.get_iter_at_location(x, y)
|
iter = widget.get_iter_at_location(x, y)
|
||||||
ids = selection.data.rstrip(")").lstrip("(").split(",")
|
ids = selection.data.rstrip(")").lstrip("(").split(",")
|
||||||
@@ -302,9 +354,9 @@ class MainController(Controller):
|
|||||||
|
|
||||||
if new_name and new_name != name:
|
if new_name and new_name != name:
|
||||||
self.model.rename(id, new_name)
|
self.model.rename(id, new_name)
|
||||||
self.__set_title(filepath=self.model.filename, modified=True)
|
|
||||||
self.model.unsaved_project = True
|
self.model.unsaved_project = True
|
||||||
self.__set_title(filepath=self.model.filename, modified=True)
|
self.__set_title(filepath=self.model.filename, modified=True)
|
||||||
|
return True
|
||||||
|
|
||||||
def on_rename2_activate(self, widget):
|
def on_rename2_activate(self, widget):
|
||||||
try:
|
try:
|
||||||
@@ -325,18 +377,17 @@ class MainController(Controller):
|
|||||||
|
|
||||||
if new_name and new_name != name:
|
if new_name and new_name != name:
|
||||||
self.model.rename(fid, new_name)
|
self.model.rename(fid, new_name)
|
||||||
|
self.__get_item_info(fid)
|
||||||
self.__set_title(filepath=self.model.filename, modified=True)
|
self.__set_title(filepath=self.model.filename, modified=True)
|
||||||
|
|
||||||
try:
|
#try:
|
||||||
path, column = self.view['discs'].get_cursor()
|
# path, column = self.view['discs'].get_cursor()
|
||||||
iter = model.get_iter(path)
|
# iter = model.get_iter(path)
|
||||||
self.model.get_root_entries(model.get_value(iter, 0))
|
# self.model.get_root_entries(model.get_value(iter, 0))
|
||||||
except TypeError:
|
#except TypeError:
|
||||||
self.model.get_root_entries(1)
|
# self.model.get_root_entries(1)
|
||||||
return
|
# return
|
||||||
|
|
||||||
self.model.unsaved_project = True
|
|
||||||
self.__set_title(filepath=self.model.filename, modified=True)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def on_tag_cloud_textview_motion_notify_event(self, widget):
|
def on_tag_cloud_textview_motion_notify_event(self, widget):
|
||||||
@@ -353,6 +404,17 @@ class MainController(Controller):
|
|||||||
self.on_discs_cursor_changed(w)
|
self.on_discs_cursor_changed(w)
|
||||||
self.__tag_cloud()
|
self.__tag_cloud()
|
||||||
|
|
||||||
|
def on_tag_cloud_textview_drag_leave(self, textview, dragcontext, time):
|
||||||
|
"""clean up tags properties"""
|
||||||
|
buff = textview.get_buffer()
|
||||||
|
tag_table = buff.get_tag_table()
|
||||||
|
|
||||||
|
# clear weight of tags
|
||||||
|
def foreach_tag(texttag, user_data):
|
||||||
|
"""set every text tag's weight to normal"""
|
||||||
|
texttag.set_property("underline", pango.UNDERLINE_NONE)
|
||||||
|
tag_table.foreach(foreach_tag, None)
|
||||||
|
|
||||||
# NOTE: text view "links" functions
|
# NOTE: text view "links" functions
|
||||||
def on_tag_cloud_textview_visibility_notify_event(self, textview, event):
|
def on_tag_cloud_textview_visibility_notify_event(self, textview, event):
|
||||||
(wx, wy, mod) = textview.window.get_pointer()
|
(wx, wy, mod) = textview.window.get_pointer()
|
||||||
@@ -399,7 +461,7 @@ class MainController(Controller):
|
|||||||
self.view['tag_path'].set_text('')
|
self.view['tag_path'].set_text('')
|
||||||
temp = self.model.selected_tags.values()
|
temp = self.model.selected_tags.values()
|
||||||
self.model.refresh_discs_tree()
|
self.model.refresh_discs_tree()
|
||||||
self.on_discs_cursor_changed(textview)
|
#self.on_discs_cursor_changed(textview)
|
||||||
|
|
||||||
temp.sort()
|
temp.sort()
|
||||||
for tag1 in temp:
|
for tag1 in temp:
|
||||||
@@ -454,6 +516,7 @@ class MainController(Controller):
|
|||||||
buf.set_text("")
|
buf.set_text("")
|
||||||
self.view['description'].set_buffer(buf)
|
self.view['description'].set_buffer(buf)
|
||||||
self.__activate_ui()
|
self.__activate_ui()
|
||||||
|
self.__tag_cloud()
|
||||||
|
|
||||||
def on_add_cd_activate(self, widget, label=None, current_id=None):
|
def on_add_cd_activate(self, widget, label=None, current_id=None):
|
||||||
"""Add directory structure from cd/dvd disc"""
|
"""Add directory structure from cd/dvd disc"""
|
||||||
@@ -627,15 +690,75 @@ class MainController(Controller):
|
|||||||
|
|
||||||
def on_img_delete_activate(self, menu_item):
|
def on_img_delete_activate(self, menu_item):
|
||||||
if self.model.config.confd['delwarn']:
|
if self.model.config.confd['delwarn']:
|
||||||
obj = Dialogs.Qst('Delete image', 'Delete image?',
|
obj = Dialogs.Qst('Delete images', 'Delete selected images?',
|
||||||
'Selected image will be permanently removed from catalog.')
|
'Selected images will be permanently removed from catalog.')
|
||||||
if not obj.run():
|
if not obj.run():
|
||||||
return
|
return
|
||||||
list_of_paths = self.view['images'].get_selected_items()
|
list_of_paths = self.view['images'].get_selected_items()
|
||||||
model = self.view['images'].get_model()
|
model = self.view['images'].get_model()
|
||||||
iter = model.get_iter(list_of_paths[0])
|
for path in list_of_paths:
|
||||||
id = model.get_value(iter, 0)
|
iter = model.get_iter(path)
|
||||||
self.model.delete_image(id)
|
id = model.get_value(iter, 0)
|
||||||
|
self.model.delete_image(id)
|
||||||
|
|
||||||
|
# refresh files tree
|
||||||
|
try:
|
||||||
|
path, column = self.view['files'].get_cursor()
|
||||||
|
model = self.view['files'].get_model()
|
||||||
|
iter = model.get_iter(path)
|
||||||
|
id = model.get_value(iter, 0)
|
||||||
|
self.__get_item_info(id)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.model.unsaved_project = True
|
||||||
|
self.__set_title(filepath=self.model.filename, modified=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
def on_img_save_activate(self, menu_item):
|
||||||
|
"""export images (not thumbnails) into desired direcotry"""
|
||||||
|
dialog = Dialogs.SelectDirectory("Choose directory to save images")
|
||||||
|
filepath = dialog.run()
|
||||||
|
|
||||||
|
if not filepath:
|
||||||
|
return
|
||||||
|
|
||||||
|
list_of_paths = self.view['images'].get_selected_items()
|
||||||
|
model = self.view['images'].get_model()
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
for path in list_of_paths:
|
||||||
|
icon_iter = model.get_iter(path)
|
||||||
|
img_id = model.get_value(icon_iter, 0)
|
||||||
|
if self.model.save_image(img_id, filepath):
|
||||||
|
count += 1
|
||||||
|
if len(list_of_paths) > 0:
|
||||||
|
if count > 0:
|
||||||
|
Dialogs.Inf("Save images",
|
||||||
|
"%d images was succsefully saved." % count,
|
||||||
|
"Images are placed in directory:\n%s." % filepath)
|
||||||
|
else:
|
||||||
|
Dialogs.Inf("Save images",
|
||||||
|
"No images was saved.",
|
||||||
|
"Images probably don't have real images - only" + \
|
||||||
|
" thumbnails.")
|
||||||
|
|
||||||
|
def on_img_delete2_activate(self, menu_item):
|
||||||
|
"""remove images, but keep thumbnails"""
|
||||||
|
if self.model.config.confd['delwarn']:
|
||||||
|
obj = Dialogs.Qst('Delete images', 'Delete selected images?',
|
||||||
|
'Selected images will be permanently removed from ' + \
|
||||||
|
'catalog,\nthumbnails will be keeped.')
|
||||||
|
if not obj.run():
|
||||||
|
return
|
||||||
|
|
||||||
|
list_of_paths = self.view['images'].get_selected_items()
|
||||||
|
model = self.view['images'].get_model()
|
||||||
|
for path in list_of_paths:
|
||||||
|
iter = model.get_iter(path)
|
||||||
|
id = model.get_value(iter, 0)
|
||||||
|
self.model.delete_images_wth_thumbs(id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
path, column = self.view['files'].get_cursor()
|
path, column = self.view['files'].get_cursor()
|
||||||
@@ -1096,6 +1219,7 @@ class MainController(Controller):
|
|||||||
"""Setup IconView images widget."""
|
"""Setup IconView images widget."""
|
||||||
self.view['images'].set_model(self.model.images_store)
|
self.view['images'].set_model(self.model.images_store)
|
||||||
self.view['images'].set_pixbuf_column(1)
|
self.view['images'].set_pixbuf_column(1)
|
||||||
|
self.view['images'].set_selection_mode(gtk.SELECTION_MULTIPLE)
|
||||||
return
|
return
|
||||||
|
|
||||||
def __setup_files_treeview(self):
|
def __setup_files_treeview(self):
|
||||||
@@ -1207,10 +1331,10 @@ class MainController(Controller):
|
|||||||
self.view['recent_files1'].set_submenu(self.recent_menu)
|
self.view['recent_files1'].set_submenu(self.recent_menu)
|
||||||
return
|
return
|
||||||
|
|
||||||
def __get_item_info(self, item):
|
def __get_item_info(self, file_id):
|
||||||
|
|
||||||
buf = gtk.TextBuffer()
|
buf = gtk.TextBuffer()
|
||||||
if not item:
|
if not file_id:
|
||||||
buf.set_text('')
|
buf.set_text('')
|
||||||
self.view['img_container'].hide()
|
self.view['img_container'].hide()
|
||||||
self.view['exifinfo'].hide()
|
self.view['exifinfo'].hide()
|
||||||
@@ -1218,7 +1342,7 @@ class MainController(Controller):
|
|||||||
self.view['description'].set_buffer(buf)
|
self.view['description'].set_buffer(buf)
|
||||||
return
|
return
|
||||||
#self.view['description'].show()
|
#self.view['description'].show()
|
||||||
set = self.model.get_file_info(item)
|
set = self.model.get_file_info(file_id)
|
||||||
|
|
||||||
if __debug__ and 'debug' in set:
|
if __debug__ and 'debug' in set:
|
||||||
tag = buf.create_tag()
|
tag = buf.create_tag()
|
||||||
@@ -1259,14 +1383,16 @@ class MainController(Controller):
|
|||||||
buf.insert_with_tags(buf.get_end_iter(), "Note:\n", tag)
|
buf.insert_with_tags(buf.get_end_iter(), "Note:\n", tag)
|
||||||
buf.insert(buf.get_end_iter(), set['note'])
|
buf.insert(buf.get_end_iter(), set['note'])
|
||||||
|
|
||||||
tags = self.model.get_file_tags(item)
|
tags = self.model.get_file_tags(file_id)
|
||||||
if tags:
|
if tags:
|
||||||
buf.insert(buf.get_end_iter(), "\n")
|
buf.insert(buf.get_end_iter(), "\n")
|
||||||
tag = buf.create_tag()
|
tag = buf.create_tag()
|
||||||
tag.set_property('weight', pango.WEIGHT_BOLD)
|
tag.set_property('weight', pango.WEIGHT_BOLD)
|
||||||
buf.insert_with_tags(buf.get_end_iter(), "File tags:\n", tag)
|
buf.insert_with_tags(buf.get_end_iter(), "File tags:\n", tag)
|
||||||
|
tags = tags.values()
|
||||||
|
tags.sort()
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
buf.insert(buf.get_end_iter(), tags[tag] + ", ")
|
buf.insert(buf.get_end_iter(), tag + ", ")
|
||||||
|
|
||||||
self.view['description'].set_buffer(buf)
|
self.view['description'].set_buffer(buf)
|
||||||
|
|
||||||
@@ -1291,7 +1417,6 @@ class MainController(Controller):
|
|||||||
|
|
||||||
def __tag_cloud(self):
|
def __tag_cloud(self):
|
||||||
"""generate tag cloud"""
|
"""generate tag cloud"""
|
||||||
self.tag_switched = True
|
|
||||||
tag_cloud = self.view['tag_cloud_textview']
|
tag_cloud = self.view['tag_cloud_textview']
|
||||||
self.model.get_tags()
|
self.model.get_tags()
|
||||||
|
|
||||||
@@ -1303,32 +1428,30 @@ class MainController(Controller):
|
|||||||
b_iter = buff.get_end_iter()
|
b_iter = buff.get_end_iter()
|
||||||
return b_iter
|
return b_iter
|
||||||
|
|
||||||
|
buff = tag_cloud.get_buffer()
|
||||||
|
|
||||||
|
# NOTE: remove old tags
|
||||||
|
def foreach_rem(texttag, data):
|
||||||
|
"""remove old tags"""
|
||||||
|
tag_table.remove(texttag)
|
||||||
|
|
||||||
|
tag_table = buff.get_tag_table()
|
||||||
|
while tag_table.get_size() > 0:
|
||||||
|
tag_table.foreach(foreach_rem, None)
|
||||||
|
|
||||||
|
buff.set_text('')
|
||||||
|
|
||||||
if len(self.model.tag_cloud) > 0:
|
if len(self.model.tag_cloud) > 0:
|
||||||
buff = tag_cloud.get_buffer()
|
|
||||||
#buff = gtk.TextBuffer()
|
|
||||||
|
|
||||||
# NOTE: remove old tags
|
|
||||||
tag_table = buff.get_tag_table()
|
|
||||||
|
|
||||||
def rem(texttag, data):
|
|
||||||
tag_table.remove(texttag)
|
|
||||||
tag_table.foreach(rem)
|
|
||||||
tag_table.foreach(rem)
|
|
||||||
buff.set_text('')
|
|
||||||
|
|
||||||
for cloud in self.model.tag_cloud:
|
for cloud in self.model.tag_cloud:
|
||||||
iter = insert_blank(buff, buff.get_end_iter())
|
buff_iter = insert_blank(buff, buff.get_end_iter())
|
||||||
tag = buff.create_tag(str(cloud['id']))
|
try:
|
||||||
tag.set_property('size-points', cloud['size'])
|
tag = buff.create_tag(str(cloud['id']))
|
||||||
tag.set_property('foreground', cloud['color'])
|
tag.set_property('size-points', cloud['size'])
|
||||||
tag.set_property("weight", pango.WEIGHT_NORMAL)
|
#tag.connect('event', self.on_tag_cloud_click, tag)
|
||||||
tag.connect('event', self.on_tag_cloud_click, tag)
|
buff.insert_with_tags(buff_iter,
|
||||||
buff.insert_with_tags(iter,
|
cloud['name'] + "(%d)" % cloud['count'],
|
||||||
cloud['name'] + "(%d)" % cloud['count'],
|
tag)
|
||||||
tag)
|
except:
|
||||||
#tag_cloud.set_buffer(buff)
|
print "fuckup", cloud
|
||||||
|
|
||||||
def __find_tag_in_textview(self, widget, x, y):
|
|
||||||
pass
|
|
||||||
|
|
||||||
pass # end of class
|
pass # end of class
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ class MainModel(ModelMT):
|
|||||||
# Directory tree: id, name, icon, type
|
# Directory tree: id, name, icon, type
|
||||||
self.discs_tree = gtk.TreeStore(gobject.TYPE_INT, gobject.TYPE_STRING,
|
self.discs_tree = gtk.TreeStore(gobject.TYPE_INT, gobject.TYPE_STRING,
|
||||||
str, gobject.TYPE_INT)
|
str, gobject.TYPE_INT)
|
||||||
# File list of selected directory: child_id(?), filename, size,
|
# File list of selected directory: is, filename, size,
|
||||||
# date, type, icon
|
# date, type, icon
|
||||||
self.files_list = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING,
|
self.files_list = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING,
|
||||||
gobject.TYPE_UINT64,
|
gobject.TYPE_UINT64,
|
||||||
@@ -116,8 +116,9 @@ class MainModel(ModelMT):
|
|||||||
self.exif_list = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING,
|
self.exif_list = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING,
|
||||||
gobject.TYPE_STRING)
|
gobject.TYPE_STRING)
|
||||||
|
|
||||||
# tag cloud array element is a dict with 4 keys:
|
# tag cloud array element is a dict with 5 keys:
|
||||||
# elem = {'id': str(id), 'name': tagname, 'size': size, 'color': color}
|
# elem = {'id': str(id), 'name': tagname, 'size': size,
|
||||||
|
# 'count': cout, 'color': color}
|
||||||
# where color is in one of format:
|
# where color is in one of format:
|
||||||
# - named (i.e. red, blue, black and so on)
|
# - named (i.e. red, blue, black and so on)
|
||||||
# - #rgb
|
# - #rgb
|
||||||
@@ -222,7 +223,7 @@ class MainModel(ModelMT):
|
|||||||
"""Calculate 'weight' of tag.
|
"""Calculate 'weight' of tag.
|
||||||
Tags can have sizes between 9 to ~40. Upper size is calculated with
|
Tags can have sizes between 9 to ~40. Upper size is calculated with
|
||||||
logarythm and can take in extereme situation around value 55 like
|
logarythm and can take in extereme situation around value 55 like
|
||||||
for 1 milion tags."""
|
for 1 milion tagged files."""
|
||||||
if not initial_value:
|
if not initial_value:
|
||||||
initial_value = 1
|
initial_value = 1
|
||||||
return 4 * math.log(initial_value, math.e)
|
return 4 * math.log(initial_value, math.e)
|
||||||
@@ -289,6 +290,47 @@ class MainModel(ModelMT):
|
|||||||
self.db_cursor.execute(sql, (file_id,))
|
self.db_cursor.execute(sql, (file_id,))
|
||||||
self.db_connection.commit()
|
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.internal_dirname, res[0])
|
||||||
|
count = 1
|
||||||
|
dest = os.path.join(file_path, res[1] + "_%d." % count + \
|
||||||
|
res[0].split('.')[-1])
|
||||||
|
|
||||||
|
while os.path.exists(dest):
|
||||||
|
count += 1
|
||||||
|
dest = os.path.join(file_path, res[1] + "_%d." % count + \
|
||||||
|
res[0].split('.')[-1])
|
||||||
|
|
||||||
|
shutil.copy(source, dest)
|
||||||
|
return True
|
||||||
|
#os.unlink()
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def delete_images_wth_thumbs(self, image_id):
|
||||||
|
"""removes image (without thumbnail) on specified image id"""
|
||||||
|
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_image(self, image_id):
|
def delete_image(self, image_id):
|
||||||
"""removes image on specified image id"""
|
"""removes image on specified image id"""
|
||||||
sql = """SELECT filename, thumbnail FROM images WHERE id=?"""
|
sql = """SELECT filename, thumbnail FROM images WHERE id=?"""
|
||||||
@@ -355,6 +397,8 @@ class MainModel(ModelMT):
|
|||||||
self.__connect_to_db()
|
self.__connect_to_db()
|
||||||
self.__create_database()
|
self.__create_database()
|
||||||
self.__clear_trees()
|
self.__clear_trees()
|
||||||
|
self.tag_cloud = []
|
||||||
|
self.selected_tags = None
|
||||||
return
|
return
|
||||||
|
|
||||||
def save(self, filename=None):
|
def save(self, filename=None):
|
||||||
@@ -394,7 +438,7 @@ class MainModel(ModelMT):
|
|||||||
print "m_main.py: extracted tarfile into",
|
print "m_main.py: extracted tarfile into",
|
||||||
print self.internal_dirname
|
print self.internal_dirname
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# python's 2.4 tarfile module lacks of method extractall()
|
# python 2.4 tarfile module lacks of method extractall()
|
||||||
directories = []
|
directories = []
|
||||||
for tarinfo in tar:
|
for tarinfo in tar:
|
||||||
if tarinfo.isdir():
|
if tarinfo.isdir():
|
||||||
@@ -450,10 +494,24 @@ class MainModel(ModelMT):
|
|||||||
def rename(self, file_id, new_name=None):
|
def rename(self, file_id, new_name=None):
|
||||||
"""change name of selected object id"""
|
"""change name of selected object id"""
|
||||||
if new_name:
|
if new_name:
|
||||||
|
# do it in DB
|
||||||
self.db_cursor.execute("update files set filename=? \
|
self.db_cursor.execute("update files set filename=? \
|
||||||
WHERE id=?", (new_name, file_id))
|
WHERE id=?", (new_name, file_id))
|
||||||
self.db_connection.commit()
|
self.db_connection.commit()
|
||||||
self.__fetch_db_into_treestore()
|
|
||||||
|
for row in self.files_list:
|
||||||
|
if row[0] == file_id:
|
||||||
|
print row[0], row[1], row[2]
|
||||||
|
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
|
self.unsaved_project = True
|
||||||
else:
|
else:
|
||||||
if __debug__:
|
if __debug__:
|
||||||
|
|||||||
@@ -220,6 +220,42 @@ class PointDirectoryToAdd(object):
|
|||||||
else:
|
else:
|
||||||
return None,None
|
return None,None
|
||||||
|
|
||||||
|
class SelectDirectory(object):
|
||||||
|
"""Sepcific dialog for quering user for selecting directory to add"""
|
||||||
|
|
||||||
|
URI="file://"+os.path.abspath(os.path.curdir)
|
||||||
|
|
||||||
|
def __init__(self, title=None):
|
||||||
|
if title:
|
||||||
|
self.title = title
|
||||||
|
else:
|
||||||
|
self.title = "Choose directory"
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""dialog for point the mountpoint"""
|
||||||
|
dialog = gtk.FileChooserDialog(
|
||||||
|
title = self.title,
|
||||||
|
action = gtk.FILE_CHOOSER_ACTION_OPEN,
|
||||||
|
buttons = (
|
||||||
|
gtk.STOCK_CANCEL,
|
||||||
|
gtk.RESPONSE_CANCEL,
|
||||||
|
gtk.STOCK_OPEN,
|
||||||
|
gtk.RESPONSE_OK))
|
||||||
|
|
||||||
|
dialog.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
|
||||||
|
dialog.set_default_response(gtk.RESPONSE_OK)
|
||||||
|
|
||||||
|
retval = None
|
||||||
|
|
||||||
|
if self.URI:
|
||||||
|
dialog.set_current_folder_uri(self.URI)
|
||||||
|
response = dialog.run()
|
||||||
|
if response == gtk.RESPONSE_OK:
|
||||||
|
retval = dialog.get_filename()
|
||||||
|
self.__class__.URI = dialog.get_current_folder_uri()
|
||||||
|
dialog.destroy()
|
||||||
|
return retval
|
||||||
|
|
||||||
class ChooseDBFilename(object):
|
class ChooseDBFilename(object):
|
||||||
"""Sepcific dialog for quering user for selecting filename for database"""
|
"""Sepcific dialog for quering user for selecting filename for database"""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user