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

Lots of changes, callbacks for gui events, added details and so on

This commit is contained in:
2010-11-07 16:34:26 +01:00
parent 22c24fbaf7
commit 54b6a377bf
11 changed files with 919 additions and 59 deletions

View File

@@ -32,14 +32,17 @@ msgid "Add _Directory"
msgstr "Dodaj kata_log"
#: pygtktalog/views/glade/main.glade.h:6
#: pygtktalog/views/glade/files.glade.h:1
msgid "Add _Images"
msgstr "Dodaj _obrazy"
#: pygtktalog/views/glade/main.glade.h:7
#: pygtktalog/views/glade/files.glade.h:2
msgid "Add _Thumbnail"
msgstr "Dodaj miniaturę"
#: pygtktalog/views/glade/main.glade.h:8
#: pygtktalog/views/glade/files.glade.h:3
msgid ""
"Add images to file. If file have no thumbnail,\n"
"thumbnail from first image will be generated."
@@ -48,182 +51,234 @@ msgstr ""
"zostanie wygenerowana miniatura z pierwszego obrazu."
#: pygtktalog/views/glade/main.glade.h:10
#: pygtktalog/views/glade/main.glade.h:6
msgid "Cancel"
msgstr "Analuj"
#: pygtktalog/views/glade/main.glade.h:11
#: pygtktalog/views/glade/main.glade.h:7
msgid "Catalog _statistics"
msgstr "_Statystyka katalogu"
#: pygtktalog/views/glade/main.glade.h:12
#: pygtktalog/views/glade/discs.glade.h:1
msgid "Collapse all nodes"
msgstr "Zwiń wszystkie gałęzie"
#: pygtktalog/views/glade/main.glade.h:13
#: pygtktalog/views/glade/main.glade.h:8
msgid "Create new catalog"
msgstr "Utwórz nowy katalog"
#: pygtktalog/views/glade/main.glade.h:14
#: pygtktalog/views/glade/main.glade.h:9
msgid "Delete all images"
msgstr "Usuń wszystkie obrazy"
#: pygtktalog/views/glade/main.glade.h:15
#: pygtktalog/views/glade/main.glade.h:10
msgid "Delete all thumbnals"
msgstr "Usuń wszystkie miniatury"
#: pygtktalog/views/glade/main.glade.h:16
#: pygtktalog/views/glade/main.glade.h:11
msgid "Delete tag"
msgstr "Usuń tag"
#: pygtktalog/views/glade/main.glade.h:17
#: pygtktalog/views/glade/main.glade.h:12
msgid "Deletes all images from files in current colection"
msgstr "Usuwa wszystkie obrazy z plików w bieżącej kolekcji"
#: pygtktalog/views/glade/main.glade.h:18
#: pygtktalog/views/glade/main.glade.h:13
msgid "Discs"
msgstr "Dyski"
#: pygtktalog/views/glade/main.glade.h:19
#: pygtktalog/views/glade/details.glade.h:1
msgid "Double click to open image"
msgstr "Dwukrotne kliknięcie otwiera obraz"
#: pygtktalog/views/glade/main.glade.h:20
#: pygtktalog/views/glade/details.glade.h:2
msgid "EXIF"
msgstr "EXIF"
#: pygtktalog/views/glade/main.glade.h:21
#: pygtktalog/views/glade/discs.glade.h:2
msgid "Expand all nodes"
msgstr "Rozwiń wszystkie gałęzie"
#: pygtktalog/views/glade/main.glade.h:22
#: pygtktalog/views/glade/main.glade.h:14
msgid "Export"
msgstr "Eksport"
#: pygtktalog/views/glade/main.glade.h:23
#: pygtktalog/views/glade/details.glade.h:3
msgid "File info"
msgstr "Informacje o pliku"
#: pygtktalog/views/glade/main.glade.h:24
#: pygtktalog/views/glade/main.glade.h:15
msgid "Find file"
msgstr "Znajdź plik"
#: pygtktalog/views/glade/main.glade.h:25
#: pygtktalog/views/glade/details.glade.h:4
msgid "Images"
msgstr "Obrazy"
#: pygtktalog/views/glade/main.glade.h:26
#: pygtktalog/views/glade/main.glade.h:16
msgid "Import"
msgstr "Import"
#: pygtktalog/views/glade/main.glade.h:27
#: pygtktalog/views/glade/main.glade.h:17
msgid "Open catalog file"
msgstr "Otwórz plik katalogu"
#: pygtktalog/views/glade/main.glade.h:28
#: pygtktalog/views/glade/main.glade.h:18
msgid "Quit pyGTKtalog"
msgstr "Zakończ pyGTKtalog"
#: pygtktalog/views/glade/main.glade.h:29
#: pygtktalog/views/glade/files.glade.h:5
msgid "Re_move Thumbnail"
msgstr "Usuń miniaturę"
#: pygtktalog/views/glade/main.glade.h:30
#: pygtktalog/views/glade/main.glade.h:19
msgid "Recent files"
msgstr "Ostatnio używane pliki"
#: pygtktalog/views/glade/main.glade.h:31
#: pygtktalog/views/glade/files.glade.h:6
msgid "Rem_ove All Images"
msgstr "Usuń wszystkie obrazy"
#: pygtktalog/views/glade/main.glade.h:32
#: pygtktalog/views/glade/files.glade.h:7
msgid "Remo_ve tag"
msgstr "Usuń tag"
#: pygtktalog/views/glade/main.glade.h:33
#: pygtktalog/views/glade/main.glade.h:20
msgid "Save all images..."
msgstr "Zapisz wszytkie obrazy..."
#: pygtktalog/views/glade/main.glade.h:34
#: pygtktalog/views/glade/main.glade.h:21
msgid "Save catalog"
msgstr "Zapisz katalog"
#: pygtktalog/views/glade/main.glade.h:35
#: pygtktalog/views/glade/main.glade.h:22
msgid "Set as _thumbnail"
msgstr "Ustaw jako miniaturę"
#: pygtktalog/views/glade/main.glade.h:36
#: pygtktalog/views/glade/main.glade.h:23
msgid "Status bar"
msgstr "Pasek stanu"
#: pygtktalog/views/glade/main.glade.h:37
#: pygtktalog/views/glade/main.glade.h:24
msgid "Tags"
msgstr "Tagi"
#: pygtktalog/views/glade/main.glade.h:38
#: pygtktalog/views/glade/main.glade.h:25
msgid "Toolbar"
msgstr "Pasek narzędzi"
#: pygtktalog/views/glade/main.glade.h:39
#: pygtktalog/views/glade/main.glade.h:26
msgid "_Add images"
msgstr "Dodaj obrazy"
#: pygtktalog/views/glade/main.glade.h:40
#: pygtktalog/views/glade/files.glade.h:8
msgid "_Add tag"
msgstr "_Dodaj tag"
#: pygtktalog/views/glade/main.glade.h:41
#: pygtktalog/views/glade/main.glade.h:27
msgid "_Catalog"
msgstr "_Katalog"
#: pygtktalog/views/glade/main.glade.h:42
#: pygtktalog/views/glade/discs.glade.h:3
msgid "_Collapse all"
msgstr "_Zwiń wszystko"
#: pygtktalog/views/glade/main.glade.h:43
#: pygtktalog/views/glade/discs.glade.h:4
#: pygtktalog/views/glade/files.glade.h:9
msgid "_Delete"
msgstr "_Usuń"
#: pygtktalog/views/glade/main.glade.h:44
#: pygtktalog/views/glade/main.glade.h:28
msgid "_Delete images"
msgstr "Usuń obrazy"
#: pygtktalog/views/glade/main.glade.h:45
#: pygtktalog/views/glade/main.glade.h:29
#: pygtktalog/views/glade/files.glade.h:10
#: pygtktalog/views/glade/test.glade.h:1
msgid "_Edit"
msgstr "_Edycja"
#: pygtktalog/views/glade/main.glade.h:46
#: pygtktalog/views/glade/discs.glade.h:5
msgid "_Expand all"
msgstr "_Rozwiń wszystko"
#: pygtktalog/views/glade/main.glade.h:47
#: pygtktalog/views/glade/main.glade.h:47 pygtktalog/views/main_menu.py:19
#: pygtktalog/views/glade/main.glade.h:30
#: pygtktalog/views/glade/test.glade.h:2
msgid "_File"
msgstr "_Plik"
#: pygtktalog/views/glade/main.glade.h:48
#: pygtktalog/views/glade/main.glade.h:31
#: pygtktalog/views/glade/test.glade.h:3
msgid "_Help"
msgstr "_Pomoc"
#: pygtktalog/views/glade/main.glade.h:49
#: pygtktalog/views/glade/main.glade.h:32
msgid "_Remove Thumbnail"
msgstr "Usuń miniaturę"
#: pygtktalog/views/glade/main.glade.h:50
#: pygtktalog/views/glade/discs.glade.h:6
#: pygtktalog/views/glade/files.glade.h:11
msgid "_Rename"
msgstr "_Zmień nazwę"
#: pygtktalog/views/glade/main.glade.h:51
#: pygtktalog/views/glade/main.glade.h:33
msgid "_Save images to..."
msgstr "Zapisz obrazy do..."
#: pygtktalog/views/glade/main.glade.h:52
#: pygtktalog/views/glade/discs.glade.h:7
msgid "_Statistics"
msgstr "_Statystyka"
#: pygtktalog/views/glade/main.glade.h:53
#: pygtktalog/views/glade/discs.glade.h:8
msgid "_Update"
msgstr "_Uaktualnij"
#: pygtktalog/views/glade/main.glade.h:54
#: pygtktalog/views/glade/main.glade.h:34
#: pygtktalog/views/glade/test.glade.h:4
msgid "_View"
msgstr "_Widok"
@@ -232,10 +287,12 @@ msgid "gtk-clear"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:56
#: pygtktalog/views/glade/main.glade.h:35
msgid "pyGTKtalog"
msgstr "pyGTKtalog"
#: pygtktalog/views/glade/main.glade.h:57
#: pygtktalog/views/glade/main.glade.h:36
msgid "pyGTKtalog - Image"
msgstr "pyGTKtalog - Obraz"
@@ -251,6 +308,68 @@ msgstr "Bieżący katalog nie jest zapisany, wszelkie zmiany zostaną utracone."
msgid "Quit application"
msgstr "Zakończ aplikację"
#: pygtktalog/models/main.py:16
#: pygtktalog/models/main.py:16 pygtktalog/models/main.py:31
msgid "Idle"
msgstr "Bezczynny"
#: pygtktalog/controllers/files.py:33
#, fuzzy
msgid "Disc"
msgstr "Dyski"
#: pygtktalog/controllers/files.py:39
#, fuzzy
msgid "Filename"
msgstr "_Zmień nazwę"
#: pygtktalog/controllers/files.py:50
msgid "Path"
msgstr ""
#: pygtktalog/controllers/files.py:56
msgid "Size"
msgstr ""
#: pygtktalog/controllers/files.py:61
msgid "Date"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:5
msgid "gtk-about"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:6
msgid "gtk-copy"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:7
msgid "gtk-cut"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:8
msgid "gtk-delete"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:9
msgid "gtk-new"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:10
msgid "gtk-open"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:11
msgid "gtk-paste"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:12
msgid "gtk-quit"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:13
msgid "gtk-save"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:14
msgid "gtk-save-as"
msgstr ""

