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:
150
README
150
README
@@ -1,37 +1,40 @@
|
||||
pyGTKtalog 1.9
|
||||
==============
|
||||
pyGTKtalog
|
||||
==========
|
||||
|
||||
pyGTKtalog is Linux/FreeBSD program for indexing CD/DVD or directories on
|
||||
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
|
||||
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
|
||||
application, because it's ment to be replacement (in some way) for gtktalog,
|
||||
which seems to be dead project for years.
|
||||
|
||||
FEATURES
|
||||
========
|
||||
Current version is 1.9.
|
||||
|
||||
- scan for files in selected media
|
||||
- get/generate thumbnails from exif and other images
|
||||
- most important exif tags
|
||||
- add/edit description and notes
|
||||
- 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 :)
|
||||
FEATURES
|
||||
--------
|
||||
|
||||
* scan for files in selected media
|
||||
* get/generate thumbnails from exif and other images
|
||||
* most important exif tags
|
||||
* add/edit description and notes
|
||||
* 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
|
||||
============
|
||||
------------
|
||||
|
||||
pyGTKtalog is written in python with following dependencies:
|
||||
|
||||
- python 2.5 or higher (not tested on python 3000)
|
||||
- pygtk 2.12 or higher <http://www.pygtk.org>
|
||||
- pygtkmvc 1.99 or higher <http://apps.sourceforge.net/trac/pygtkmvc/wiki>
|
||||
- sqlalchemy 0.5.5 or higher <http://www.sqlalchemy.org>
|
||||
* python 2.5 or higher (not tested on python 3000)
|
||||
* `pygtk 2.12 <http://www.pygtk.org>`_ or higher
|
||||
* `pygtkmvc 1.99 <http://apps.sourceforge.net/trac/pygtkmvc/wiki>`_ or higher
|
||||
* `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
|
||||
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).
|
||||
|
||||
Programs that are used:
|
||||
- mencoder (provided by mplayer package)
|
||||
- montage, convert from ImageMagick
|
||||
* mencoder (provided by mplayer package)
|
||||
* montage, convert from ImageMagick
|
||||
|
||||
For development process following programs are used:
|
||||
- gettext <http://www.gnu.org/software/gettext/gettext.html>
|
||||
- intltool <http://www.gnome.org/>
|
||||
- nose <http://code.google.com/p/python-nose/>
|
||||
- paver <http://code.google.com/p/paver/>
|
||||
* `gettext <http://www.gnu.org/software/gettext/gettext.html>`_
|
||||
* `intltool <http://www.gnome.org/>`_
|
||||
* `nose <http://code.google.com/p/python-nose/>`_
|
||||
* `paver <http://code.google.com/p/paver/>`_
|
||||
|
||||
INSTALATION
|
||||
===========
|
||||
-----------
|
||||
|
||||
You don't have to install it if you don't want to. You can just change current
|
||||
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
|
||||
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)
|
||||
- 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.
|
||||
- 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.
|
||||
|
||||
TODO
|
||||
====
|
||||
----
|
||||
|
||||
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
|
||||
@@ -80,43 +83,43 @@ function to update DB schema).
|
||||
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:
|
||||
- consolidate popup-menus with edit menu
|
||||
- add popup menu for directly removing tag from tag cloud
|
||||
- implement advanced search
|
||||
* consolidate popup-menus with edit menu
|
||||
* add popup menu for directly removing tag from tag cloud
|
||||
* implement advanced search
|
||||
|
||||
For version 2.0:
|
||||
- Export/Import
|
||||
- Icon grid in files view
|
||||
- command line support: query, adding media to collection etc
|
||||
- internationalization
|
||||
- export to XLS
|
||||
- user definied group of tags (represented by color in cloud tag)
|
||||
- hiding specified files - configurable, like dot prefixed, cfg and manualy
|
||||
* Export/Import
|
||||
* Icon grid in files view
|
||||
* command line support: query, adding media to collection etc
|
||||
* internationalization
|
||||
* export to XLS
|
||||
* user definied group of tags (represented by color in cloud tag)
|
||||
* hiding specified files - configurable, like dot prefixed, cfg and manualy
|
||||
selected
|
||||
- tests
|
||||
- warning about existing image in media directory
|
||||
* tests
|
||||
* warning about existing image in media directory
|
||||
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
|
||||
line programs.
|
||||
- anime/movie
|
||||
- title
|
||||
- alt title
|
||||
- type (anime movie, movie, anime oav, anime tv series, tv series, etc)
|
||||
- cover/images
|
||||
- genre
|
||||
- lang
|
||||
- sub lang
|
||||
- release date (from - to)
|
||||
- anidb link/imdb link
|
||||
Maybe in future versions. Now text file descriptions/notes and tags have to
|
||||
be enough for good and fast information search.
|
||||
* anime/movie
|
||||
* title
|
||||
* alt title
|
||||
* type (anime movie, movie, anime oav, anime tv series, tv series, etc)
|
||||
* cover/images
|
||||
* genre
|
||||
* lang
|
||||
* sub lang
|
||||
* release date (from - to)
|
||||
* anidb link/imdb link
|
||||
Maybe in future versions. Now text file descriptions/notes and tags have to
|
||||
be enough for good and fast information search.
|
||||
|
||||
NOTES
|
||||
=====
|
||||
-----
|
||||
|
||||
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
|
||||
identical hash for different image files. However, no images are overwritten.
|
||||
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
|
||||
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
|
||||
images without big image will be lost. There are serious changes with
|
||||
deleted. There are some issues with converting. All thumbnails will be lost.
|
||||
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
|
||||
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
|
||||
~/.pygtktalog/images). Functionality for exporting images and corresponding db
|
||||
file is planned.
|
||||
``~/.pygtktalog/images``). Functionality for exporting images and corresponding
|
||||
db file is planned.
|
||||
|
||||
|
||||
DEVELOPMENT
|
||||
===========
|
||||
-----------
|
||||
|
||||
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
|
||||
pavement.py script, which provides several tasks, that can be helpfull in a work
|
||||
with sources. Paver is also used to generate standard setup.py.
|
||||
I've choose `Paver <http://www.blueskyonmars.com/projects/paver/>`_ as make
|
||||
equivalent. Inside main project directory there is pavement.py script, which
|
||||
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
|
||||
====
|
||||
----
|
||||
|
||||
All bugs please report to Roman 'gryf' Dobosz <gryf73@gmail.com>
|
||||
All bugs please report to Roman 'gryf' Dobosz <gryf73@gmail.com>.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"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"
|
||||
"MIME-Version: 1.0\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."
|
||||
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"
|
||||
msgstr "Zakończ aplikację"
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ msgstr ""
|
||||
msgid "Current database is not saved, any changes will be lost."
|
||||
msgstr ""
|
||||
|
||||
#: pygtktalog/controllers/main.py:48
|
||||
#: pygtktalog/controllers/main.py:48 pygtktalog/controllers/main.py:49
|
||||
msgid "Quit application"
|
||||
msgstr ""
|
||||
|
||||
|
||||
14
pavement.py
14
pavement.py
@@ -1,6 +1,8 @@
|
||||
"""
|
||||
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
|
||||
Author: Roman 'gryf' Dobosz, gryf73@gmail.com
|
||||
Created: 2009-05-07
|
||||
@@ -10,10 +12,12 @@ import sys
|
||||
import shutil
|
||||
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.setuputils import setup
|
||||
from paver.misctasks import generate_setup, minilib
|
||||
import paver.doctools
|
||||
|
||||
try:
|
||||
from pylint import lint
|
||||
HAVE_LINT = True
|
||||
@@ -76,6 +80,8 @@ setup(
|
||||
test_suite = 'nose.collector'
|
||||
)
|
||||
|
||||
options(sphinx=Bunch(builddir="build", sourcedir="source"))
|
||||
|
||||
|
||||
@task
|
||||
@needs(['locale_gen', 'minilib', 'generate_setup'])
|
||||
@@ -186,10 +192,10 @@ if HAVE_LINT:
|
||||
|
||||
@task
|
||||
@cmdopts([('coverage', 'c', 'display coverage information')])
|
||||
def test(options):
|
||||
def test(opts):
|
||||
"""run unit tests"""
|
||||
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"
|
||||
os.system(cmd)
|
||||
|
||||
|
||||
@@ -9,8 +9,15 @@ import gtk
|
||||
|
||||
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):
|
||||
"""
|
||||
@@ -21,8 +28,16 @@ class MainController(Controller):
|
||||
"""Initialize main controller"""
|
||||
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):
|
||||
"""Default view registration stuff"""
|
||||
# one row contains image and text
|
||||
view['main'].show()
|
||||
|
||||
def register_adapters(self):
|
||||
@@ -31,21 +46,20 @@ class MainController(Controller):
|
||||
"""
|
||||
pass
|
||||
|
||||
# signals
|
||||
def on_main_destroy_event(self, widget, event):
|
||||
"""Quit"""
|
||||
self.on_quit_activate(widget)
|
||||
return True
|
||||
|
||||
def on_quit_activate(self, widget):
|
||||
"""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?"),
|
||||
_("Current database is not saved, any changes will be "
|
||||
"lost."), _("Quit application") + " - pyGTKtalog", 0):
|
||||
#if yesno(_("Do you really want to quit?"),
|
||||
# _("Current database is not saved, any changes will be "
|
||||
# "lost."), _("Quit application") + " - pyGTKtalog", 0):
|
||||
self.model.cleanup()
|
||||
LOG.debug("quit application")
|
||||
gtk.main_quit()
|
||||
return False
|
||||
|
||||
|
||||
@@ -9,12 +9,20 @@ from sqlalchemy import MetaData, create_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
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
|
||||
Meta = MetaData()
|
||||
Base = declarative_base(metadata=Meta)
|
||||
Session = sessionmaker()
|
||||
|
||||
|
||||
def connect(filename):
|
||||
"""
|
||||
create engine and bind to Meta object.
|
||||
@@ -22,8 +30,8 @@ def connect(filename):
|
||||
@filename - string with absolute or relative path to sqlite database
|
||||
file.
|
||||
"""
|
||||
|
||||
engine = create_engine("sqlite:///%s" % filename, echo=True)
|
||||
get_logger("dbcommon").info("db filename: %s" % filename)
|
||||
engine = create_engine("sqlite:///%s" % filename)
|
||||
Meta.bind = engine
|
||||
Meta.create_all()
|
||||
|
||||
|
||||
50
pygtktalog/logger.py
Normal file
50
pygtktalog/logger.py
Normal 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
|
||||
@@ -5,14 +5,142 @@
|
||||
Author: Roman 'gryf' Dobosz, gryf73@gmail.com
|
||||
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 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")
|
||||
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)))
|
||||
|
||||
76
pygtktalog/views/glade/discs.glade
Normal file
76
pygtktalog/views/glade/discs.glade
Normal 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>
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||
<!--*- mode: xml -*-->
|
||||
<?xml version="1.0"?>
|
||||
<glade-interface>
|
||||
<!-- interface-requires gtk+ 2.16 -->
|
||||
<!-- interface-naming-policy toplevel-contextual -->
|
||||
<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="title" translatable="yes">pyGTKtalog</property>
|
||||
@@ -11,6 +11,7 @@
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<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="orientation">vertical</property>
|
||||
<child>
|
||||
<widget class="GtkMenuBar" id="mainMenubar">
|
||||
<property name="visible">True</property>
|
||||
@@ -23,8 +24,8 @@
|
||||
<widget class="GtkMenu" id="file1_menu">
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="new1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label">gtk-new</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_new_activate"/>
|
||||
@@ -32,8 +33,8 @@
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="open1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label">gtk-open</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_open_activate"/>
|
||||
@@ -41,8 +42,8 @@
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="save1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label">gtk-save</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_save_activate"/>
|
||||
@@ -50,8 +51,8 @@
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="save_as1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label">gtk-save-as</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_save_as_activate"/>
|
||||
@@ -98,8 +99,8 @@
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="quit1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label">gtk-quit</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_quit_activate"/>
|
||||
@@ -119,12 +120,12 @@
|
||||
<widget class="GtkMenu" id="edit1_menu">
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="delete1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label">gtk-delete</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_delete1_activate"/>
|
||||
<accelerator key="Delete" modifiers="" signal="activate"/>
|
||||
<accelerator key="Delete" signal="activate"/>
|
||||
</widget>
|
||||
</child>
|
||||
<child>
|
||||
@@ -134,12 +135,12 @@
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="find1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label">gtk-find</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<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>
|
||||
</child>
|
||||
<child>
|
||||
@@ -149,8 +150,8 @@
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="properties1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label">gtk-preferences</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_preferences_activate"/>
|
||||
@@ -173,7 +174,7 @@
|
||||
<property name="label" translatable="yes">Add _CD/DVD</property>
|
||||
<property name="use_underline">True</property>
|
||||
<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>
|
||||
</child>
|
||||
<child>
|
||||
@@ -182,7 +183,7 @@
|
||||
<property name="label" translatable="yes">Add _Directory</property>
|
||||
<property name="use_underline">True</property>
|
||||
<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>
|
||||
</child>
|
||||
<child>
|
||||
@@ -238,17 +239,11 @@
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="cancel1">
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Cancel</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<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>
|
||||
</child>
|
||||
</widget>
|
||||
@@ -291,8 +286,8 @@
|
||||
<widget class="GtkMenu" id="help1_menu">
|
||||
<child>
|
||||
<widget class="GtkImageMenuItem" id="about1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label">gtk-about</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_about1_activate"/>
|
||||
@@ -306,12 +301,13 @@
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkToolbar" id="maintoolbar">
|
||||
<property name="visible">True</property>
|
||||
<property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
|
||||
<property name="toolbar_style">both</property>
|
||||
<child>
|
||||
<widget class="GtkToolButton" id="tb_new">
|
||||
<property name="visible">True</property>
|
||||
@@ -320,6 +316,7 @@
|
||||
<signal name="clicked" handler="on_new_activate"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
@@ -331,6 +328,7 @@
|
||||
<signal name="clicked" handler="on_open_activate"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
@@ -342,6 +340,7 @@
|
||||
<signal name="clicked" handler="on_save_activate"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
@@ -354,6 +353,9 @@
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkToolButton" id="tb_addcd">
|
||||
@@ -365,6 +367,7 @@
|
||||
<signal name="clicked" handler="on_add_cd_activate"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
@@ -377,6 +380,7 @@
|
||||
<signal name="clicked" handler="on_add_directory_activate"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
@@ -388,6 +392,7 @@
|
||||
<signal name="clicked" handler="on_find_activate"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
@@ -400,6 +405,9 @@
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkToolButton" id="cancel">
|
||||
@@ -411,6 +419,7 @@
|
||||
<signal name="clicked" handler="on_cancel_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
@@ -422,6 +431,7 @@
|
||||
<signal name="clicked" handler="on_quit_activate"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
@@ -443,18 +453,24 @@
|
||||
<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="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>
|
||||
<packing>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkButton" id="clear">
|
||||
<property name="label">gtk-clear</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">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="label" translatable="yes">gtk-clear</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_clear_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
@@ -483,19 +499,10 @@
|
||||
<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="hscrollbar_policy">automatic</property>
|
||||
<property name="vscrollbar_policy">automatic</property>
|
||||
<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>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
@@ -506,8 +513,8 @@
|
||||
<property name="label" translatable="yes">Discs</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="type">tab</property>
|
||||
<property name="tab_fill">False</property>
|
||||
<property name="type">tab</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
@@ -515,23 +522,10 @@
|
||||
<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="hscrollbar_policy">automatic</property>
|
||||
<property name="vscrollbar_policy">automatic</property>
|
||||
<child>
|
||||
<widget class="GtkTextView" id="tag_cloud_textview">
|
||||
<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>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
@@ -545,9 +539,9 @@
|
||||
<property name="label" translatable="yes">Tags</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="type">tab</property>
|
||||
<property name="position">1</property>
|
||||
<property name="tab_fill">False</property>
|
||||
<property name="type">tab</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
@@ -560,24 +554,16 @@
|
||||
<widget class="GtkVPaned" id="vpaned1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</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>
|
||||
<property name="hscrollbar_policy">automatic</property>
|
||||
<property name="vscrollbar_policy">automatic</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="files">
|
||||
<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>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
@@ -586,143 +572,7 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkNotebook" id="notebook_details">
|
||||
<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>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
@@ -753,6 +603,9 @@
|
||||
<property name="visible">True</property>
|
||||
<property name="has_resize_grip">False</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<widget class="GtkProgressBar" id="progressbar1">
|
||||
@@ -774,63 +627,6 @@
|
||||
</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>
|
||||
<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>
|
||||
<child>
|
||||
|
||||
@@ -6,29 +6,110 @@
|
||||
Created: 2009-05-02
|
||||
"""
|
||||
import os.path
|
||||
import gtk
|
||||
|
||||
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):
|
||||
"""
|
||||
Create window from glade file. Note, that glade file is placed in view
|
||||
module under glade subdirectory.
|
||||
"""
|
||||
|
||||
glade = os.path.join(os.path.dirname(__file__), "glade", "main.glade")
|
||||
glade = get_glade("main.glade")
|
||||
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):
|
||||
"""
|
||||
Initialize view
|
||||
"""
|
||||
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
|
||||
|
||||
|
||||
@@ -83,7 +83,8 @@ class Thumbnail(object):
|
||||
if 'Image Orientation' in exif:
|
||||
orient = exif['Image Orientation'].values[0]
|
||||
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)
|
||||
tmp_thumb_img = thumb_image.transpose(orientations[orient])
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
"""
|
||||
import unittest
|
||||
import os
|
||||
from tempfile import mkstemp
|
||||
|
||||
from pygtktalog.dbcommon import connect, Meta, Session, Base
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ class TestVideo(unittest.TestCase):
|
||||
self.assertTrue(filename != None)
|
||||
self.assertTrue(os.path.exists(filename))
|
||||
file_size = os.stat(filename)[6]
|
||||
self.assertEqual(file_size, 9067)
|
||||
self.assertEqual(file_size, 9075)
|
||||
os.unlink(filename)
|
||||
|
||||
for length in (480, 380, 4):
|
||||
|
||||
Reference in New Issue
Block a user