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

Early design for separating main classes into smaller parts. Added logger module.

This commit is contained in:
2010-04-28 21:55:49 +02:00
parent 9b7f15122d
commit dbb01acd3f
14 changed files with 547 additions and 384 deletions

152
README
View File

@@ -1,37 +1,40 @@
pyGTKtalog 1.9 pyGTKtalog
============== ==========
pyGTKtalog is Linux/FreeBSD program for indexing CD/DVD or directories on pyGTKtalog is Linux/FreeBSD program for indexing CD/DVD or directories on
filesystem. It is similar to gtktalog <http://www.nongnu.org/gtktalog/> or filesystem. It is similar to `gtktalog <http://www.nongnu.org/gtktalog/>`_ or
gwhere <http://www.gwhere.org/home.php3>. There is no coincidence in name of `gwhere <http://www.gwhere.org/home.php3>`_. There is no coincidence in name of
application, because it's ment to be replacement (in some way) for gtktalog, application, because it's ment to be replacement (in some way) for gtktalog,
which seems to be dead project for years. which seems to be dead project for years.
FEATURES Current version is 1.9.
========
- scan for files in selected media FEATURES
- get/generate thumbnails from exif and other images --------
- most important exif tags
- add/edit description and notes * scan for files in selected media
- fetch comments for images made in gThumb <http://gthumb.sourceforge.net> * get/generate thumbnails from exif and other images
- add/remove unlimited images to any file or directory * most important exif tags
- tagging files <http://en.wikipedia.org/wiki/Tag_%28metadata%29> * add/edit description and notes
- and more :) * fetch comments for images made in `gThumb <http://gthumb.sourceforge.net>`_
* add/remove unlimited images to any file or directory
* `tagging files <http://en.wikipedia.org/wiki/Tag_%28metadata%29>`_
* and more :)
REQUIREMENTS REQUIREMENTS
============ ------------
pyGTKtalog is written in python with following dependencies: pyGTKtalog is written in python with following dependencies:
- python 2.5 or higher (not tested on python 3000) * python 2.5 or higher (not tested on python 3000)
- pygtk 2.12 or higher <http://www.pygtk.org> * `pygtk 2.12 <http://www.pygtk.org>`_ or higher
- pygtkmvc 1.99 or higher <http://apps.sourceforge.net/trac/pygtkmvc/wiki> * `pygtkmvc 1.99 <http://apps.sourceforge.net/trac/pygtkmvc/wiki>`_ or higher
- sqlalchemy 0.5.5 or higher <http://www.sqlalchemy.org> * `sqlalchemy 0.5.5 <http://www.sqlalchemy.org>`_ or higher
Optional modules: Optional modules
^^^^^^^^^^^^^^^^
- PIL <http://www.pythonware.com/products/pil/index.htm> for image manipulation * `PIL <http://www.pythonware.com/products/pil/index.htm>`_ for image manipulation
Additional pyGTKtalog uses EXIF module by Gene Cash (slightly updatetd to EXIF Additional pyGTKtalog uses EXIF module by Gene Cash (slightly updatetd to EXIF
2.2 by me) which is included in sources. 2.2 by me) which is included in sources.
@@ -42,17 +45,17 @@ possiblity to run it on other sofisticated unix-like systems (i.e.
BeOS/ZETA/Haiku, QNX or MacOSX). BeOS/ZETA/Haiku, QNX or MacOSX).
Programs that are used: Programs that are used:
- mencoder (provided by mplayer package) * mencoder (provided by mplayer package)
- montage, convert from ImageMagick * montage, convert from ImageMagick
For development process following programs are used: For development process following programs are used:
- gettext <http://www.gnu.org/software/gettext/gettext.html> * `gettext <http://www.gnu.org/software/gettext/gettext.html>`_
- intltool <http://www.gnome.org/> * `intltool <http://www.gnome.org/>`_
- nose <http://code.google.com/p/python-nose/> * `nose <http://code.google.com/p/python-nose/>`_
- paver <http://code.google.com/p/paver/> * `paver <http://code.google.com/p/paver/>`_
INSTALATION INSTALATION
=========== -----------
You don't have to install it if you don't want to. You can just change current You don't have to install it if you don't want to. You can just change current
directory to pyGTKtalog and simply run: directory to pyGTKtalog and simply run:
@@ -62,16 +65,16 @@ $ paver run
That's it. Alternatively, if you like to put it in more system wide place, all That's it. Alternatively, if you like to put it in more system wide place, all
you have to do is: you have to do is:
- put pyGTKtalog directory into your destination of choice (/usr/local/share, #. put pyGTKtalog directory into your destination of choice (/usr/local/share,
/opt or ~/ is typical bet) /opt or ~/ is typical bet)
- copy pyGTKtalog shell script to /usr/bin, /usr/local/bin or in #. copy pyGTKtalog shell script to /usr/bin, /usr/local/bin or in
other place, where PATH variable is pointing or you feel like. other place, where PATH variable is pointing or you feel like.
- then modify pyGTKtalog line 6 to match right pygtktalog.py directory #. then modify pyGTKtalog line 6 to match right pygtktalog.py directory
Then, just run pyGTKtalog script. Then, just run pyGTKtalog script.
TODO TODO
==== ----
PyGTKtalog is still under heavy development, however there is small chance to PyGTKtalog is still under heavy development, however there is small chance to
change structure of catalogs (and if it'll change, there will be transparent change structure of catalogs (and if it'll change, there will be transparent
@@ -80,43 +83,43 @@ function to update DB schema).
For version 1.0 there are no features to be done, just bug fixes. For version 1.0 there are no features to be done, just bug fixes.
There are still minor aims for versions 1.x to be done: There are still minor aims for versions 1.x to be done:
- consolidate popup-menus with edit menu * consolidate popup-menus with edit menu
- add popup menu for directly removing tag from tag cloud * add popup menu for directly removing tag from tag cloud
- implement advanced search * implement advanced search
For version 2.0: For version 2.0:
- Export/Import * Export/Import
- Icon grid in files view * Icon grid in files view
- command line support: query, adding media to collection etc * command line support: query, adding media to collection etc
- internationalization * internationalization
- export to XLS * export to XLS
- user definied group of tags (represented by color in cloud tag) * user definied group of tags (represented by color in cloud tag)
- hiding specified files - configurable, like dot prefixed, cfg and manualy * hiding specified files - configurable, like dot prefixed, cfg and manualy
selected selected
- tests * tests
- warning about existing image in media directory * warning about existing image in media directory
Removed: Removed:
- filetypes handling (movies, images, archives, documents etc). Now it have * filetypes handling (movies, images, archives, documents etc). Now it have
common, unified external "plugin" system - simple text output from command common, unified external "plugin" system - simple text output from command
line programs. line programs.
- anime/movie * anime/movie
- title * title
- alt title * alt title
- type (anime movie, movie, anime oav, anime tv series, tv series, etc) * type (anime movie, movie, anime oav, anime tv series, tv series, etc)
- cover/images * cover/images
- genre * genre
- lang * lang
- sub lang * sub lang
- release date (from - to) * release date (from - to)
- anidb link/imdb link * anidb link/imdb link
Maybe in future versions. Now text file descriptions/notes and tags have to Maybe in future versions. Now text file descriptions/notes and tags have to
be enough for good and fast information search. be enough for good and fast information search.
NOTES NOTES
===== -----
Catalog file is plain sqlite database (optionally compressed with bzip2). All Catalog file is plain sqlite database (optionally compressed with bzip2). All
images are stored in ~/.pygtktalog/images directory. Names for images are images are stored in ``~/.pygtktalog/images`` directory. Names for images are
generated sha512 hash from image file itself. There is small possibility for two generated sha512 hash from image file itself. There is small possibility for two
identical hash for different image files. However, no images are overwritten. identical hash for different image files. However, no images are overwritten.
Thumbnail filename for each image is simply concatenation of image filename in Thumbnail filename for each image is simply concatenation of image filename in
@@ -124,32 +127,33 @@ images directory and '_t' string.
There is also converter from old database to new for internal use only. In There is also converter from old database to new for internal use only. In
public release there will be no other formats so it will be useless, and public release there will be no other formats so it will be useless, and
deleted. There are some issues with converting. All thumbnails will be lost. All deleted. There are some issues with converting. All thumbnails will be lost.
images without big image will be lost. There are serious changes with All images without big image will be lost. There are serious changes with
application design, and I decided, that is better to keep media unpacked on application design, and I decided, that is better to keep media unpacked on
disk, instead of pack it every time with save and unpack with open methods. New disk, instead of pack it every time with save and unpack with open methods. New
design prevent from deleting any file from media directory (placed in design prevent from deleting any file from media directory (placed in
~/.pygtktalog/images). Functionality for exporting images and corresponding db ``~/.pygtktalog/images``). Functionality for exporting images and corresponding
file is planned. db file is planned.
DEVELOPMENT DEVELOPMENT
=========== -----------
Several tools has been used to develop pyGTKtalog. Several tools has been used to develop pyGTKtalog.
1. Paver Paver
-------- ^^^^^
I've choose Paver[1] as make equivalent. Inside main project directory there is I've choose `Paver <http://www.blueskyonmars.com/projects/paver/>`_ as make
pavement.py script, which provides several tasks, that can be helpfull in a work equivalent. Inside main project directory there is pavement.py script, which
with sources. Paver is also used to generate standard setup.py. provides several tasks, that can be helpfull in a work with sources. Paver is
also used to generate standard setup.py.
2. Nose Nose
------- ^^^^
BUGS BUGS
==== ----
All bugs please report to Roman 'gryf' Dobosz <gryf73@gmail.com> All bugs please report to Roman 'gryf' Dobosz <gryf73@gmail.com>.

