1# vim: ts=8:sts=8:sw=8:noexpandtab
2
3# This file is part of ReText
4# Copyright: 2012-2021 Dmitry Shachnev
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19import sys
20import markups
21import markups.common
22from os.path import dirname, exists, join, expanduser
23
24from PyQt5.QtCore import QByteArray, QLocale, QSettings, QStandardPaths
25from PyQt5.QtGui import QFont, QFontDatabase
26
27app_version = "7.2.2"
28
29settings = QSettings('ReText project', 'ReText')
30
31if not str(settings.fileName()).endswith('.conf'):
32	# We are on Windows probably
33	settings = QSettings(QSettings.Format.IniFormat, QSettings.Scope.UserScope,
34		'ReText project', 'ReText')
35
36datadirs = []
37
38def initializeDataDirs():
39	assert not datadirs
40
41	try:
42		datadirs.append(dirname(dirname(__file__)))
43	except NameError:
44		pass
45
46	dataLocations = QStandardPaths.standardLocations(QStandardPaths.StandardLocation.GenericDataLocation)
47	datadirs.extend(join(d, 'retext') for d in dataLocations)
48
49	if sys.platform == "win32":
50		# Windows compatibility: Add "PythonXXX\share\" path
51		datadirs.append(join(dirname(sys.executable), 'share', 'retext'))
52
53	# For virtualenvs
54	datadirs.append(join(dirname(dirname(sys.executable)), 'share', 'retext'))
55
56_iconPath = None
57
58def getBundledIcon(iconName):
59	global _iconPath
60	if _iconPath is None:
61		for dir in ['icons'] + datadirs:
62			_iconPath = join(dir, 'icons')
63			if exists(_iconPath):
64				break
65	return join(_iconPath, iconName + '.png')
66
67configOptions = {
68	'appStyleSheet': '',
69	'autoSave': False,
70	'defaultCodec': '',
71	'defaultMarkup': markups.MarkdownMarkup.name,
72	'defaultPreviewState': 'editor',
73	'detectEncoding': True,
74	'directoryPath': expanduser("~"),
75	'documentStatsEnabled': False,
76	'editorFont': QFont(),
77	'font': QFont(),
78	'handleWebLinks': False,
79	'hideToolBar': False,
80	'highlightCurrentLine': 'disabled',
81	'iconTheme': '',
82	'lastTabIndex': 0,
83	'lineNumbersEnabled': False,
84	'markdownDefaultFileExtension': '.mkd',
85	'openFilesInExistingWindow': True,
86	'openLastFilesOnStartup': False,
87	'orderedListMode': 'increment',
88	'paperSize': '',
89	'pygmentsStyle': 'default',
90	'recentDocumentsCount': 10,
91	'relativeLineNumbers': False,
92	'restDefaultFileExtension': '.rst',
93	'rightMargin': 0,
94	'rightMarginWrap': False,
95	'saveWindowGeometry': False,
96	'showDirectoryTree': False,
97	'spellCheck': False,
98	'spellCheckLocale': '',
99	'styleSheet': '',
100	'syncScroll': True,
101	'tabBarAutoHide': False,
102	'tabInsertsSpaces': True,
103	'tabWidth': 4,
104	'uiLanguage': QLocale.system().name(),
105	'useFakeVim': False,
106	'useWebEngine': False,
107	'useWebKit': False,
108	'wideCursor': False,
109	'windowGeometry': QByteArray(),
110	'windowTitleFullPath': False,
111}
112
113def readFromSettings(key, keytype, settings=settings, default=None):
114	if isinstance(default, QFont):
115		family = readFromSettings(key, str, settings, default.family())
116		size = readFromSettings(key + 'Size', int, settings, 0)
117		return QFont(family, size)
118	if not settings.contains(key):
119		return default
120	try:
121		value = settings.value(key, type=keytype)
122		if isinstance(value, keytype):
123			return value
124		return keytype(value)
125	except TypeError as error:
126		# Type mismatch
127		print('Warning: '+str(error))
128		# Return an instance of keytype
129		return default if (default is not None) else keytype()
130
131def readListFromSettings(key, settings=settings):
132	if not settings.contains(key):
133		return []
134	value = settings.value(key)
135	if isinstance(value, str):
136		return [value]
137	else:
138		return value
139
140def writeToSettings(key, value, default, settings=settings):
141	if isinstance(value, QFont):
142		writeToSettings(key, value.family(), '', settings)
143		writeToSettings(key + 'Size', max(value.pointSize(), 0), 0, settings)
144	elif value == default:
145		settings.remove(key)
146	else:
147		settings.setValue(key, value)
148
149def writeListToSettings(key, value, settings=settings):
150	if len(value) > 1:
151		settings.setValue(key, value)
152	elif len(value) == 1:
153		settings.setValue(key, value[0])
154	else:
155		settings.remove(key)
156
157def getSettingsFilePath(settings=settings):
158	return settings.fileName()
159
160
161class ReTextSettings(object):
162	def __init__(self):
163		for option in configOptions:
164			value = configOptions[option]
165			object.__setattr__(self, option, readFromSettings(
166				option, type(value), default=value))
167
168	def __setattr__(self, option, value):
169		if not option in configOptions:
170			raise AttributeError('Unknown attribute')
171		object.__setattr__(self, option, value)
172		writeToSettings(option, value, configOptions[option])
173
174	def __getattribute__(self, option):
175		value = object.__getattribute__(self, option)
176		# Choose a font just-in-time, because when the settings are
177		# loaded it is too early to work.
178		if option == 'font' and not value.family():
179			value = QFont()
180		if option == 'editorFont' and not value.family():
181			value = QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont)
182		return value
183
184globalSettings = ReTextSettings()
185
186markups.common.PYGMENTS_STYLE = globalSettings.pygmentsStyle
187