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'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import sys, os, re, logging, time, mimetypes, \
|
||||
__builtin__, warnings, multiprocessing
|
||||
from urllib import getproxies
|
||||
@ -13,12 +14,13 @@ from functools import partial
|
||||
warnings.simplefilter('ignore', DeprecationWarning)
|
||||
|
||||
|
||||
from calibre.startup import plugins, winutil, winutilerror
|
||||
from calibre.constants import iswindows, isosx, islinux, isfreebsd, isfrozen, \
|
||||
terminal_controller, preferred_encoding, \
|
||||
__appname__, __version__, __author__, \
|
||||
win32event, win32api, winerror, fcntl, \
|
||||
filesystem_encoding
|
||||
filesystem_encoding, plugins, config_dir
|
||||
from calibre.startup import winutil, winutilerror
|
||||
|
||||
import mechanize
|
||||
|
||||
if False:
|
||||
@ -486,7 +488,6 @@ def ipython(user_ns=None):
|
||||
sys.argv = ['ipython']
|
||||
if user_ns is None:
|
||||
user_ns = locals()
|
||||
from calibre.utils.config import config_dir
|
||||
ipydir = os.path.join(config_dir, ('_' if iswindows else '.')+'ipython')
|
||||
os.environ['IPYTHONDIR'] = ipydir
|
||||
if not os.path.exists(ipydir):
|
||||
|
@ -14,7 +14,7 @@ numeric_version = tuple(_ver)
|
||||
Various run time constants.
|
||||
'''
|
||||
|
||||
import sys, locale, codecs
|
||||
import sys, locale, codecs, os
|
||||
from calibre.utils.terminfo import TerminalController
|
||||
|
||||
terminal_controller = TerminalController(sys.stdout)
|
||||
@ -47,7 +47,7 @@ def debug():
|
||||
global DEBUG
|
||||
DEBUG = True
|
||||
|
||||
################################################################################
|
||||
# plugins {{{
|
||||
plugins = None
|
||||
if plugins is None:
|
||||
# Load plugins
|
||||
@ -80,3 +80,22 @@ if plugins is None:
|
||||
return 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
|
||||
*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|.
|
||||
|
||||
.. contents::
|
||||
@ -35,6 +36,20 @@ The default tweaks.py file is reproduced below
|
||||
.. 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
|
||||
------------------------
|
||||
|
||||
|
@ -13,25 +13,10 @@ from optparse import OptionParser as _OptionParser
|
||||
from optparse import IndentedHelpFormatter
|
||||
from collections import defaultdict
|
||||
|
||||
from calibre.constants import terminal_controller, iswindows, isosx, \
|
||||
__appname__, __version__, __author__, plugins
|
||||
from calibre.constants import terminal_controller, config_dir, \
|
||||
__appname__, __version__, __author__
|
||||
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')
|
||||
|
||||
CONFIG_DIR_MODE = 0700
|
||||
|
@ -9,26 +9,54 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
import __builtin__, sys, os
|
||||
|
||||
_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 not os.path.exists(_dev_path):
|
||||
_dev_path = None
|
||||
from calibre import config_dir
|
||||
|
||||
_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):
|
||||
global _dev_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
|
||||
fpath = _resolver(path)
|
||||
if data:
|
||||
return open(fpath, 'rb').read()
|
||||
return fpath
|
||||
|
Loading…
x
Reference in New Issue
Block a user