View File

@@ -4,7 +4,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: pygtktalog\n" "Project-Id-Version: pygtktalog\n"
"POT-Creation-Date: 2009-08-25 22:22:50.964390\n" "POT-Creation-Date: 2009-08-26 22:10:33.892815\n"
"Last-Translator: Roman Dobosz<gryf73@gmail.com>\n" "Last-Translator: Roman Dobosz<gryf73@gmail.com>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@@ -247,7 +247,7 @@ msgstr "Czy na pewno chcesz zakończyć?"
msgid "Current database is not saved, any changes will be lost." msgid "Current database is not saved, any changes will be lost."
msgstr "Bieżący katalog nie jest zapisany, wszelkie zmiany zostaną utracone." msgstr "Bieżący katalog nie jest zapisany, wszelkie zmiany zostaną utracone."
#: pygtktalog/controllers/main.py:48 #: pygtktalog/controllers/main.py:48 pygtktalog/controllers/main.py:49
msgid "Quit application" msgid "Quit application"
msgstr "Zakończ aplikację" msgstr "Zakończ aplikację"

View File

@@ -244,7 +244,7 @@ msgstr ""
msgid "Current database is not saved, any changes will be lost." msgid "Current database is not saved, any changes will be lost."
msgstr "" msgstr ""
#: pygtktalog/controllers/main.py:48 #: pygtktalog/controllers/main.py:48 pygtktalog/controllers/main.py:49
msgid "Quit application" msgid "Quit application"
msgstr "" msgstr ""

View File

