Merge pull request #515 from Zeioth/patch-1
[git-cola.git] / cola / settings.py
blob2721cf9e5da141b327851fab31742e3897bf84d6
1 # Copyright (c) 2008 David Aguilar
2 """This handles saving complex settings such as bookmarks, etc.
3 """
4 from __future__ import division, absolute_import, unicode_literals
6 import os
7 import sys
9 from cola import core
10 from cola import git
11 from cola import resources
12 import json
15 def mkdict(obj):
16 if type(obj) is dict:
17 return obj
18 else:
19 return {}
22 def mklist(obj):
23 if type(obj) is list:
24 return obj
25 else:
26 return []
29 def read_json(path):
30 try:
31 with core.xopen(path, 'rt') as fp:
32 return mkdict(json.load(fp))
33 except: # bad path or json
34 return {}
37 def write_json(values, path):
38 try:
39 parent = os.path.dirname(path)
40 if not core.isdir(parent):
41 core.makedirs(parent)
42 with core.xopen(path, 'wt') as fp:
43 json.dump(values, fp, indent=4)
44 except:
45 sys.stderr.write('git-cola: error writing "%s"\n' % path)
48 class Settings(object):
49 _file = resources.config_home('settings')
50 bookmarks = property(lambda self: mklist(self.values['bookmarks']))
51 gui_state = property(lambda self: mkdict(self.values['gui_state']))
52 recent = property(lambda self: mklist(self.values['recent']))
54 def __init__(self, verify=git.is_git_worktree):
55 """Load existing settings if they exist"""
56 self.values = {
57 'bookmarks': [],
58 'gui_state': {},
59 'recent': [],
61 self.verify = verify
63 def remove_missing(self):
64 missing_bookmarks = []
65 missing_recent = []
67 for bookmark in self.bookmarks:
68 if not self.verify(bookmark):
69 missing_bookmarks.append(bookmark)
71 for bookmark in missing_bookmarks:
72 try:
73 self.bookmarks.remove(bookmark)
74 except:
75 pass
77 for recent in self.recent:
78 if not self.verify(recent):
79 missing_recent.append(recent)
81 for recent in missing_recent:
82 try:
83 self.recent.remove(recent)
84 except:
85 pass
87 def add_bookmark(self, bookmark):
88 """Adds a bookmark to the saved settings"""
89 if bookmark not in self.bookmarks:
90 self.bookmarks.append(bookmark)
92 def remove_bookmark(self, bookmark):
93 """Remove a bookmark"""
94 if bookmark in self.bookmarks:
95 self.bookmarks.remove(bookmark)
97 def remove_recent(self, entry):
98 """Removes an item from the recent items list"""
99 if entry in self.recent:
100 self.recent.remove(entry)
102 def add_recent(self, entry):
103 if entry in self.recent:
104 self.recent.remove(entry)
105 self.recent.insert(0, entry)
106 if len(self.recent) >= 8:
107 self.recent.pop()
109 def path(self):
110 return self._file
112 def save(self):
113 write_json(self.values, self.path())
115 def load(self):
116 self.values.update(self.asdict())
117 self.remove_missing()
119 def asdict(self):
120 path = self.path()
121 if core.exists(path):
122 return read_json(path)
123 # We couldn't find ~/.config/git-cola, try ~/.cola
124 values = {}
125 path = os.path.join(core.expanduser('~'), '.cola')
126 if core.exists(path):
127 json_values = read_json(path)
128 # Keep only the entries we care about
129 for key in self.values:
130 try:
131 values[key] = json_values[key]
132 except KeyError:
133 pass
134 return values
136 def reload_recent(self):
137 values = self.asdict()
138 self.values['recent'] = mklist(values.get('recent', []))
140 def save_gui_state(self, gui):
141 """Saves settings for a cola view"""
142 name = gui.name()
143 self.gui_state[name] = mkdict(gui.export_state())
144 self.save()
146 def get_gui_state(self, gui):
147 """Returns the saved state for a gui"""
148 try:
149 state = mkdict(self.gui_state[gui.name()])
150 except KeyError:
151 state = self.gui_state[gui.name()] = {}
152 return state
155 class Session(Settings):
156 """Store per-session settings"""
158 _sessions_dir = resources.config_home('sessions')
160 repo = property(lambda self: self.values['repo'])
162 def __init__(self, session_id, repo=None):
163 Settings.__init__(self)
164 self.session_id = session_id
165 self.values.update({'repo': repo})
167 def path(self):
168 return os.path.join(self._sessions_dir, self.session_id)
170 def load(self):
171 path = self.path()
172 if core.exists(path):
173 self.values.update(read_json(path))
174 try:
175 os.unlink(path)
176 except:
177 pass
178 return True
179 return False