prefs: group checkboxes for a better visual flow
[git-cola.git] / cola / widgets / prefs.py
blobcd7589b1a9db7dac877a81d9b4be8088337ab1c0
1 from __future__ import division, absolute_import, unicode_literals
2 import os
4 from qtpy import QtCore
5 from qtpy import QtWidgets
7 from ..i18n import N_
8 from ..models import prefs
9 from .. import cmds
10 from .. import qtutils
11 from . import defs
12 from . import standard
15 def preferences(context, model=None, parent=None):
16 if model is None:
17 model = prefs.PreferencesModel(context)
18 view = PreferencesView(context, model, parent=parent)
19 view.show()
20 view.raise_()
21 return view
24 class FormWidget(QtWidgets.QWidget):
26 def __init__(self, context, model, parent, source='user'):
27 QtWidgets.QWidget.__init__(self, parent)
28 self.context = context
29 self.cfg = context.cfg
30 self.model = model
31 self.config_to_widget = {}
32 self.widget_to_config = {}
33 self.source = source
34 self.defaults = {}
35 self.setLayout(QtWidgets.QFormLayout())
37 def add_row(self, label, widget):
38 self.layout().addRow(label, widget)
40 def set_config(self, config_dict):
41 self.config_to_widget.update(config_dict)
42 for config, (widget, default) in config_dict.items():
43 self.widget_to_config[config] = widget
44 self.defaults[config] = default
45 self.connect_widget_to_config(widget, config)
47 def connect_widget_to_config(self, widget, config):
48 if isinstance(widget, QtWidgets.QSpinBox):
49 widget.valueChanged.connect(self._int_config_changed(config))
51 elif isinstance(widget, QtWidgets.QCheckBox):
52 widget.toggled.connect(self._bool_config_changed(config))
54 elif isinstance(widget, QtWidgets.QLineEdit):
55 widget.editingFinished.connect(
56 self._text_config_changed(config, widget))
57 widget.returnPressed.connect(
58 self._text_config_changed(config, widget))
60 def _int_config_changed(self, config):
61 def runner(value):
62 cmds.do(prefs.SetConfig, self.model, self.source, config, value)
63 return runner
65 def _bool_config_changed(self, config):
66 def runner(value):
67 cmds.do(prefs.SetConfig, self.model, self.source, config, value)
68 return runner
70 def _text_config_changed(self, config, widget):
71 def runner():
72 value = widget.text()
73 cmds.do(prefs.SetConfig, self.model, self.source, config, value)
74 return runner
76 def update_from_config(self):
77 if self.source == 'user':
78 getter = self.cfg.get_user_or_system
79 else:
80 getter = self.cfg.get
82 for config, widget in self.widget_to_config.items():
83 value = getter(config)
84 if value is None:
85 value = self.defaults[config]
86 self.set_widget_value(widget, value)
88 def set_widget_value(self, widget, value):
89 widget.blockSignals(True)
90 if isinstance(widget, QtWidgets.QSpinBox):
91 widget.setValue(value)
92 elif isinstance(widget, QtWidgets.QLineEdit):
93 widget.setText(value)
94 elif isinstance(widget, QtWidgets.QCheckBox):
95 widget.setChecked(value)
96 widget.blockSignals(False)
99 class RepoFormWidget(FormWidget):
101 def __init__(self, context, model, parent, source):
102 FormWidget.__init__(self, context, model, parent, source=source)
103 self.name = QtWidgets.QLineEdit()
104 self.email = QtWidgets.QLineEdit()
106 self.merge_verbosity = standard.SpinBox(value=5, maxi=5)
107 self.diff_context = standard.SpinBox(value=5, mini=2, maxi=9995)
109 self.merge_summary = qtutils.checkbox(checked=True)
110 self.merge_diffstat = qtutils.checkbox(checked=True)
111 self.display_untracked = qtutils.checkbox(checked=True)
112 self.show_path = qtutils.checkbox(checked=True)
114 tooltip = N_('Detect conflict markers in unmerged files')
115 self.check_conflicts = qtutils.checkbox(checked=True, tooltip=tooltip)
117 tooltip = N_(
118 'Prevent "Stage" from staging all files when nothing is selected')
119 self.safe_mode = qtutils.checkbox(checked=False, tooltip=tooltip)
121 self.add_row(N_('User Name'), self.name)
122 self.add_row(N_('Email Address'), self.email)
123 self.add_row(N_('Merge Verbosity'), self.merge_verbosity)
124 self.add_row(N_('Number of Diff Context Lines'), self.diff_context)
125 self.add_row(N_('Summarize Merge Commits'), self.merge_summary)
126 self.add_row(N_('Show Full Paths in the Window Title'), self.show_path)
127 self.add_row(N_('Show Diffstat After Merge'), self.merge_diffstat)
128 self.add_row(N_('Display Untracked Files'), self.display_untracked)
129 self.add_row(N_('Detect Conflict Markers'), self.check_conflicts)
130 self.add_row(N_('Safe Mode'), self.safe_mode)
132 self.set_config({
133 prefs.CHECKCONFLICTS: (self.check_conflicts, True),
134 prefs.DIFFCONTEXT: (self.diff_context, 5),
135 prefs.DISPLAY_UNTRACKED: (self.display_untracked, True),
136 prefs.USER_NAME: (self.name, ''),
137 prefs.USER_EMAIL: (self.email, ''),
138 prefs.MERGE_DIFFSTAT: (self.merge_diffstat, True),
139 prefs.MERGE_SUMMARY: (self.merge_summary, True),
140 prefs.MERGE_VERBOSITY: (self.merge_verbosity, 5),
141 prefs.SAFE_MODE: (self.safe_mode, False),
142 prefs.SHOW_PATH: (self.show_path, True),
146 class SettingsFormWidget(FormWidget):
148 def __init__(self, context, model, parent):
149 FormWidget.__init__(self, context, model, parent)
151 self.fixed_font = QtWidgets.QFontComboBox()
152 self.font_size = standard.SpinBox(value=12, mini=8, maxi=192)
154 self.maxrecent = standard.SpinBox(maxi=99)
155 self.tabwidth = standard.SpinBox(maxi=42)
156 self.textwidth = standard.SpinBox(maxi=150)
158 self.editor = QtWidgets.QLineEdit()
159 self.historybrowser = QtWidgets.QLineEdit()
160 self.blameviewer = QtWidgets.QLineEdit()
161 self.difftool = QtWidgets.QLineEdit()
162 self.mergetool = QtWidgets.QLineEdit()
164 self.linebreak = qtutils.checkbox()
165 self.keep_merge_backups = qtutils.checkbox()
166 self.sort_bookmarks = qtutils.checkbox()
167 self.bold_headers = qtutils.checkbox()
168 self.save_gui_settings = qtutils.checkbox()
169 self.check_spelling = qtutils.checkbox()
170 self.expandtab = qtutils.checkbox()
172 self.add_row(N_('Fixed-Width Font'), self.fixed_font)
173 self.add_row(N_('Font Size'), self.font_size)
174 self.add_row(N_('Tab Width'), self.tabwidth)
175 self.add_row(N_('Text Width'), self.textwidth)
176 self.add_row(N_('Editor'), self.editor)
177 self.add_row(N_('History Browser'), self.historybrowser)
178 self.add_row(N_('Blame Viewer'), self.blameviewer)
179 self.add_row(N_('Diff Tool'), self.difftool)
180 self.add_row(N_('Merge Tool'), self.mergetool)
181 self.add_row(N_('Recent repository count'), self.maxrecent)
182 self.add_row(N_('Auto-Wrap Lines'), self.linebreak)
183 self.add_row(N_('Insert spaces instead of tabs'), self.expandtab)
184 self.add_row(N_('Sort bookmarks alphabetically'), self.sort_bookmarks)
185 self.add_row(N_('Keep *.orig Merge Backups'), self.keep_merge_backups)
186 self.add_row(N_('Bold with dark background font instead of italic '
187 'headers (restart required)'), self.bold_headers)
188 self.add_row(N_('Save GUI Settings'), self.save_gui_settings)
189 self.add_row(N_('Check spelling'), self.check_spelling)
191 self.set_config({
192 prefs.SAVEWINDOWSETTINGS: (self.save_gui_settings, True),
193 prefs.TABWIDTH: (self.tabwidth, 8),
194 prefs.EXPANDTAB: (self.expandtab, False),
195 prefs.TEXTWIDTH: (self.textwidth, 72),
196 prefs.LINEBREAK: (self.linebreak, True),
197 prefs.MAXRECENT: (self.maxrecent, 8),
198 prefs.SORT_BOOKMARKS: (self.sort_bookmarks, True),
199 prefs.BOLD_HEADERS: (self.bold_headers, False),
200 prefs.DIFFTOOL: (self.difftool, 'xxdiff'),
201 prefs.EDITOR: (self.editor, os.getenv('VISUAL', 'gvim')),
202 prefs.HISTORY_BROWSER: (self.historybrowser,
203 prefs.default_history_browser()),
204 prefs.BLAME_VIEWER: (self.blameviewer,
205 prefs.default_blame_viewer()),
206 prefs.MERGE_KEEPBACKUP: (self.keep_merge_backups, True),
207 prefs.MERGETOOL: (self.mergetool, 'xxdiff'),
208 prefs.SPELL_CHECK: (self.check_spelling, False),
211 self.fixed_font.currentFontChanged.connect(self.current_font_changed)
212 self.font_size.valueChanged.connect(self.font_size_changed)
214 def update_from_config(self):
215 FormWidget.update_from_config(self)
216 context = self.context
217 block = self.fixed_font.blockSignals(True)
218 font = qtutils.diff_font(context)
219 self.fixed_font.setCurrentFont(font)
220 self.fixed_font.blockSignals(block)
222 block = self.font_size.blockSignals(True)
223 font_size = font.pointSize()
224 self.font_size.setValue(font_size)
225 self.font_size.blockSignals(block)
227 def font_size_changed(self, size):
228 font = self.fixed_font.currentFont()
229 font.setPointSize(size)
230 cmds.do(prefs.SetConfig, self.model,
231 'user', prefs.FONTDIFF, font.toString())
233 def current_font_changed(self, font):
234 cmds.do(prefs.SetConfig, self.model,
235 'user', prefs.FONTDIFF, font.toString())
238 class PreferencesView(standard.Dialog):
240 def __init__(self, context, model, parent=None):
241 standard.Dialog.__init__(self, parent=parent)
242 self.context = context
243 self.setWindowTitle(N_('Preferences'))
244 if parent is not None:
245 self.setWindowModality(QtCore.Qt.WindowModal)
247 self.resize(600, 360)
249 self.tab_bar = QtWidgets.QTabBar()
250 self.tab_bar.setDrawBase(False)
251 self.tab_bar.addTab(N_('All Repositories'))
252 self.tab_bar.addTab(N_('Current Repository'))
253 self.tab_bar.addTab(N_('Settings'))
255 self.user_form = RepoFormWidget(context, model, self, source='user')
256 self.repo_form = RepoFormWidget(context, model, self, source='repo')
257 self.options_form = SettingsFormWidget(context, model, self)
259 self.stack_widget = QtWidgets.QStackedWidget()
260 self.stack_widget.addWidget(self.user_form)
261 self.stack_widget.addWidget(self.repo_form)
262 self.stack_widget.addWidget(self.options_form)
264 self.close_button = qtutils.close_button()
266 self.button_layout = qtutils.hbox(defs.no_margin, defs.spacing,
267 qtutils.STRETCH, self.close_button)
269 self.main_layout = qtutils.vbox(defs.margin, defs.spacing,
270 self.tab_bar, self.stack_widget,
271 self.button_layout)
272 self.setLayout(self.main_layout)
274 self.tab_bar.currentChanged.connect(self.stack_widget.setCurrentIndex)
275 self.stack_widget.currentChanged.connect(self.update_widget)
277 qtutils.connect_button(self.close_button, self.accept)
278 qtutils.add_close_action(self)
280 self.update_widget(0)
282 def update_widget(self, idx):
283 widget = self.stack_widget.widget(idx)
284 widget.update_from_config()