@@ -1,6 +1,8 @@
""" """
Project: pyGTKtalog Project: pyGTKtalog
Description: Makefile and setup.py replacement. Used package: paver Description: Makefile and setup.py replacement. Used python packages -
paver, nosetests. External commands - xgettext, intltool-extract, svn,
grep.
Type: management Type: management
Author: Roman 'gryf' Dobosz, gryf73@gmail.com Author: Roman 'gryf' Dobosz, gryf73@gmail.com
Created: 2009-05-07 Created: 2009-05-07
@@ -10,10 +12,12 @@ import sys
import shutil import shutil
from datetime import datetime from datetime import datetime
from paver.easy import sh, dry, call_task from paver.easy import sh, dry, call_task, options, Bunch
from paver.tasks import task, needs, help, cmdopts from paver.tasks import task, needs, help, cmdopts
from paver.setuputils import setup from paver.setuputils import setup
from paver.misctasks import generate_setup, minilib from paver.misctasks import generate_setup, minilib
import paver.doctools
try: try:
from pylint import lint from pylint import lint
HAVE_LINT = True HAVE_LINT = True
@@ -76,6 +80,8 @@ setup(
test_suite = 'nose.collector' test_suite = 'nose.collector'
) )
options(sphinx=Bunch(builddir="build", sourcedir="source"))
@task @task
@needs(['locale_gen', 'minilib', 'generate_setup']) @needs(['locale_gen', 'minilib', 'generate_setup'])
@@ -186,10 +192,10 @@ if HAVE_LINT:
@task @task
@cmdopts([('coverage', 'c', 'display coverage information')]) @cmdopts([('coverage', 'c', 'display coverage information')])
def test(options): def test(opts):
"""run unit tests""" """run unit tests"""
cmd = "PYTHONPATH=%s:$PYTHONPATH nosetests -w test" % _setup_env() cmd = "PYTHONPATH=%s:$PYTHONPATH nosetests -w test" % _setup_env()
if hasattr(options.test, 'coverage'): if hasattr(opts.test, 'coverage'):
cmd += " --with-coverage --cover-package pygtktalog" cmd += " --with-coverage --cover-package pygtktalog"
os.system(cmd) os.system(cmd)

View File

@@ -9,8 +9,15 @@ import gtk
from gtkmvc import Controller from gtkmvc import Controller
from pygtktalog.dialogs import yesno, okcancel, info, warn, error #from pygtktalog.dialogs import yesno
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.logger import get_logger
LOG = get_logger("main controller")
class MainController(Controller): class MainController(Controller):
""" """
@@ -21,8 +28,16 @@ class MainController(Controller):
"""Initialize main controller""" """Initialize main controller"""
Controller.__init__(self, model, view) Controller.__init__(self, model, view)
# add controllers for files/tags components
self.discs = DiscsController(model, view.discs)
#self.files = FilesController(model, view.files)
#self.details = DetailsController(model, view.details)
#self.tags = TagcloudController(model, view.tags)
def register_view(self, view): def register_view(self, view):
"""Default view registration stuff""" """Default view registration stuff"""
# one row contains image and text
view['main'].show() view['main'].show()
def register_adapters(self): def register_adapters(self):
@@ -31,21 +46,20 @@ class MainController(Controller):
""" """
pass pass
# signals
def on_main_destroy_event(self, widget, event):
"""Quit"""
self.on_quit_activate(widget)
return True
def on_quit_activate(self, widget): def on_quit_activate(self, widget):
"""Quit and save window parameters to config file""" """Quit and save window parameters to config file"""
# check if any unsaved project is on go.
#if self.model.unsaved_project and \
#self.model.config.confd['confirmquit']:
# if not yesno.Qst(_("Quit application") + " - pyGTKtalog",
# _("Do you really want to quit?"),
# _("Current database is not saved, any changes "
# "will be lost.")).run():
# return
#self.__store_settings()
#self.model.cleanup()
if yesno(_("Do you really want to quit?"), #if yesno(_("Do you really want to quit?"),
_("Current database is not saved, any changes will be " # _("Current database is not saved, any changes will be "
"lost."), _("Quit application") + " - pyGTKtalog", 0): # "lost."), _("Quit application") + " - pyGTKtalog", 0):
gtk.main_quit() self.model.cleanup()
LOG.debug("quit application")
gtk.main_quit()
return False return False

View File

@@ -9,12 +9,20 @@ from sqlalchemy import MetaData, create_engine
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from pygtktalog.logger import get_logger
# setup SQLAlchemy logging facility
# TODO: Logger("sqlalchemy")
# or maybe it will be better to separate sqlalchemy stuff from application
get_logger("sqlalchemy", 'INFO')
# Prepare SQLAlchemy objects # Prepare SQLAlchemy objects
Meta = MetaData() Meta = MetaData()
Base = declarative_base(metadata=Meta) Base = declarative_base(metadata=Meta)
Session = sessionmaker() Session = sessionmaker()
def connect(filename): def connect(filename):
""" """
create engine and bind to Meta object. create engine and bind to Meta object.
@@ -22,8 +30,8 @@ def connect(filename):
@filename - string with absolute or relative path to sqlite database @filename - string with absolute or relative path to sqlite database
file. file.
""" """
get_logger("dbcommon").info("db filename: %s" % filename)
engine = create_engine("sqlite:///%s" % filename, echo=True) engine = create_engine("sqlite:///%s" % filename)
Meta.bind = engine Meta.bind = engine
Meta.create_all() Meta.create_all()

50
pygtktalog/logger.py Normal file
View File