View File

@@ -31,196 +31,251 @@ msgid "Add _Directory"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:6
#: pygtktalog/views/glade/files.glade.h:1
msgid "Add _Images"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:7
#: pygtktalog/views/glade/files.glade.h:2
msgid "Add _Thumbnail"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:8
#: pygtktalog/views/glade/files.glade.h:3
msgid ""
"Add images to file. If file have no thumbnail,\n"
"thumbnail from first image will be generated."
msgstr ""
#: pygtktalog/views/glade/main.glade.h:10
#: pygtktalog/views/glade/main.glade.h:6
msgid "Cancel"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:11
#: pygtktalog/views/glade/main.glade.h:7
msgid "Catalog _statistics"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:12
#: pygtktalog/views/glade/discs.glade.h:1
msgid "Collapse all nodes"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:13
#: pygtktalog/views/glade/main.glade.h:8
msgid "Create new catalog"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:14
#: pygtktalog/views/glade/main.glade.h:9
msgid "Delete all images"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:15
#: pygtktalog/views/glade/main.glade.h:10
msgid "Delete all thumbnals"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:16
#: pygtktalog/views/glade/main.glade.h:11
msgid "Delete tag"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:17
#: pygtktalog/views/glade/main.glade.h:12
msgid "Deletes all images from files in current colection"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:18
#: pygtktalog/views/glade/main.glade.h:13
msgid "Discs"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:19
#: pygtktalog/views/glade/details.glade.h:1
msgid "Double click to open image"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:20
#: pygtktalog/views/glade/details.glade.h:2
msgid "EXIF"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:21
#: pygtktalog/views/glade/discs.glade.h:2
msgid "Expand all nodes"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:22
#: pygtktalog/views/glade/main.glade.h:14
msgid "Export"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:23
#: pygtktalog/views/glade/details.glade.h:3
msgid "File info"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:24
#: pygtktalog/views/glade/main.glade.h:15
msgid "Find file"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:25
#: pygtktalog/views/glade/details.glade.h:4
msgid "Images"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:26
#: pygtktalog/views/glade/main.glade.h:16
msgid "Import"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:27
#: pygtktalog/views/glade/main.glade.h:17
msgid "Open catalog file"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:28
#: pygtktalog/views/glade/main.glade.h:18
msgid "Quit pyGTKtalog"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:29
#: pygtktalog/views/glade/files.glade.h:5
msgid "Re_move Thumbnail"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:30
#: pygtktalog/views/glade/main.glade.h:19
msgid "Recent files"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:31
#: pygtktalog/views/glade/files.glade.h:6
msgid "Rem_ove All Images"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:32
#: pygtktalog/views/glade/files.glade.h:7
msgid "Remo_ve tag"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:33
#: pygtktalog/views/glade/main.glade.h:20
msgid "Save all images..."
msgstr ""
#: pygtktalog/views/glade/main.glade.h:34
#: pygtktalog/views/glade/main.glade.h:21
msgid "Save catalog"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:35
#: pygtktalog/views/glade/main.glade.h:22
msgid "Set as _thumbnail"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:36
#: pygtktalog/views/glade/main.glade.h:23
msgid "Status bar"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:37
#: pygtktalog/views/glade/main.glade.h:24
msgid "Tags"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:38
#: pygtktalog/views/glade/main.glade.h:25
msgid "Toolbar"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:39
#: pygtktalog/views/glade/main.glade.h:26
msgid "_Add images"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:40
#: pygtktalog/views/glade/files.glade.h:8
msgid "_Add tag"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:41
#: pygtktalog/views/glade/main.glade.h:27
msgid "_Catalog"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:42
#: pygtktalog/views/glade/discs.glade.h:3
msgid "_Collapse all"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:43
#: pygtktalog/views/glade/discs.glade.h:4
#: pygtktalog/views/glade/files.glade.h:9
msgid "_Delete"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:44
#: pygtktalog/views/glade/main.glade.h:28
msgid "_Delete images"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:45
#: pygtktalog/views/glade/main.glade.h:29
#: pygtktalog/views/glade/files.glade.h:10
#: pygtktalog/views/glade/test.glade.h:1
msgid "_Edit"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:46
#: pygtktalog/views/glade/discs.glade.h:5
msgid "_Expand all"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:47
#: pygtktalog/views/glade/main.glade.h:47 pygtktalog/views/main_menu.py:19
#: pygtktalog/views/glade/main.glade.h:30
#: pygtktalog/views/glade/test.glade.h:2
msgid "_File"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:48
#: pygtktalog/views/glade/main.glade.h:31
#: pygtktalog/views/glade/test.glade.h:3
msgid "_Help"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:49
#: pygtktalog/views/glade/main.glade.h:32
msgid "_Remove Thumbnail"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:50
#: pygtktalog/views/glade/discs.glade.h:6
#: pygtktalog/views/glade/files.glade.h:11
msgid "_Rename"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:51
#: pygtktalog/views/glade/main.glade.h:33
msgid "_Save images to..."
msgstr ""
#: pygtktalog/views/glade/main.glade.h:52
#: pygtktalog/views/glade/discs.glade.h:7
msgid "_Statistics"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:53
#: pygtktalog/views/glade/discs.glade.h:8
msgid "_Update"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:54
#: pygtktalog/views/glade/main.glade.h:34
#: pygtktalog/views/glade/test.glade.h:4
msgid "_View"
msgstr ""
@@ -229,10 +284,12 @@ msgid "gtk-clear"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:56
#: pygtktalog/views/glade/main.glade.h:35
msgid "pyGTKtalog"
msgstr ""
#: pygtktalog/views/glade/main.glade.h:57
#: pygtktalog/views/glade/main.glade.h:36
msgid "pyGTKtalog - Image"
msgstr ""
@@ -248,6 +305,66 @@ msgstr ""
msgid "Quit application"
msgstr ""
#: pygtktalog/models/main.py:16
#: pygtktalog/models/main.py:16 pygtktalog/models/main.py:31
msgid "Idle"
msgstr ""
#: pygtktalog/controllers/files.py:33
msgid "Disc"
msgstr ""
#: pygtktalog/controllers/files.py:39
msgid "Filename"
msgstr ""
#: pygtktalog/controllers/files.py:50
msgid "Path"
msgstr ""
#: pygtktalog/controllers/files.py:56
msgid "Size"
msgstr ""
#: pygtktalog/controllers/files.py:61
msgid "Date"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:5
msgid "gtk-about"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:6
msgid "gtk-copy"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:7
msgid "gtk-cut"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:8
msgid "gtk-delete"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:9
msgid "gtk-new"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:10
msgid "gtk-open"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:11
msgid "gtk-paste"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:12
msgid "gtk-quit"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:13
msgid "gtk-save"
msgstr ""
#: pygtktalog/views/glade/test.glade.h:14
msgid "gtk-save-as"
msgstr ""

