Merge pull request #1237 from scop/fix/editor-fallback
[git-cola.git] / cola / icons.py
blob5d0e4fbe597dd9fe858231cdcdd82b2bece4e152
1 """The only file where icon filenames are mentioned"""
2 from __future__ import absolute_import, division, print_function, unicode_literals
3 import os
5 from qtpy import QtGui
6 from qtpy import QtWidgets
8 from . import core
9 from . import qtcompat
10 from . import resources
11 from .compat import ustr
12 from .i18n import N_
15 KNOWN_FILE_MIME_TYPES = [
16 ('text', 'file-code.svg'),
17 ('image', 'file-media.svg'),
18 ('octet', 'file-binary.svg'),
21 KNOWN_FILE_EXTENSIONS = {
22 '.bash': 'file-code.svg',
23 '.c': 'file-code.svg',
24 '.cpp': 'file-code.svg',
25 '.css': 'file-code.svg',
26 '.cxx': 'file-code.svg',
27 '.h': 'file-code.svg',
28 '.hpp': 'file-code.svg',
29 '.hs': 'file-code.svg',
30 '.html': 'file-code.svg',
31 '.java': 'file-code.svg',
32 '.js': 'file-code.svg',
33 '.ksh': 'file-code.svg',
34 '.lisp': 'file-code.svg',
35 '.perl': 'file-code.svg',
36 '.pl': 'file-code.svg',
37 '.py': 'file-code.svg',
38 '.rb': 'file-code.svg',
39 '.rs': 'file-code.svg',
40 '.sh': 'file-code.svg',
41 '.zsh': 'file-code.svg',
45 def install(themes):
46 for theme in themes:
47 icon_dir = resources.icon_dir(theme)
48 qtcompat.add_search_path('icons', icon_dir)
51 def icon_themes():
52 return (
53 (N_('Default'), 'default'),
54 (N_('Dark Theme'), 'dark'),
55 (N_('Light Theme'), 'light'),
59 def name_from_basename(basename):
60 """Prefix the basename with "icons:" so that git-cola's icons are found
62 "icons" is registered with Qt's resource system during install().
64 """
65 return 'icons:' + basename
68 def from_name(name):
69 """Return a QIcon from an absolute filename or "icons:basename.svg" name"""
70 return QtGui.QIcon(name)
73 def icon(basename):
74 """Given a basename returns a QIcon from the corresponding cola icon"""
75 return from_name(name_from_basename(basename))
78 def from_theme(name, fallback=None):
79 """Grab an icon from the current theme with a fallback
81 Support older versions of Qt checking for fromTheme's availability.
83 """
84 if hasattr(QtGui.QIcon, 'fromTheme'):
85 base, _ = os.path.splitext(name)
86 if fallback:
87 qicon = QtGui.QIcon.fromTheme(base, icon(fallback))
88 else:
89 qicon = QtGui.QIcon.fromTheme(base)
90 if not qicon.isNull():
91 return qicon
92 return icon(fallback or name)
95 def basename_from_filename(filename):
96 """Returns an icon name based on the filename"""
97 mimetype = core.guess_mimetype(filename)
98 if mimetype is not None:
99 mimetype = mimetype.lower()
100 for filetype, icon_name in KNOWN_FILE_MIME_TYPES:
101 if filetype in mimetype:
102 return icon_name
103 extension = os.path.splitext(filename)[1]
104 return KNOWN_FILE_EXTENSIONS.get(extension.lower(), 'file-text.svg')
107 def from_filename(filename):
108 basename = basename_from_filename(filename)
109 return from_name(name_from_basename(basename))
112 def mkicon(value, default=None):
113 if value is None and default is not None:
114 value = default()
115 elif value and isinstance(value, (str, ustr)):
116 value = QtGui.QIcon(value)
117 return value
120 def from_style(key):
121 """Maintain a cache of standard icons and return cache entries."""
122 style = QtWidgets.QApplication.instance().style()
123 return style.standardIcon(key)
126 def status(filename, deleted, is_staged, untracked):
127 if deleted:
128 icon_name = 'circle-slash-red.svg'
129 elif is_staged:
130 icon_name = 'staged.svg'
131 elif untracked:
132 icon_name = 'question-plain.svg'
133 else:
134 icon_name = basename_from_filename(filename)
135 return icon_name
138 # Icons creators and SVG file references
141 def three_bars():
142 return icon('three-bars.svg')
145 def add():
146 return from_theme('list-add', fallback='plus.svg')
149 def alphabetical():
150 return from_theme('view-sort', fallback='a-z-order.svg')
153 def branch():
154 return icon('git-branch.svg')
157 def check_name():
158 return name_from_basename('check.svg')
161 def cherry_pick():
162 return icon('git-commit.svg')
165 def close():
166 return icon('x.svg')
169 def cola():
170 return icon('git-cola.svg')
173 def commit():
174 return icon('document-save-symbolic.svg')
177 def compare():
178 return icon('git-compare.svg')
181 def configure():
182 return icon('gear.svg')
185 def cut():
186 return from_theme('edit-cut', fallback='edit-cut.svg')
189 def copy():
190 return from_theme('edit-copy', fallback='edit-copy.svg')
193 def paste():
194 return from_theme('edit-paste', fallback='edit-paste.svg')
197 def delete():
198 return from_theme('edit-delete', fallback='trashcan.svg')
201 def default_app():
202 return icon('telescope.svg')
205 def dot_name():
206 return name_from_basename('primitive-dot.svg')
209 def download():
210 return icon('file-download.svg')
213 def discard():
214 return from_theme('delete', fallback='trashcan.svg')
217 # folder vs directory: directory is opaque, folder is just an outline
218 # directory is used for the File Browser, where more contrast with the file
219 # icons are needed.
222 def folder():
223 return from_theme('folder', fallback='folder.svg')
226 def directory():
227 return from_theme('folder', fallback='file-directory.svg')
230 def diff():
231 return icon('diff.svg')
234 def edit():
235 return from_theme('document-edit', fallback='pencil.svg')
238 def ellipsis():
239 return icon('ellipsis.svg')
242 def external():
243 return icon('link-external.svg')
246 def file_code():
247 return icon('file-code.svg')
250 def file_text():
251 return icon('file-text.svg')
254 def file_zip():
255 return icon('file-zip.svg')
258 def fold():
259 return icon('fold.svg')
262 def merge():
263 return icon('git-merge.svg')
266 def modified():
267 return icon('modified.svg')
270 def modified_name():
271 return name_from_basename('modified.svg')
274 def move_down():
275 return from_theme('go-previous', fallback='arrow-down.svg')
278 def move_up():
279 return from_theme('go-next', fallback='arrow-up.svg')
282 def new():
283 return from_theme('list-add', fallback='folder-new.svg')
286 def ok():
287 return from_theme('checkmark', fallback='check.svg')
290 def open_directory():
291 return from_theme('folder', fallback='folder.svg')
294 def partial_name():
295 return name_from_basename('partial.svg')
298 def pull():
299 return icon('repo-pull.svg')
302 def push():
303 return icon('repo-push.svg')
306 def question():
307 return icon('question.svg')
310 def remove():
311 return from_theme('list-remove', fallback='circle-slash.svg')
314 def repo():
315 return icon('repo.svg')
318 def reverse_chronological():
319 return icon('last-first-order.svg')
322 def save():
323 return from_theme('document-save', fallback='desktop-download.svg')
326 def search():
327 return from_theme('search', fallback='search.svg')
330 def select_all():
331 return from_theme('edit-select-all', fallback='edit-select-all')
334 def staged():
335 return icon('staged.svg')
338 def staged_name():
339 return name_from_basename('staged.svg')
342 def star():
343 return icon('star.svg')
346 def sync():
347 return icon('sync.svg')
350 def tag():
351 return icon('tag.svg')
354 def undo():
355 return from_theme('edit-undo', fallback='edit-undo.svg')
358 def redo():
359 return from_theme('edit-redo', fallback='edit-redo.svg')
362 def style_dialog_apply():
363 return from_style(QtWidgets.QStyle.SP_DialogApplyButton)
366 def style_dialog_discard():
367 return from_style(QtWidgets.QStyle.SP_DialogDiscardButton)
370 def style_dialog_reset():
371 return from_style(QtWidgets.QStyle.SP_DialogResetButton)
374 def unfold():
375 return icon('unfold.svg')
378 def visualize():
379 return icon('eye.svg')
382 def upstream_name():
383 return name_from_basename('upstream.svg')
386 def zoom_fit_best():
387 return from_theme('zoom-fit-best', fallback='zoom-fit-best.svg')
390 def zoom_in():
391 return from_theme('zoom-in', fallback='zoom-in.svg')
394 def zoom_out():
395 return from_theme('zoom-out', fallback='zoom-out.svg')