mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Allow user customization of static resources
This commit is contained in:
parent
241b2a4841
commit
6fa16aa3fa
@ -2,6 +2,7 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2008, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import sys, os, re, logging, time, mimetypes, \
|
import sys, os, re, logging, time, mimetypes, \
|
||||||
__builtin__, warnings, multiprocessing
|
__builtin__, warnings, multiprocessing
|
||||||
from urllib import getproxies
|
from urllib import getproxies
|
||||||
@ -13,12 +14,13 @@ from functools import partial
|
|||||||
warnings.simplefilter('ignore', DeprecationWarning)
|
warnings.simplefilter('ignore', DeprecationWarning)
|
||||||
|
|
||||||
|
|
||||||
from calibre.startup import plugins, winutil, winutilerror
|
|
||||||
from calibre.constants import iswindows, isosx, islinux, isfreebsd, isfrozen, \
|
from calibre.constants import iswindows, isosx, islinux, isfreebsd, isfrozen, \
|
||||||
terminal_controller, preferred_encoding, \
|
terminal_controller, preferred_encoding, \
|
||||||
__appname__, __version__, __author__, \
|
__appname__, __version__, __author__, \
|
||||||
win32event, win32api, winerror, fcntl, \
|
win32event, win32api, winerror, fcntl, \
|
||||||
filesystem_encoding
|
filesystem_encoding, plugins, config_dir
|
||||||
|
from calibre.startup import winutil, winutilerror
|
||||||
|
|
||||||
import mechanize
|
import mechanize
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
@ -486,7 +488,6 @@ def ipython(user_ns=None):
|
|||||||
sys.argv = ['ipython']
|
sys.argv = ['ipython']
|
||||||
if user_ns is None:
|
if user_ns is None:
|
||||||
user_ns = locals()
|
user_ns = locals()
|
||||||
from calibre.utils.config import config_dir
|
|
||||||
ipydir = os.path.join(config_dir, ('_' if iswindows else '.')+'ipython')
|
ipydir = os.path.join(config_dir, ('_' if iswindows else '.')+'ipython')
|
||||||
os.environ['IPYTHONDIR'] = ipydir
|
os.environ['IPYTHONDIR'] = ipydir
|
||||||
if not os.path.exists(ipydir):
|
if not os.path.exists(ipydir):
|
||||||
|
@ -14,7 +14,7 @@ numeric_version = tuple(_ver)
|
|||||||
Various run time constants.
|
Various run time constants.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import sys, locale, codecs
|
import sys, locale, codecs, os
|
||||||
from calibre.utils.terminfo import TerminalController
|
from calibre.utils.terminfo import TerminalController
|
||||||
|
|
||||||
terminal_controller = TerminalController(sys.stdout)
|
terminal_controller = TerminalController(sys.stdout)
|
||||||
@ -47,7 +47,7 @@ def debug():
|
|||||||
global DEBUG
|
global DEBUG
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
|
|
||||||
################################################################################
|
# plugins {{{
|
||||||
plugins = None
|
plugins = None
|
||||||
if plugins is None:
|
if plugins is None:
|
||||||
# Load plugins
|
# Load plugins
|
||||||
@ -80,3 +80,22 @@ if plugins is None:
|
|||||||
return plugins
|
return plugins
|
||||||
|
|
||||||
plugins = load_plugins()
|
plugins = load_plugins()
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
# config_dir {{{
|
||||||
|
if os.environ.has_key('CALIBRE_CONFIG_DIRECTORY'):
|
||||||
|
config_dir = os.path.abspath(os.environ['CALIBRE_CONFIG_DIRECTORY'])
|
||||||
|
elif iswindows:
|
||||||
|
if plugins['winutil'][0] is None:
|
||||||
|
raise Exception(plugins['winutil'][1])
|
||||||
|
config_dir = plugins['winutil'][0].special_folder_path(plugins['winutil'][0].CSIDL_APPDATA)
|
||||||
|
if not os.access(config_dir, os.W_OK|os.X_OK):
|
||||||
|
config_dir = os.path.expanduser('~')
|
||||||
|
config_dir = os.path.join(config_dir, 'calibre')
|
||||||
|
elif isosx:
|
||||||
|
config_dir = os.path.expanduser('~/Library/Preferences/calibre')
|
||||||
|
else:
|
||||||
|
bdir = os.path.abspath(os.path.expanduser(os.environ.get('XDG_CONFIG_HOME', '~/.config')))
|
||||||
|
config_dir = os.path.join(bdir, 'calibre')
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
@ -9,7 +9,8 @@ Customizing |app|
|
|||||||
|
|
||||||
|app| has a highly modular design. Various parts of it can be customized. You can learn how to create
|
|app| has a highly modular design. Various parts of it can be customized. You can learn how to create
|
||||||
*recipes* to add new sources of online content to |app| in the Section :ref:`news`. Here, you will learn,
|
*recipes* to add new sources of online content to |app| in the Section :ref:`news`. Here, you will learn,
|
||||||
first, how to use environment variables and *tweaks* to customize |app|'s behavior and then how to
|
first, how to use environment variables and *tweaks* to customize |app|'s behavior, and then how to
|
||||||
|
specify your own static resources like icons and templates to override the defaults and finally how to
|
||||||
use *plugins* to add funtionality to |app|.
|
use *plugins* to add funtionality to |app|.
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
@ -35,6 +36,20 @@ The default tweaks.py file is reproduced below
|
|||||||
.. literalinclude:: ../../../resources/default_tweaks.py
|
.. literalinclude:: ../../../resources/default_tweaks.py
|
||||||
|
|
||||||
|
|
||||||
|
Overriding icons, templates, etcetera
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
|app| allows you to override the static resources, like icons, templates, javascript, etc. with customized versions that you like.
|
||||||
|
All static resources are stored in the resources sub-folder of the calibre install location. On Windows, this is usually
|
||||||
|
:file:`C:\Program Files\Calibre2\resources`. On OS X, :file:`/Applications/calibre.app/Contents/Resources/resources/`. On linux, if you are using the binary installer
|
||||||
|
from the calibre website it will be :file:`/opt/calibre/resources`. These paths can change depending on where you choose to install |app|.
|
||||||
|
|
||||||
|
You should not change the files in this resources folder, as your changes will get overwritten the next time you update |app|. Instead, go to
|
||||||
|
:guilabel:`Preferences->Advanced` and click :guilabel:`Open calibre configuration directory`. In this configuration directory, create a sub-folder called resources and place the files you want to override in it. |app| will automatically use your custom file in preference to the builtin one the next time it is started.
|
||||||
|
|
||||||
|
For example, if you wanted to change the icon for the :guilabel:`Remove books` action, you would first look in the builtin resources folder and see that the relevant file is
|
||||||
|
:file:`resources/images/trash.svg`. Assuming you have an alternate icon in svg format called :file:`mytrash.svg` you would save it in the configuration directory as :file:`resources/images/trash.svg`. All the icons used by the calibre user interface are in :file:`resources/images` and its sub-folders.
|
||||||
|
|
||||||
A Hello World plugin
|
A Hello World plugin
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
@ -13,25 +13,10 @@ from optparse import OptionParser as _OptionParser
|
|||||||
from optparse import IndentedHelpFormatter
|
from optparse import IndentedHelpFormatter
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from calibre.constants import terminal_controller, iswindows, isosx, \
|
from calibre.constants import terminal_controller, config_dir, \
|
||||||
__appname__, __version__, __author__, plugins
|
__appname__, __version__, __author__
|
||||||
from calibre.utils.lock import LockError, ExclusiveFile
|
from calibre.utils.lock import LockError, ExclusiveFile
|
||||||
|
|
||||||
if os.environ.has_key('CALIBRE_CONFIG_DIRECTORY'):
|
|
||||||
config_dir = os.path.abspath(os.environ['CALIBRE_CONFIG_DIRECTORY'])
|
|
||||||
elif iswindows:
|
|
||||||
if plugins['winutil'][0] is None:
|
|
||||||
raise Exception(plugins['winutil'][1])
|
|
||||||
config_dir = plugins['winutil'][0].special_folder_path(plugins['winutil'][0].CSIDL_APPDATA)
|
|
||||||
if not os.access(config_dir, os.W_OK|os.X_OK):
|
|
||||||
config_dir = os.path.expanduser('~')
|
|
||||||
config_dir = os.path.join(config_dir, 'calibre')
|
|
||||||
elif isosx:
|
|
||||||
config_dir = os.path.expanduser('~/Library/Preferences/calibre')
|
|
||||||
else:
|
|
||||||
bdir = os.path.abspath(os.path.expanduser(os.environ.get('XDG_CONFIG_HOME', '~/.config')))
|
|
||||||
config_dir = os.path.join(bdir, 'calibre')
|
|
||||||
|
|
||||||
plugin_dir = os.path.join(config_dir, 'plugins')
|
plugin_dir = os.path.join(config_dir, 'plugins')
|
||||||
|
|
||||||
CONFIG_DIR_MODE = 0700
|
CONFIG_DIR_MODE = 0700
|
||||||
|
@ -9,26 +9,54 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import __builtin__, sys, os
|
import __builtin__, sys, os
|
||||||
|
|
||||||
_dev_path = os.environ.get('CALIBRE_DEVELOP_FROM', None)
|
from calibre import config_dir
|
||||||
if _dev_path is not None:
|
|
||||||
_dev_path = os.path.join(os.path.abspath(os.path.dirname(_dev_path)), 'resources')
|
|
||||||
if not os.path.exists(_dev_path):
|
|
||||||
_dev_path = None
|
|
||||||
|
|
||||||
_path_cache = {}
|
class PathResolver(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.locations = [sys.resources_location]
|
||||||
|
self.cache = {}
|
||||||
|
|
||||||
|
def suitable(path):
|
||||||
|
try:
|
||||||
|
return os.path.exists(path) and os.path.isdir(path) and \
|
||||||
|
os.listdir(path)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
dev_path = os.environ.get('CALIBRE_DEVELOP_FROM', None)
|
||||||
|
if dev_path is not None:
|
||||||
|
dev_path = os.path.join(os.path.abspath(
|
||||||
|
os.path.dirname(dev_path)), 'resources')
|
||||||
|
if suitable(dev_path):
|
||||||
|
self.locations.insert(0, dev_path)
|
||||||
|
|
||||||
|
user_path = os.path.join(config_dir, 'resources')
|
||||||
|
if suitable(user_path):
|
||||||
|
self.locations.insert(0, user_path)
|
||||||
|
|
||||||
|
def __call__(self, path):
|
||||||
|
path = path.replace(os.sep, '/')
|
||||||
|
ans = self.cache.get(path, None)
|
||||||
|
if ans is None:
|
||||||
|
for base in self.locations:
|
||||||
|
fpath = os.path.join(base, *path.split('/'))
|
||||||
|
if os.path.exists(fpath):
|
||||||
|
ans = fpath
|
||||||
|
break
|
||||||
|
|
||||||
|
if ans is None:
|
||||||
|
ans = os.path.join(self.location[0], *path.split('/'))
|
||||||
|
|
||||||
|
self.cache[path] = ans
|
||||||
|
|
||||||
|
return ans
|
||||||
|
|
||||||
|
_resolver = PathResolver()
|
||||||
|
|
||||||
def get_path(path, data=False):
|
def get_path(path, data=False):
|
||||||
global _dev_path
|
fpath = _resolver(path)
|
||||||
path = path.replace(os.sep, '/')
|
|
||||||
base = sys.resources_location
|
|
||||||
if _dev_path is not None:
|
|
||||||
if path in _path_cache:
|
|
||||||
return _path_cache[path]
|
|
||||||
if os.path.exists(os.path.join(_dev_path, *path.split('/'))):
|
|
||||||
base = _dev_path
|
|
||||||
fpath = os.path.join(base, *path.split('/'))
|
|
||||||
if _dev_path is not None:
|
|
||||||
_path_cache[path] = fpath
|
|
||||||
if data:
|
if data:
|
||||||
return open(fpath, 'rb').read()
|
return open(fpath, 'rb').read()
|
||||||
return fpath
|
return fpath
|
||||||
|
Loading…
x
Reference in New Issue
Block a user