View File

@@ -9,6 +9,11 @@ import gtk
from gtkmvc import Controller
from pygtktalog.pygtkutils import get_tv_item_under_cursor
from pygtktalog.logger import get_logger
LOG = get_logger("files ctrl")
class FilesController(Controller):
"""
@@ -28,6 +33,20 @@ class FilesController(Controller):
Register view, and setup columns for files treeview
"""
view['files'].set_model(self.model.files)
sigs = {"add_tag": ("activate", self.on_add_tag1_activate),
"delete_tag": ("activate", self.on_delete_tag_activate),
"add_thumb": ("activate", self.on_add_thumb1_activate),
"remove_thumb": ("activate", self.on_remove_thumb1_activate),
"add_image": ("activate", self.on_add_image1_activate),
"remove_image": ("activate", self.on_remove_image1_activate),
"edit": ("activate", self.on_edit2_activate),
"delete": ("activate", self.on_delete3_activate),
"rename": ("activate", self.on_rename2_activate)}
for signal in sigs:
view.menu[signal].connect(sigs[signal][0], sigs[signal][1])
view['files'].get_selection().set_mode(gtk.SELECTION_MULTIPLE)
col = gtk.TreeViewColumn(_('Disc'), gtk.CellRendererText(), text=1)
@@ -65,7 +84,178 @@ class FilesController(Controller):
self.view['files'].set_search_column(2)
# setup d'n'd support
view['files'].drag_source_set(gtk.gdk.BUTTON1_MASK,
self.view['files'].drag_source_set(gtk.gdk.BUTTON1_MASK,
self.DND_TARGETS,
gtk.gdk.ACTION_COPY)
# signals
def on_files_drag_data_get(self, treeview, context, selection,
targetType, eventTime):
"""responce to "data get" DnD signal"""
# get selection, and send it to the client
if targetType == self.DND_TARGETS[0][2]:
# get selection
treesrl = treeview.get_selection()
model, list_of_paths = treesrl.get_selected_rows()
ids = []
for path in list_of_paths:
fid = model.get_value(model.get_iter(path), 0)
ids.append(fid)
string = str(tuple(ids)).replace(",)", ")")
selection.set(selection.target, 8, string)
def on_files_button_press_event(self, treeview, event):
"""
Handle right click on files treeview - show popup menu.
"""
LOG.debug(self.on_files_button_press_event.__doc__.strip())
pathinfo = treeview.get_path_at_pos(int(event.x), int(event.y))
if event.button == 3: # Right mouse button. Show context menu.
if pathinfo:
path = pathinfo[0]
# 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)
else:
self._popup_menu(None, event, event.button)
return True
#try:
# selection = tree.get_selection()
# model, list_of_paths = selection.get_selected_rows()
#except TypeError:
# list_of_paths = []
#if len(list_of_paths) == 0:
# # try to select item under cursor
# try:
# path, column, x, y = tree.get_path_at_pos(int(event.x),
# int(event.y))
# except TypeError:
# # failed, do not show any popup and return
# tree.get_selection().unselect_all()
# return False
# selection.select_path(path[0])
#if len(list_of_paths) > 1:
# self.view['add_image'].set_sensitive(False)
# self.view['rename'].set_sensitive(False)
# self.view['edit'].set_sensitive(False)
#else:
# self.view['add_image'].set_sensitive(True)
# self.view['rename'].set_sensitive(True)
# self.view['edit'].set_sensitive(True)
#self.__popup_menu(event, 'files_popup')
#return True
def on_files_cursor_changed(self, treeview):
"""Show details of selected file/directory"""
file_id = get_tv_item_under_cursor(treeview)
LOG.debug("found item: %s" % file_id)
return
def on_files_key_release_event(self, treeview, event):
"""do something with pressed keys"""
if gtk.gdk.keyval_name(event.keyval) == 'Menu':
try:
selection = treeview.get_selection()
model, list_of_paths = selection.get_selected_rows()
if not list_of_paths:
return
except TypeError:
return
self._popup_menu(selection, event, 0)
if gtk.gdk.keyval_name(event.keyval) == 'BackSpace':
d_path, d_column = self.view['discs'].get_cursor()
if d_path and d_column:
# easy way
model = self.view['discs'].get_model()
child_iter = model.get_iter(d_path)
parent_iter = model.iter_parent(child_iter)
if parent_iter:
self.view['discs'].set_cursor(model.get_path(parent_iter))
else:
# hard way
f_model = treeview.get_model()
first_iter = f_model.get_iter_first()
first_child_value = f_model.get_value(first_iter, 0)
# get two steps up
val = self.model.get_parent_id(first_child_value)
parent_value = self.model.get_parent_id(val)
iter = self.model.discs_tree.get_iter_first()
while iter:
current_value = self.model.discs_tree.get_value(iter,
0)
if current_value == parent_value:
path = self.model.discs_tree.get_path(iter)
self.view['discs'].set_cursor(path)
iter = None
else:
iter = self.model.discs_tree.iter_next(iter)
#if gtk.gdk.keyval_name(event.keyval) == 'Delete':
# for file_id in self.__get_tv_selection_ids(treeview):
# self.main.delete(file_id)
#ids = self.__get_tv_selection_ids(self.view['files'])
def on_files_row_activated(self, files_obj, row, column):
"""On directory doubleclick in files listview dive into desired
branch."""
f_iter = self.model.files_list.get_iter(row)
current_id = self.model.files_list.get_value(f_iter, 0)
if self.model.files_list.get_value(f_iter, 6) == 1:
# ONLY directories. files are omitted.
self.__set_files_hiden_columns_visible(False)
self.model.get_root_entries(current_id)
d_path, d_column = self.view['discs'].get_cursor()
if d_path:
if not self.view['discs'].row_expanded(d_path):
self.view['discs'].expand_row(d_path, False)
discs_model = self.model.discs_tree
iterator = discs_model.get_iter(d_path)
new_iter = discs_model.iter_children(iterator)
if new_iter:
while new_iter:
current_value = discs_model.get_value(new_iter, 0)
if current_value == current_id:
path = discs_model.get_path(new_iter)
self.view['discs'].set_cursor(path)
new_iter = discs_model.iter_next(new_iter)
return
def on_add_tag1_activate(self, menu_item): pass
def on_delete_tag_activate(self, menuitem): pass
def on_add_thumb1_activate(self, menuitem): pass
def on_remove_thumb1_activate(self, menuitem): pass
def on_add_image1_activate(self, menuitem): pass
def on_remove_image1_activate(self, menuitem): pass
def on_edit2_activate(self, menuitem): pass
def on_delete3_activate(self, menuitem): pass
def on_rename2_activate(self, menuitem): pass
# private methods
def _popup_menu(self, selection, event, button):
"""
Popup menu for files treeview. Gather information from discs model,
and trigger menu popup.
"""
LOG.debug(self._popup_menu.__doc__.strip())
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_menu_items_sensitivity(True)
self.view.menu['files_popup'].popup(None, None, None,
button, event.time)

View File

@@ -9,15 +9,17 @@ import gtk
from gtkmvc import Controller
#from pygtktalog.dialogs import yesno
from pygtktalog.dialogs import About
from pygtktalog.controllers.discs import DiscsController
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
from pygtktalog.dialogs import open_catalog, save_catalog, error, yesno
from pygtktalog.dialogs import About # TODO: how about make it like a functions above?
from pygtktalog.logger import get_logger
from pygtktalog import __version__
# although it seems to be unused, it is necessary, because it contains
# definitions for additional connectable widgets for observers.
LOG = get_logger("main controller")
@@ -25,6 +27,8 @@ class MainController(Controller):
"""
Controller for main application window
"""
TITLE = "pyGTKtalog"
UNTITLED = _("untitled")
def __init__(self, model, view):
"""
@@ -48,6 +52,8 @@ class MainController(Controller):
LOG.debug("replace hardcoded defaults with configured!")
view['main'].set_default_size(800, 600)
view['hpaned1'].set_position(200)
if not self.model.tmp_filename:
view.set_widgets_app_sensitivity(False)
view['main'].show()
def register_adapters(self):
@@ -55,6 +61,10 @@ class MainController(Controller):
progress bar/status bar adapters goes here
"""
LOG.debug(self.register_adapters.__doc__.strip())
#title_ad = Adapter(self.model, "cat_fname")
#title_ad.connect_widget(self.view["main"],
# setter=lambda w,v: \
# w.set_title(self._get_title()))
pass
# signals
@@ -79,10 +89,123 @@ class MainController(Controller):
gtk.main_quit()
return False
def on_new_activate(self, widget):
"""
Create new catalog file
"""
LOG.debug(self.on_new_activate.__doc__.strip())
self.model.new()
self.view.discs['discs'].set_model(self.model.discs)
self.view.files['files'].set_model(self.model.files)
self._set_title()
self.view.set_widgets_app_sensitivity(True)
def on_open_activate(self, widget):
"""
Open catalog file
"""
LOG.debug(self.on_open_activate.__doc__.strip())
if self.model.db_unsaved and 'confirm' in self.model.config and \
self.model.config['confirm']:
if not yesno(_("Current database is not saved"),
_("Do you really want to open new file and abandon "
"current one?"),
_("Unsaved data")):
LOG.debug("Cancel opening catalog file - unsaved data remain")
return
initial_path = None
#if self.model.config.recent and self.model.config.recent[0]:
# initial_path = os.path.dirname(self.model.config.recent[0])
#if not path:
path = open_catalog(path=initial_path)
if not path:
return
# cleanup files and details
try:
self.model.files_list.clear()
except:
pass
#self.__hide_details()
#self.view['tag_path_box'].hide()
#buf = self.view['tag_cloud_textview'].get_buffer()
#buf.set_text('')
#self.view['tag_cloud_textview'].set_buffer(buf)
if not self.model.open(path):
error(_("Cannot open file."),
_("File %s cannot be open") % path,
_("Error opening file"))
else:
#self.__generate_recent_menu()
#self.__activate_ui(path)
#self.__tag_cloud()
self.view.set_widgets_app_sensitivity()
self._set_title()
return
def on_about1_activate(self, widget):
"""Show about dialog"""
About("pyGTKtalog",
"%s" % __version__,
"About",
["Roman 'gryf' Dobosz"],
'')
About("pyGTKtalog", "%s" % __version__, "About",
["Roman 'gryf' Dobosz"], '')
def on_save_activate(self, widget):
"""
Save current catalog
"""
LOG.debug(self.on_save_activate.__doc__.strip())
if not self.model.cat_fname:
self.on_save_as_activate(widget)
else:
self.model.save()
self._set_title()
def on_save_as_activate(self, widget):
"""
Save current catalog under differnet file
"""
LOG.debug(self.on_save_as_activate.__doc__.strip())
initial_path = None
#if self.model.config.recent[0]:
# initial_path = os.path.dirname(self.model.config.recent[0])
path = save_catalog(path=initial_path)
if path:
ret, err = self.model.save(path)
if ret:
#self.model.config.add_recent(path)
self._set_title()
pass
else:
error(_("Cannot write file %s.") % path,
"%s" % err,
_("Error writing file"))
# helpers
def _set_title(self):
"""
Get title of the main window, to reflect state of the catalog file
Returns:
String with apropriate title for main form
"""
LOG.debug("change the title")
if not self.model.tmp_filename:
LOG.debug("application has been initialized, title should"
" be empty")
fname = ""
elif not self.model.cat_fname:
fname = self.UNTITLED
else:
fname = self.model.cat_fname
modified = self.model.db_unsaved and "*" or ""
self.view['main'].set_title("%s%s - %s" % (fname,
modified, self.TITLE))

View File

@@ -22,6 +22,8 @@ Meta = MetaData()
Base = declarative_base(metadata=Meta)
Session = sessionmaker()
LOG = get_logger("dbcommon")
def connect(filename):
"""
@@ -30,8 +32,7 @@ def connect(filename):
@filename - string with absolute or relative path to sqlite database
file.
"""
get_logger("dbcommon").info("db filename: %s" % filename)
LOG.info("db filename: %s" % filename)
engine = create_engine("sqlite:///%s" % filename)
Meta.bind = engine
Meta.create_all()
Meta.create_all(engine)

View File

@@ -5,13 +5,15 @@
Author: Roman 'gryf' Dobosz, gryf73@gmail.com
Created: 2009-05-12
"""
import os
import gtk
class Dialog(object):
"""Show simple dialog for questions
if "OK" button pressed, return "True"
"Cancel" button return "False"
"""
Show simple dialog for questions
Returns: Bool - True, if "OK" button pressed, False otherwise.
"""
def __init__(self, dialog_type, message, secondary_msg="", title=""):
@@ -29,7 +31,7 @@ class Dialog(object):
def run(self):
"""Show the dialog"""
if self.dialog is None:
self.__create_dialog()
self._create_dialog()
# Change default/focus from cancel/no to ok/yes. Suitable only for
# Question dialog.
@@ -45,7 +47,7 @@ class Dialog(object):
return True
return False
def __create_dialog(self):
def _create_dialog(self):
"""Create MessageDialog widgt"""
if self.type == gtk.MESSAGE_QUESTION and \
self.buttons not in (gtk.BUTTONS_YES_NO, gtk.BUTTONS_OK_CANCEL):
@@ -60,7 +62,7 @@ class About(object):
"""
Show About dialog
"""
def __init__(self, name=None, ver="", title="", authors=[],licence=""):
def __init__(self, name=None, ver="", title="", authors=[], licence=""):
self.dialog = gtk.AboutDialog()
self.dialog.set_title(title)
self.dialog.set_version(ver)
@@ -74,6 +76,90 @@ class About(object):
# TODO: finish this, re-use Dialog class instead of copy/paste of old classes!
# def about(name, version, )
class ChooseFile(object):
"""
Common file chooser
"""
URI = None
BUTTON_PAIRS = {'cancel': (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
'ok': (gtk.STOCK_OK, gtk.RESPONSE_APPLY),
'save': (gtk.STOCK_SAVE, gtk.RESPONSE_APPLY),
'open': (gtk.STOCK_OPEN, gtk.RESPONSE_APPLY)}
CHOOSER_TYPES = {'open': gtk.FILE_CHOOSER_ACTION_OPEN,
'save': gtk.FILE_CHOOSER_ACTION_SAVE}
FILTERS = {'catalogs': {'name': "Catalog files",
'patterns': ("*.sqlite", "*.sqlite.bz2")},
'all': {'name': "All files", 'patterns': ("*.*",)}}
def __init__(self, title="", buttons=('cancel', 'ok'), path=None,
chooser_type="open"):
super(ChooseFile, self).__init__()
self.path = path
self.title = title
self.action = self.CHOOSER_TYPES[chooser_type]
self.buttons=[]
for button in buttons:
self.buttons.append(self.BUTTON_PAIRS[button][0])
self.buttons.append(self.BUTTON_PAIRS[button][1])
self.buttons = tuple(self.buttons)
self.confirmation = False
self.dialog = None
self.filters = []
def _mk_dialog(self):
"""
Create FileChooserDialog object
"""
self.dialog = gtk.FileChooserDialog(self.title, None, self.action,
self.buttons)
self.dialog.set_action(gtk.FILE_CHOOSER_ACTION_SAVE)
self.dialog.set_default_response(gtk.RESPONSE_OK)
self.dialog.set_do_overwrite_confirmation(self.confirmation)
self.dialog.set_title(self.title)
if self.URI:
self.dialog.set_current_folder_uri(self.URI)
elif self.path and os.path.exists(self.path):
self.path = "file://"+os.path.abspath(self.path)
self.dialog.set_current_folder_uri(self.path)
for filtr in self._get_filters():
self.dialog.add_filter(filtr)
def _get_filters(self):
"""
"""
filters = []
for filter_def in self.filters:
filtr = gtk.FileFilter()
filtr.set_name(self.FILTERS[filter_def]['name'])
for pat in self.FILTERS[filter_def]['patterns']:
filtr.add_pattern(pat)
filters.append(filtr)
return filters
def run(self):
"""
Show dialog, get response.
Returns:
Returns: String - with filename, None otherwise.
"""
if self.dialog is None:
self._mk_dialog()
response = self.dialog.run()
filename = None
if response == gtk.RESPONSE_APPLY:
filename = self.dialog.get_filename()
self.__class__.URI = self.dialog.get_current_folder_uri()
self.dialog.destroy()
return filename
def yesno(message, secondarymsg="", title="", default=False):
"""Question with yes-no buttons. Returns False on 'no', True on 'yes'"""
dialog = Dialog(gtk.MESSAGE_QUESTION, message, secondarymsg, title)
@@ -116,3 +202,21 @@ def error(message, secondarymsg="", title="", button=gtk.BUTTONS_OK):
dialog.run()
return True
def open_catalog(title=_("Open catalog"), path=None):
"""
Request filename from user to open.
Returns: string - full path and filename or None
"""
requester = ChooseFile(title)
requester.filters = ['catalogs', 'all']
return requester.run()
def save_catalog(title=_("Open catalog"), path=None):
"""
Request filename from user for save.
Returns: string - full path and filename or None
"""
requester = ChooseFile(title, chooser_type="save")
requester.filters = ['catalogs', 'all']
requester.confirmation = True
return requester.run()

View File

@@ -40,12 +40,11 @@ def get_logger(module_name, level=None, to_file=False):
if to_file:
log_handler = logging.FileHandler(path)
formatter = logging.Formatter("%(asctime)s %(filename)s:%(lineno) - "
"%(name)s - %(levelname)s - "
"%(message)s")
formatter = logging.Formatter("%(asctime)s %(filename)s:%(lineno)s - "
"%(levelname)s - %(message)s")
else:
log_handler = logging.StreamHandler(sys.stderr)
formatter = logging.Formatter("%(name)s - %(filename)s:%(lineno)s - "
formatter = logging.Formatter("%(filename)s:%(lineno)s - "
"%(levelname)s - %(message)s")
log_handler.setFormatter(formatter)

View File

@@ -13,6 +13,7 @@ from tempfile import mkstemp
import gtk
import gobject
from gtkmvc import ModelMT
from sqlalchemy import create_engine
from pygtktalog.dbobjects import File, Exif, Group, Gthumb
from pygtktalog.dbobjects import Image, Tag, Thumbnail
@@ -45,17 +46,38 @@ class MainModel(ModelMT):
self.cat_fname = filename
# Temporary (usually in /tmp) working database.
self.tmp_filename = None
self.config = {}
# SQLAlchemy session object for internal use
self._session = None
# Flag indicates, that db was compressed
# TODO: make it depend on configuration
self.compressed = False
self.db_unsaved = False
self.db_unsaved = None
self.discs = None
self.files = None
self._init_discs()
self._init_files()
if self.cat_fname:
self.open(self.cat_fname)
def _init_discs(self):
"""
Create TreeStore model for the discs
"""
self.discs = gtk.TreeStore(gobject.TYPE_PYOBJECT,
gobject.TYPE_STRING,
str)
def _init_files(self):
"""
Create ListStore model for the diles
"""
self.files = gtk.ListStore(gobject.TYPE_PYOBJECT,
gobject.TYPE_STRING,
gobject.TYPE_STRING,
@@ -64,8 +86,6 @@ class MainModel(ModelMT):
gobject.TYPE_STRING,
gobject.TYPE_INT,
str)
if self.cat_fname:
self.open(self.cat_fname)
def open(self, filename):
"""
@@ -87,12 +107,45 @@ class MainModel(ModelMT):
else:
return False
def save(self, filename=None):
"""
Save tared directory at given catalog fielname
Arguments:
@filename - see MainModel __init__ docstring.
Returns: tuple:
Bool - true for success, false otherwise.
String or None - error message
"""
if not filename and not self.cat_fname:
LOG.debug("no filename detected!")
return False, None
if filename:
if not '.sqlite' in filename:
filename += '.sqlite'
else:
filename = filename[:filename.rindex('.sqlite')] + '.sqlite'
if 'compress' in self.config and self.config['compress']:
filename += '.bz2'
self.cat_fname = filename
val, err = self._compress_and_save()
if not val:
self.cat_fname = None
return val, err
def new(self):
"""
Create new catalog
"""
self.cleanup()
self._create_temp_db_file()
self._create_schema()
self._init_discs()
self._init_files()
self.db_unsaved = False
def cleanup(self):
"""
@@ -108,20 +161,13 @@ class MainModel(ModelMT):
try:
os.unlink(self.tmp_filename)
LOG.debug("file %s succesfully deleted", self.tmp_filename)
except OSError:
LOG.exception("temporary db file doesn't exists!")
LOG.error("temporary db file doesn't exists!")
except TypeError:
# TODO: file not exist - create? print error message?
LOG.exception("temporary db file doesn't exists!")
def _create_empty_db(self):
"""
Create new DB
"""
self.cleanup()
self._create_temp_db_file()
# TODO: file does not exist - create? print error message?
LOG.error("temporary db file doesn't exists!")
else:
LOG.debug("file %s succesfully deleted", self.tmp_filename)
def _examine_file(self, filename):
"""
@@ -179,7 +225,7 @@ class MainModel(ModelMT):
open_file.close()
except IOError:
self.cleanup()
self.filename = None
self.cat_fname = None
self.internal_dirname = None
LOG.exception("File is probably not a bz2!")
return False
@@ -195,7 +241,7 @@ class MainModel(ModelMT):
LOG.error("Error opening file '%s' - not a catalog file!",
self.tmp_filename)
self.cleanup()
self.filename = None
self.cat_fname = None
self.internal_dirname = None
return False
@@ -204,11 +250,33 @@ class MainModel(ModelMT):
return True
def _create_temp_db_file(self):
"""
Create new DB file, populate schema.
"""
fd, self.tmp_filename = mkstemp()
LOG.debug("new db filename: %s" % self.tmp_filename)
# close file descriptor, otherwise it can be source of app crash!
# http://www.logilab.org/blogentry/17873
os.close(fd)
def _create_schema(self):
"""
"""
self._session = Session()
connect(os.path.abspath(self.tmp_filename))
root = File()
root.id = 1
root.filename = 'root'
root.size = 0
root.source = 0
root.type = 0
root.parent_id = 1
self._session.add(root)
self._session.commit()
def _populate_discs_from_db(self):
"""
Read objects from database, fill TreeStore model with discs
@@ -222,7 +290,7 @@ class MainModel(ModelMT):
Get all children of the selected parent.
Arguments:
@parent_id - integer with id of the parent (from db)
@iterator - TODO
@iterator - gtk.TreeIter, which points to a path inside model
"""
for fileob in dirs:
if fileob.parent_id == parent_id:
@@ -263,5 +331,30 @@ class MainModel(ModelMT):
self.files.set_value(myiter, 7, gtk.STOCK_DIRECTORY \
if child.type==1 else gtk.STOCK_FILE)
def _compress_and_save(self):
"""
Create (and optionaly compress) tar archive from working directory and
write it to specified file.
"""
# flush all changes
self._session.commit()
try:
if 'compress' in self.config and self.config['compress']:
output_file = bz2.BZ2File(self.cat_fname, "w")
else:
output_file = open(self.cat_fname, "w")
LOG.debug("save (and optionally compress) successed")
except IOError, (errno, strerror):
LOG.error("error saving or compressing file", errno, strerror)
return False, strerror
dbpath = open(self.tmp_filename)
output_file.write(dbpath.read())
dbpath.close()
output_file.close()
self.db_unsaved = False
return True, None

25
pygtktalog/pygtkutils.py Normal file
View File

@@ -0,0 +1,25 @@
"""
Project: pyGTKtalog
Description: pyGTK common utility functions
Type: tility
Author: Roman 'gryf' Dobosz, gryf73@gmail.com
Created: 2010-11-07 13:30:37
"""
def get_tv_item_under_cursor(treeview):
"""
Get item (most probably id of the row) form tree view under cursor.
Arguments:
@treeview - gtk.TreeView
Returns:
Item in first column of TreeModel, which TreeView is connected with,
None in other cases
"""
path, column = treeview.get_cursor()
if path and column:
model = treeview.get_model()
tm_iter = model.get_iter(path)
item_id = model.get_value(tm_iter, 0)
return item_id
return None

View File

@@ -12,6 +12,7 @@ import shutil
from tempfile import mkdtemp, mkstemp
import math
import Image
from pygtktalog.misc import float_to_string
@@ -21,9 +22,15 @@ class Video(object):
Midentify script belongs to mplayer package.
"""
def __init__(self, filename):
"""Init class instance. Filename of a video file is required."""
def __init__(self, filename, out_width=1024):
"""
Init class instance.
Arguments:
@filename - Filename of a video file (required).
@out_width - width of final image to be scaled to.
"""
self.filename = filename
self.out_width = out_width
self.tags = {}
output = self.__get_movie_info()
@@ -52,14 +59,12 @@ class Video(object):
length_str = "%02d:%02d:%02d" % (hours, minutes, seconds)
self.tags['duration'] = length_str
def capture(self, out_width=1024):
def capture(self):
"""
Extract images for given video filename and montage it into one, big
picture, similar to output from Windows Media Player thing, but without
captions and time (who need it anyway?).
Arguments:
@out_width - width of generated image. If actual image width
exceeds this number scale is performed.
Returns: image filename or None
NOTE: You should remove returned file manually, or move it in some
@@ -93,7 +98,7 @@ class Video(object):
file_desc, image_fn = mkstemp()
os.close(file_desc)
self.__make_captures(tempdir, no_pictures)
self.__make_montage(tempdir, image_fn, no_pictures, out_width)
self.__make_montage(tempdir, image_fn, no_pictures, self.out_width)
shutil.rmtree(tempdir)
return image_fn
@@ -149,26 +154,71 @@ class Video(object):
shutil.move(os.path.join(directory, "00000001.jpg"),
os.path.join(directory, "picture_%s.jpg" % time))
def __make_montage(self, directory, image_fn, no_pictures, out_width):
def __make_montage2(self, directory, image_fn, no_pictures):
"""
Generate one big image from screnshots and optionally resize it.
Arguments:
@directory - source directory containing images
@image_fn - destination final image
@no_pictures - number of pictures
@out_width - width of final image to be scaled to.
"""
scale = False
row_length = 4
if no_pictures < 8:
row_length = 2
if (self.tags['width'] * row_length) > out_width:
if (self.tags['width'] * row_length) > self.out_width:
scale = True
else:
for i in [8, 6, 5]:
if (no_pictures % i) == 0 and \
(i * self.tags['width']) <= out_width:
(i * self.tags['width']) <= self.out_width:
row_length = i
break
tile = "%dx%d" % (row_length, no_pictures / row_length)
_curdir = os.path.abspath(os.path.curdir)
os.chdir(directory)
# composite pictures
# readlines trick will make to wait for process end
#cmd = "montage -tile %s -geometry +2+2 picture_*.jpg montage.jpg"
imgs = [Image.open(fn).resize((photow,photoh)) for fn in fnames]
os.popen(cmd % tile).readlines()
# scale it to minimum 'modern' width: 1024
if scale:
cmd = "convert -scale %s montage.jpg montage_scaled.jpg"
os.popen(cmd % out_width).readlines()
shutil.move(os.path.join(directory, 'montage_scaled.jpg'),
image_fn)
else:
shutil.move(os.path.join(directory, 'montage.jpg'),
image_fn)
os.chdir(_curdir)
def __make_montage(self, directory, image_fn, no_pictures):
"""
Generate one big image from screnshots and optionally resize it.
Arguments:
@directory - source directory containing images
@image_fn - destination final image
@no_pictures - number of pictures
"""
scale = False
row_length = 4
if no_pictures < 8:
row_length = 2
if (self.tags['width'] * row_length) > self.out_width:
scale = True
else:
for i in [8, 6, 5]:
if (no_pictures % i) == 0 and \
(i * self.tags['width']) <= self.ut_width:
row_length = i
break
@@ -185,7 +235,7 @@ class Video(object):
# scale it to minimum 'modern' width: 1024
if scale:
cmd = "convert -scale %s montage.jpg montage_scaled.jpg"
os.popen(cmd % out_width).readlines()
os.popen(cmd % self.out_width).readlines()
shutil.move(os.path.join(directory, 'montage_scaled.jpg'),
image_fn)
else:

View File

@@ -30,14 +30,20 @@ class MainView(View):
Initialize view
"""
View.__init__(self)
self.app_sensitive = None
self['tag_path_box'].hide()
self.discs = DiscsView()
#self['scrolledwindow_discs'].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())
self['scrolledwindow_files'].add_with_viewport(\
self.files.get_top_widget())
self.details = DetailsView()
self['vpaned1'].add2(self.details.get_top_widget())
def set_widgets_scan_sensitivity(self, sensitive=True):
"""
@@ -45,6 +51,23 @@ class MainView(View):
"""
pass
def set_widgets_app_sensitivity(self, sensitive=True):
"""
Enable/disable widgets for empty application. Usefull for first run
of an application (without any db filename as an argument).
"""
if self.app_sensitive is sensitive:
return
for widget in ['scrolledwindow_discs', 'scrolledwindow_files',
'tb_save', 'tb_addcd', 'tb_adddir', 'tb_find',
'edit1', 'catalog1', 'save1', 'save_as1', 'import',
'export']:
self[widget].set_sensitive(sensitive)
# widgets from subclasses
self.details['notebook_details'].set_sensitive(sensitive)
class DiscsView(View):
"""
@@ -94,6 +117,7 @@ class DiscsPopupView(View):
for item in ['update', 'rename', 'delete', 'statistics']:
self[item].set_sensitive(state)
class FilesView(View):
"""
Separate subview of Files TreeView as a table.
@@ -106,6 +130,8 @@ class FilesView(View):
Initialize view
"""
View.__init__(self)
self.menu = FilesPopupView()
class FilesPopupView(View):
"""
@@ -120,6 +146,19 @@ class FilesPopupView(View):
"""
View.__init__(self)
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 ["add_tag", "delete_tag", "add_thumb", "remove_thumb",
"add_image", "remove_image", "edit", "delete", "rename"]:
self[item].set_sensitive(state)
class TagcloudView(View):
"""
Textview subview with clickable tags.