@@ -0,0 +1,50 @@
"""
Project: pyGTKtalog
Description: Logging functionality
Type: core
Author: Roman 'gryf' Dobosz, gryf73@gmail.com
Created: 2009-09-02
"""
import os
import sys
import logging
LEVEL = {'DEBUG': logging.DEBUG,
'INFO': logging.INFO,
'WARN': logging.WARN,
'ERROR': logging.ERROR,
'CRITICAL': logging.CRITICAL}
#def get_logger(module_name, level=None, to_file=True):
def get_logger(module_name, level=None, to_file=False):
"""
Prepare and return log object. Standard formatting is used for all logs.
Arguments:
@module_name - String name for Logger object.
@level - Log level (as string), one of DEBUG, INFO, WARN, ERROR and
CRITICAL.
@to_file - If True, stores log in file inside .pygtktalog config
directory, otherwise log is redirected to stderr.
Returns: object of logging.Logger class
"""
path = os.path.join(os.path.expanduser("~"), ".pygtktalog", "app.log")
path = "/dev/null"
log = logging.getLogger(module_name)
if not level:
#log.setLevel(LEVEL['WARN'])
log.setLevel(LEVEL['DEBUG'])
else:
log.setLevel(LEVEL[level])
if to_file:
log_handler = logging.FileHandler(path)
formatter = logging.Formatter("%(asctime)s %(filename)s:%(lineno) - %(name)s - %(levelname)s - %(message)s")
else:
log_handler = logging.StreamHandler(sys.stderr)
formatter = logging.Formatter("%(name)s - %(filename)s:%(lineno)s - %(levelname)s - %(message)s")
log_handler.setFormatter(formatter)
log.addHandler(log_handler)
return log

View File

@@ -5,14 +5,142 @@
Author: Roman 'gryf' Dobosz, gryf73@gmail.com Author: Roman 'gryf' Dobosz, gryf73@gmail.com
Created: 2009-05-02 Created: 2009-05-02
""" """
from gtkmvc import Model import os
import bz2
from tempfile import mkstemp
import gtk
import gobject
from gtkmvc import ModelMT
from pygtktalog.dbobjects import File, Exif, Group, Gthumb from pygtktalog.dbobjects import File, Exif, Group, Gthumb
from pygtktalog.dbobjects import Image, Tag, Thumbnail from pygtktalog.dbobjects import Image, Tag, Thumbnail
from pygtktalog.dbcommon import connect, Meta from pygtktalog.dbcommon import connect, Meta, Session
from pygtktalog.logger import get_logger
LOG = get_logger("main model")
class MainModel(Model): class MainModel(ModelMT):
status_bar_message = _("Idle") status_bar_message = _("Idle")
current_disc = None
__observables__ = ("status_bar_message",) __observables__ = ("status_bar_message", "current_disc")
def __init__(self, filename=None):
"""Initialization. Make some nice defaults."""
print "model"
ModelMT.__init__(self)
# Opened/saved database location in filesystem. Could be compressed.
self.db_filename = filename
# Temporary (usually in /tmp) working database.
self.tmp_filename = None
# Flag indicates, that db was compressed
# TODO: make it depend on configuration
self.compressed = False
self.db_unsaved = False
self.discs = gtk.TreeStore(str, gobject.TYPE_STRING)
# XXX remove this on production!
myiter = self.discs.insert_before(None, None)
self.discs.set_value(myiter, 1, "bubu")
self.discs.set_value(myiter, 1, "foo")
self.discs.set_value(myiter, 1, "bar")
itr = self.discs.append(None, None)
self.discs.set_value(itr, 0, gtk.STOCK_DIRECTORY)
self.discs.set_value(itr, 1, "foobar")
for nr, name in enumerate(('foo', 'bar', 'baz')):
self.discs.append(itr, (gtk.STOCK_FILE, "%s %d" % (name, nr)))
#self.open()
def open(self, filename=None):
self.unsaved_project = False
if filename is not None and not os.path.exists(filename):
LOG.warn("db file '%s' doesn't exist", filename)
return False
if filename:
self.db_filename = filename
if self.db_filename:
return self.__open_or_decompress()
else:
self.__create_empty_db()
return True
def cleanup(self):
"""remove temporary directory tree from filesystem"""
if self.tmp_filename is None:
return
#import ipdb; ipdb.set_trace()
LOG.debug("cleanup()")
try:
os.unlink(self.tmp_filename)
except OSError:
LOG.exception("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):
pass
def __open_or_decompress(self):
filename = os.path.abspath(self.db_filename)
LOG.info("database file: %s", filename)
self.__cleanup_and_create_temp_db_file()
LOG.debug("tmp database file: %s", str(self.tmp_filename))
try:
test_file = open(filename).read(15)
LOG.debug("test_file: %s", test_file)
except IOError:
self.cleanup()
self.db_filename = None
self.tmp_filename = None
LOG.exception("Error opening file!")
return False
if test_file == "SQLite format 3":
db_tmp = open(self.tmp_filename, "wb")
db_tmp.write(open(filename).read())
db_tmp.close()
LOG.debug("file format: sqlite")
elif test_file[0:10] == "BZh91AY&SY":
open_file = bz2.BZ2File(filename)
try:
db_tmp = open(self.tmp_filename, "w")
db_tmp.write(open_file.read())
db_tmp.close()
open_file.close()
except IOError:
# file is not bz2
self.cleanup()
self.filename = None
self.internal_dirname = None
# TODO: add logger
LOG.exception("File is probably not a bz2!")
return False
else:
self.filename = None
self.internal_dirname = None
return False
connect(os.path.abspath(self.tmp_filename))
return True
def __cleanup_and_create_temp_db_file(self):
self.cleanup()
fd, self.tmp_filename = mkstemp()
# close file descriptor, otherwise it can be source of app crash!
# http://www.logilab.org/blogentry/17873
os.close(fd)
# TODO: get this thing right
def get_root_entries(self, id):
LOG.debug("id: %s" (type(id)))

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.5 on Mon Aug 31 09:03:55 2009 -->
<glade-interface>
<widget class="GtkWindow" id="top_discs">
<child>
<widget class="GtkTreeView" id="discs">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<property name="rules_hint">True</property>
<signal name="button_press_event" handler="on_discs_button_press_event"/>
<signal name="row_activated" handler="on_discs_row_activated"/>
<signal name="cursor_changed" handler="on_discs_cursor_changed"/>
<signal name="key_release_event" handler="on_discs_key_release_event"/>
</widget>
</child>
</widget>
<widget class="GtkMenu" id="discs_popup">
<child>
<widget class="GtkMenuItem" id="expand_all1">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Expand all nodes</property>
<property name="label" translatable="yes">_Expand all</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_expand_all1_activate"/>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="collapse_all1">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Collapse all nodes</property>
<property name="label" translatable="yes">_Collapse all</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_collapse_all1_activate"/>
</widget>
</child>
<child>
<widget class="GtkSeparatorMenuItem" id="separator4">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="update1">
<property name="visible">True</property>
<property name="label" translatable="yes">_Update</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_update1_activate"/>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="rename1">
<property name="visible">True</property>
<property name="label" translatable="yes">_Rename</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_rename1_activate"/>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="delete2">
<property name="visible">True</property>
<property name="label" translatable="yes">_Delete</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_delete2_activate"/>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="statistics1">
<property name="visible">True</property>
<property name="label" translatable="yes">_Statistics</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_statistics1_activate"/>
</widget>
</child>
</widget>
</glade-interface>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--*- mode: xml -*-->
<glade-interface> <glade-interface>
<!-- interface-requires gtk+ 2.16 -->
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkWindow" id="main"> <widget class="GtkWindow" id="main">
<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>
<property name="title" translatable="yes">pyGTKtalog</property> <property name="title" translatable="yes">pyGTKtalog</property>
@@ -11,6 +11,7 @@
<widget class="GtkVBox" id="vbox1"> <widget class="GtkVBox" id="vbox1">
<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>
<property name="orientation">vertical</property>
<child> <child>
<widget class="GtkMenuBar" id="mainMenubar"> <widget class="GtkMenuBar" id="mainMenubar">
<property name="visible">True</property> <property name="visible">True</property>
@@ -23,8 +24,8 @@
<widget class="GtkMenu" id="file1_menu"> <widget class="GtkMenu" id="file1_menu">
<child> <child>
<widget class="GtkImageMenuItem" id="new1"> <widget class="GtkImageMenuItem" id="new1">
<property name="visible">True</property>
<property name="label">gtk-new</property> <property name="label">gtk-new</property>
<property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_new_activate"/> <signal name="activate" handler="on_new_activate"/>
@@ -32,8 +33,8 @@
</child> </child>
<child> <child>
<widget class="GtkImageMenuItem" id="open1"> <widget class="GtkImageMenuItem" id="open1">
<property name="visible">True</property>
<property name="label">gtk-open</property> <property name="label">gtk-open</property>
<property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_open_activate"/> <signal name="activate" handler="on_open_activate"/>
@@ -41,8 +42,8 @@
</child> </child>
<child> <child>
<widget class="GtkImageMenuItem" id="save1"> <widget class="GtkImageMenuItem" id="save1">
<property name="visible">True</property>
<property name="label">gtk-save</property> <property name="label">gtk-save</property>
<property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_save_activate"/> <signal name="activate" handler="on_save_activate"/>
@@ -50,8 +51,8 @@
</child> </child>
<child> <child>
<widget class="GtkImageMenuItem" id="save_as1"> <widget class="GtkImageMenuItem" id="save_as1">
<property name="visible">True</property>
<property name="label">gtk-save-as</property> <property name="label">gtk-save-as</property>
<property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_save_as_activate"/> <signal name="activate" handler="on_save_as_activate"/>
@@ -98,8 +99,8 @@
</child> </child>
<child> <child>
<widget class="GtkImageMenuItem" id="quit1"> <widget class="GtkImageMenuItem" id="quit1">
<property name="visible">True</property>
<property name="label">gtk-quit</property> <property name="label">gtk-quit</property>
<property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_quit_activate"/> <signal name="activate" handler="on_quit_activate"/>
@@ -119,12 +120,12 @@
<widget class="GtkMenu" id="edit1_menu"> <widget class="GtkMenu" id="edit1_menu">
<child> <child>
<widget class="GtkImageMenuItem" id="delete1"> <widget class="GtkImageMenuItem" id="delete1">
<property name="visible">True</property>
<property name="label">gtk-delete</property> <property name="label">gtk-delete</property>
<property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_delete1_activate"/> <signal name="activate" handler="on_delete1_activate"/>
<accelerator key="Delete" modifiers="" signal="activate"/> <accelerator key="Delete" signal="activate"/>
</widget> </widget>
</child> </child>
<child> <child>
@@ -134,12 +135,12 @@
</child> </child>
<child> <child>
<widget class="GtkImageMenuItem" id="find1"> <widget class="GtkImageMenuItem" id="find1">
<property name="visible">True</property>
<property name="label">gtk-find</property> <property name="label">gtk-find</property>
<property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_find_activate"/> <signal name="activate" handler="on_find_activate"/>
<accelerator key="f" modifiers="GDK_CONTROL_MASK" signal="activate"/> <accelerator key="f" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</widget> </widget>
</child> </child>
<child> <child>
@@ -149,8 +150,8 @@
</child> </child>
<child> <child>
<widget class="GtkImageMenuItem" id="properties1"> <widget class="GtkImageMenuItem" id="properties1">
<property name="visible">True</property>
<property name="label">gtk-preferences</property> <property name="label">gtk-preferences</property>
<property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_preferences_activate"/> <signal name="activate" handler="on_preferences_activate"/>
@@ -173,7 +174,7 @@
<property name="label" translatable="yes">Add _CD/DVD</property> <property name="label" translatable="yes">Add _CD/DVD</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<signal name="activate" handler="on_add_cd_activate"/> <signal name="activate" handler="on_add_cd_activate"/>
<accelerator key="e" modifiers="GDK_CONTROL_MASK" signal="activate"/> <accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</widget> </widget>
</child> </child>
<child> <child>
@@ -182,7 +183,7 @@
<property name="label" translatable="yes">Add _Directory</property> <property name="label" translatable="yes">Add _Directory</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<signal name="activate" handler="on_add_directory_activate"/> <signal name="activate" handler="on_add_directory_activate"/>
<accelerator key="d" modifiers="GDK_CONTROL_MASK" signal="activate"/> <accelerator key="d" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</widget> </widget>
</child> </child>
<child> <child>
@@ -238,17 +239,11 @@
</child> </child>
<child> <child>
<widget class="GtkImageMenuItem" id="cancel1"> <widget class="GtkImageMenuItem" id="cancel1">
<property name="label">gtk-cancel</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="label" translatable="yes">Cancel</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_cancel_clicked"/> <signal name="activate" handler="on_cancel_clicked"/>
<child internal-child="image">
<widget class="GtkImage" id="image3">
<property name="visible">True</property>
<property name="stock">gtk-cancel</property>
<property name="icon_size">1</property>
</widget>
</child>
</widget> </widget>
</child> </child>
</widget> </widget>
@@ -291,8 +286,8 @@
<widget class="GtkMenu" id="help1_menu"> <widget class="GtkMenu" id="help1_menu">
<child> <child>
<widget class="GtkImageMenuItem" id="about1"> <widget class="GtkImageMenuItem" id="about1">
<property name="visible">True</property>
<property name="label">gtk-about</property> <property name="label">gtk-about</property>
<property name="visible">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_about1_activate"/> <signal name="activate" handler="on_about1_activate"/>
@@ -306,12 +301,13 @@
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">0</property>
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkToolbar" id="maintoolbar"> <widget class="GtkToolbar" id="maintoolbar">
<property name="visible">True</property> <property name="visible">True</property>
<property name="toolbar_style">GTK_TOOLBAR_BOTH</property> <property name="toolbar_style">both</property>
<child> <child>
<widget class="GtkToolButton" id="tb_new"> <widget class="GtkToolButton" id="tb_new">
<property name="visible">True</property> <property name="visible">True</property>
@@ -320,6 +316,7 @@
<signal name="clicked" handler="on_new_activate"/> <signal name="clicked" handler="on_new_activate"/>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="homogeneous">True</property> <property name="homogeneous">True</property>
</packing> </packing>
</child> </child>
@@ -331,6 +328,7 @@
<signal name="clicked" handler="on_open_activate"/> <signal name="clicked" handler="on_open_activate"/>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="homogeneous">True</property> <property name="homogeneous">True</property>
</packing> </packing>
</child> </child>
@@ -342,6 +340,7 @@
<signal name="clicked" handler="on_save_activate"/> <signal name="clicked" handler="on_save_activate"/>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="homogeneous">True</property> <property name="homogeneous">True</property>
</packing> </packing>
</child> </child>
@@ -354,6 +353,9 @@
</widget> </widget>
</child> </child>
</widget> </widget>
<packing>
<property name="expand">False</property>
</packing>
</child> </child>
<child> <child>
<widget class="GtkToolButton" id="tb_addcd"> <widget class="GtkToolButton" id="tb_addcd">
@@ -365,6 +367,7 @@
<signal name="clicked" handler="on_add_cd_activate"/> <signal name="clicked" handler="on_add_cd_activate"/>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="homogeneous">True</property> <property name="homogeneous">True</property>
</packing> </packing>
</child> </child>
@@ -377,6 +380,7 @@
<signal name="clicked" handler="on_add_directory_activate"/> <signal name="clicked" handler="on_add_directory_activate"/>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="homogeneous">True</property> <property name="homogeneous">True</property>
</packing> </packing>
</child> </child>
@@ -388,6 +392,7 @@
<signal name="clicked" handler="on_find_activate"/> <signal name="clicked" handler="on_find_activate"/>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="homogeneous">True</property> <property name="homogeneous">True</property>
</packing> </packing>
</child> </child>
@@ -400,6 +405,9 @@
</widget> </widget>
</child> </child>
</widget> </widget>
<packing>
<property name="expand">False</property>
</packing>
</child> </child>
<child> <child>
<widget class="GtkToolButton" id="cancel"> <widget class="GtkToolButton" id="cancel">
@@ -411,6 +419,7 @@
<signal name="clicked" handler="on_cancel_clicked"/> <signal name="clicked" handler="on_cancel_clicked"/>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="homogeneous">True</property> <property name="homogeneous">True</property>
</packing> </packing>
</child> </child>
@@ -422,6 +431,7 @@
<signal name="clicked" handler="on_quit_activate"/> <signal name="clicked" handler="on_quit_activate"/>
</widget> </widget>
<packing> <packing>
<property name="expand">False</property>
<property name="homogeneous">True</property> <property name="homogeneous">True</property>
</packing> </packing>
</child> </child>
@@ -443,18 +453,24 @@
<property name="can_focus">True</property> <property name="can_focus">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>
<property name="editable">False</property> <property name="editable">False</property>
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property> <property name="shadow_type">etched-in</property>
<property name="caps_lock_warning">False</property>
<property name="secondary_icon_stock">gtk-clear</property>
<property name="secondary_icon_activatable">True</property>
<property name="secondary_icon_sensitive">True</property>
</widget> </widget>
<packing>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<widget class="GtkButton" id="clear"> <widget class="GtkButton" id="clear">
<property name="label">gtk-clear</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">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>
<property name="label" translatable="yes">gtk-clear</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<property name="response_id">0</property>
<signal name="clicked" handler="on_clear_clicked"/> <signal name="clicked" handler="on_clear_clicked"/>
</widget> </widget>
<packing> <packing>
@@ -483,19 +499,10 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">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>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> <property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> <property name="vscrollbar_policy">automatic</property>
<child> <child>
<widget class="GtkTreeView" id="discs"> <placeholder/>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<property name="rules_hint">True</property>
<signal name="button_press_event" handler="on_discs_button_press_event"/>
<signal name="row_activated" handler="on_discs_row_activated"/>
<signal name="cursor_changed" handler="on_discs_cursor_changed"/>
<signal name="key_release_event" handler="on_discs_key_release_event"/>
</widget>
</child> </child>
</widget> </widget>
</child> </child>
@@ -506,8 +513,8 @@
<property name="label" translatable="yes">Discs</property> <property name="label" translatable="yes">Discs</property>
</widget> </widget>
<packing> <packing>
<property name="type">tab</property>
<property name="tab_fill">False</property> <property name="tab_fill">False</property>
<property name="type">tab</property>
</packing> </packing>
</child> </child>
<child> <child>
@@ -515,23 +522,10 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">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>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> <property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> <property name="vscrollbar_policy">automatic</property>
<child> <child>
<widget class="GtkTextView" id="tag_cloud_textview"> <placeholder/>
<property name="visible">True</property>
<property name="can_focus">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="editable">False</property>
<property name="wrap_mode">GTK_WRAP_WORD</property>
<property name="cursor_visible">False</property>
<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_data_received" handler="on_tag_cloud_textview_drag_data_received"/>
<signal name="drag_drop" handler="on_tag_cloud_textview_drag_drop"/>
</widget>
</child> </child>
</widget> </widget>
<packing> <packing>
@@ -545,9 +539,9 @@
<property name="label" translatable="yes">Tags</property> <property name="label" translatable="yes">Tags</property>
</widget> </widget>
<packing> <packing>
<property name="type">tab</property>
<property name="position">1</property> <property name="position">1</property>
<property name="tab_fill">False</property> <property name="tab_fill">False</property>
<property name="type">tab</property>
</packing> </packing>
</child> </child>
</widget> </widget>
@@ -560,24 +554,16 @@
<widget class="GtkVPaned" id="vpaned1"> <widget class="GtkVPaned" id="vpaned1">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="orientation">vertical</property>
<child> <child>
<widget class="GtkScrolledWindow" id="scrolledwindow2"> <widget class="GtkScrolledWindow" id="scrolledwindow2">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> <property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> <property name="vscrollbar_policy">automatic</property>
<property name="shadow_type">GTK_SHADOW_IN</property> <property name="shadow_type">in</property>
<child> <child>
<widget class="GtkTreeView" id="files"> <placeholder/>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="rules_hint">True</property>
<signal name="drag_data_get" handler="on_files_drag_data_get"/>
<signal name="button_press_event" handler="on_files_button_press_event"/>
<signal name="row_activated" handler="on_files_row_activated"/>
<signal name="cursor_changed" handler="on_files_cursor_changed"/>
<signal name="key_release_event" handler="on_files_key_release_event"/>
</widget>
</child> </child>
</widget> </widget>
<packing> <packing>
@@ -586,143 +572,7 @@
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkNotebook" id="notebook_details"> <placeholder/>
<property name="visible">True</property>
<property name="can_focus">True</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="GtkHBox" id="fileinfo">
<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>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow4">
<property name="visible">True</property>
<property name="can_focus">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="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<child>
<widget class="GtkTextView" id="description">
<property name="visible">True</property>
<property name="can_focus">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="editable">False</property>
<property name="wrap_mode">GTK_WRAP_WORD</property>
<property name="left_margin">2</property>
<property name="right_margin">2</property>
<property name="cursor_visible">False</property>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkViewport" id="thumb_box">
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="resize_mode">GTK_RESIZE_QUEUE</property>
<signal name="button_press_event" handler="on_thumb_box_button_press_event"/>
<child>
<widget class="GtkImage" id="thumb">
<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="xpad">3</property>
<property name="ypad">3</property>
<property name="stock">gtk-missing-image</property>
<property name="icon_size">6</property>
</widget>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="nb_fileinfo">
<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">File info</property>
</widget>
<packing>
<property name="type">tab</property>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<widget class="GtkScrolledWindow" id="img_container">
<property name="can_focus">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="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<child>
<widget class="GtkIconView" id="images">
<property name="visible">True</property>
<property name="can_focus">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">Double click to open image</property>
<signal name="button_press_event" handler="on_images_button_press_event"/>
<signal name="item_activated" handler="on_images_item_activated"/>
<signal name="key_release_event" handler="on_images_key_release_event"/>
</widget>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label3">
<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">Images</property>
</widget>
<packing>
<property name="type">tab</property>
<property name="position">1</property>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<widget class="GtkScrolledWindow" id="exifinfo">
<property name="can_focus">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="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<child>
<widget class="GtkTreeView" id="exif_tree">
<property name="visible">True</property>
<property name="can_focus">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="rules_hint">True</property>
</widget>
</child>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label4">
<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">EXIF</property>
</widget>
<packing>
<property name="type">tab</property>
<property name="position">2</property>
<property name="tab_fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="resize">True</property>
<property name="shrink">True</property>
</packing>
</child> </child>
</widget> </widget>
<packing> <packing>
@@ -753,6 +603,9 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="has_resize_grip">False</property> <property name="has_resize_grip">False</property>
</widget> </widget>
<packing>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<widget class="GtkProgressBar" id="progressbar1"> <widget class="GtkProgressBar" id="progressbar1">
@@ -774,63 +627,6 @@
</widget> </widget>
</child> </child>
</widget> </widget>
<widget class="GtkMenu" id="discs_popup">
<child>
<widget class="GtkMenuItem" id="expand_all1">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Expand all nodes</property>
<property name="label" translatable="yes">_Expand all</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_expand_all1_activate"/>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="collapse_all1">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Collapse all nodes</property>
<property name="label" translatable="yes">_Collapse all</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_collapse_all1_activate"/>
</widget>
</child>
<child>
<widget class="GtkSeparatorMenuItem" id="separator4">
<property name="visible">True</property>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="update1">
<property name="visible">True</property>
<property name="label" translatable="yes">_Update</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_update1_activate"/>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="rename1">
<property name="visible">True</property>
<property name="label" translatable="yes">_Rename</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_rename1_activate"/>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="delete2">
<property name="visible">True</property>
<property name="label" translatable="yes">_Delete</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_delete2_activate"/>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="statistics1">
<property name="visible">True</property>
<property name="label" translatable="yes">_Statistics</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_statistics1_activate"/>
</widget>
</child>
</widget>
<widget class="GtkWindow" id="win_exifinfo"> <widget class="GtkWindow" id="win_exifinfo">
<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> <child>

View File

@@ -6,29 +6,110 @@
Created: 2009-05-02 Created: 2009-05-02
""" """
import os.path import os.path
import gtk
from gtkmvc import View from gtkmvc import View
def get_glade(glade_filename):
"""
Return full path to specified glade file
"""
return os.path.join(os.path.dirname(__file__), "glade", glade_filename)
class MainView(View): class MainView(View):
""" """
Create window from glade file. Note, that glade file is placed in view Create window from glade file. Note, that glade file is placed in view
module under glade subdirectory. module under glade subdirectory.
""" """
glade = get_glade("main.glade")
glade = os.path.join(os.path.dirname(__file__), "glade", "main.glade")
top = "main" top = "main"
def __init__(self, top="main"):
"""
Initialize view
"""
View.__init__(self)
self['tag_path_box'].hide()
self.discs = DiscsView()
self['scrolledwindow1'].add_with_viewport(self.discs.get_top_widget())
def set_widgets_scan_sensitivity(self, sensitive=True):
"""
Activate/deactivate selected widgets while scanning is active
"""
pass
class DiscsView(View):
"""
Separate Discs TreeView subview.
"""
glade = get_glade("discs.glade")
top = 'discs'
def __init__(self): def __init__(self):
""" """
Initialize view Initialize view
""" """
View.__init__(self) View.__init__(self)
self['tag_path_box'].hide() #self.discs_popup = DiscsPopupView()
#class DiscsPopupView(View):
# """
# Separate Discs PopUp subview.
# """
# glade = get_glade("discs.glade")
# top = 'discs_popup'
# def __init__(self):
# """
# Initialize view
# """
# View.__init__(self)
#class FilesView(View):
# """
# Separate subview of Files TreeView as a table.
# """
# glade = get_glade("files.glade")
# top = 'files'
# def __init__(self):
# """
# Initialize view
# """
# View.__init__(self)
#class TagcloudView(View):
# """
# Textview subview with clickable tags.
# """
# glade = get_glade("tagcloud.glade")
# top = 'tag_cloud_textview'
# def __init__(self):
# """
# Initialize view
# """
# View.__init__(self)
#class DetailsView(View):
# """
# Notebook subview containing tabs with details and possibly Exif, images
# assocated with object and alternatively thumbnail.
# """
# glade = get_glade("details.glade")
# top = 'notebook_details'
# def __init__(self):
# """
# Initialize view
# """
# View.__init__(self)
def set_widgets_scan_visibility(self, flag):
"""
Activate/deactivate selected widgets while scanning is active
"""
pass

View File

@@ -83,7 +83,8 @@ class Thumbnail(object):
if 'Image Orientation' in exif: if 'Image Orientation' in exif:
orient = exif['Image Orientation'].values[0] orient = exif['Image Orientation'].values[0]
if orient > 1 and orient in orientations: if orient > 1 and orient in orientations:
temp_image_path = mkstemp()[1] fd, temp_image_path = mkstemp()
os.close(fd)
thumb_image = Image.open(self.thumbnail_path) thumb_image = Image.open(self.thumbnail_path)
tmp_thumb_img = thumb_image.transpose(orientations[orient]) tmp_thumb_img = thumb_image.transpose(orientations[orient])

View File

@@ -7,7 +7,6 @@
""" """
import unittest import unittest
import os import os
from tempfile import mkstemp
from pygtktalog.dbcommon import connect, Meta, Session, Base from pygtktalog.dbcommon import connect, Meta, Session, Base

View File

@@ -100,7 +100,7 @@ class TestVideo(unittest.TestCase):
self.assertTrue(filename != None) self.assertTrue(filename != None)
self.assertTrue(os.path.exists(filename)) self.assertTrue(os.path.exists(filename))
file_size = os.stat(filename)[6] file_size = os.stat(filename)[6]
self.assertEqual(file_size, 9067) self.assertEqual(file_size, 9075)
os.unlink(filename) os.unlink(filename)
for length in (480, 380, 4): for length in (480, 380, 4):