Skip to content

Commit 22bfff9

Browse files
committed
Merge branch 'main' of github.com:MusculoskeletalAtlasProject/mapclient
2 parents a368c0f + e6e8175 commit 22bfff9

46 files changed

Lines changed: 1350 additions & 16880 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

res/win/nsis.nsi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
; You must define these values
55

66
!define APP_NAME "MAP-Client"
7-
!define APP_VERSION "0.14.0"
7+
!define APP_VERSION "0.25.0"
88
!define APP_ORGANISATION "MAP"
99
!define VERSION "1.0.0"
1010
!define PATCH "1"
@@ -742,7 +742,7 @@ Section "-Core installation"
742742

743743
; Optional registration
744744
Push "DisplayIcon"
745-
Push "$INSTDIR\"
745+
Push "$INSTDIR\${APP_NAME},0"
746746
Call ConditionalAddToRegisty
747747
Push "HelpLink"
748748
Push ""

res/win/nsis.nsi.template

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ Section
119119

120120
; Write uninstall information to registry.
121121
!insertmacro WriteUninstallInfo "DisplayName" "${APP_NAME} ${APP_VERSION}"
122-
!insertmacro WriteUninstallInfo "DisplayVersion" "${INSTALLER_VERSION}"
122+
!insertmacro WriteUninstallInfo "DisplayIcon" "$INSTDIR\${APP_NAME}.exe,0"
123+
!insertmacro WriteUninstallInfo "DisplayVersion" "${APP_VERSION}"
123124
!insertmacro WriteUninstallInfo "Publisher" "${APP_ORGANISATION}"
124125
!insertmacro WriteUninstallInfo "UninstallString" "$INSTDIR\Uninstall.exe"
125126
!insertmacro WriteUninstallInfo "NoRepair" "1"

src/mapclient/application.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
along with MAP Client. If not, see <http://www.gnu.org/licenses/>..
2020
"""
2121
import json
22+
import multiprocessing
2223
import os
2324
import shutil
2425
import sys
@@ -55,6 +56,15 @@
5556
logger = logging.getLogger('mapclient.application')
5657

5758

59+
def get_app_path():
60+
if getattr(sys, 'frozen', False):
61+
# If the application is frozen (e.g., by PyInstaller)
62+
return os.path.dirname(sys.executable)
63+
else:
64+
# If running in a normal Python environment
65+
return os.path.dirname(os.path.abspath(__file__))
66+
67+
5868
def initialise_logger(log_path):
5969
"""
6070
Initialise logger settings and information formatting
@@ -375,7 +385,7 @@ def _user_specified_environment_main(base_dir, directories):
375385
if os.path.isdir(d) and d not in plugin_directories:
376386
plugin_directories.append(d)
377387

378-
pm.setDirectories(plugin_directories)
388+
pm.set_directories(plugin_directories)
379389
model.writeSettings()
380390

381391
logger.info(f"Set environment variable '{APPLICATION_ENVIRONMENT_CONFIG_DIR_VARIABLE}' to '{config_dir}' to use application with these settings.")
@@ -525,4 +535,5 @@ def main():
525535

526536

527537
if __name__ == '__main__':
538+
multiprocessing.freeze_support()
528539
main()

src/mapclient/core/mainapplication.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from mapclient.core.checks import runChecks
3030
from mapclient.settings.definitions import CHECK_TOOLS_ON_STARTUP, RECENTS_LENGTH
3131
from mapclient.settings.general import get_settings
32+
from mapclient.settings.version import __version__ as version
3233

3334
logger = logging.getLogger(__name__)
3435

@@ -91,6 +92,9 @@ def doEnvironmentChecks(self):
9192

9293
def writeSettings(self):
9394
settings = get_settings()
95+
settings.beginGroup('Application')
96+
settings.setValue('version', version)
97+
settings.endGroup()
9498
settings.beginGroup('MainWindow')
9599
settings.setValue('size', self._size)
96100
settings.setValue('pos', self._pos)
@@ -109,6 +113,9 @@ def writeSettings(self):
109113

110114
def readSettings(self):
111115
settings = get_settings()
116+
settings.beginGroup('Application')
117+
settings_version = settings.value('version', '0.0.0')
118+
settings.endGroup()
112119
settings.beginGroup('MainWindow')
113120
self._size = settings.value('size', self._size)
114121
self._pos = settings.value('pos', self._pos)
@@ -120,7 +127,7 @@ def readSettings(self):
120127
settings.endArray()
121128
settings.endGroup()
122129

123-
self._pluginManager.readSettings(settings)
130+
self._pluginManager.readSettings(settings, settings_version)
124131
self._workflowManager.readSettings(settings)
125132
self._optionsManager.readSettings(settings)
126133
self._package_manager.read_settings(settings)

src/mapclient/core/managers/optionsmanager.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@
77
from mapclient.settings.general import get_virtualenv_directory
88
from mapclient.settings.definitions import SHOW_STEP_NAMES, CLOSE_AFTER, METRICS_PERMISSION, INTERNAL_EXE, UNSET_FLAG, \
99
DONT_CREATE_VIRTUAL_ENV, OPTIONS_SETTINGS_TAG, INTERNAL_WORKFLOWS_AVAILABLE, INTERNAL_WORKFLOW_DIR, VIRTUAL_ENV_PATH, \
10-
GIT_EXE, PYSIDE_UIC_EXE, PYSIDE_RCC_EXE, PREVIOUS_PW_WRITE_STEP_LOCATION, PREVIOUS_PW_ICON_LOCATION, CHECK_TOOLS_ON_STARTUP, \
10+
GIT_EXE, PYSIDE_UIC_EXE, PYSIDE_RCC_EXE, PREVIOUS_PW_WRITE_STEP_LOCATION, PREVIOUS_PW_ICON_LOCATION, \
11+
CHECK_TOOLS_ON_STARTUP, \
1112
USE_EXTERNAL_GIT, USE_EXTERNAL_RCC, USE_EXTERNAL_UIC, RECENTS_ABSOLUTE_PATHS, RECENTS_LENGTH, PREVIOUS_WORKFLOW, \
12-
AUTOLOAD_PREVIOUS_WORKFLOW, METRICS_PERMISSION_ATTAINED
13+
AUTOLOAD_PREVIOUS_WORKFLOW, METRICS_PERMISSION_ATTAINED, ANIMATE_LAYOUT_UPDATES
1314

1415

1516
def _is_boolean(option):
1617
return option in [SHOW_STEP_NAMES, CHECK_TOOLS_ON_STARTUP, DONT_CREATE_VIRTUAL_ENV, METRICS_PERMISSION, USE_EXTERNAL_GIT,
17-
USE_EXTERNAL_RCC, USE_EXTERNAL_UIC, RECENTS_ABSOLUTE_PATHS, INTERNAL_WORKFLOWS_AVAILABLE, AUTOLOAD_PREVIOUS_WORKFLOW]
18+
USE_EXTERNAL_RCC, USE_EXTERNAL_UIC, RECENTS_ABSOLUTE_PATHS, INTERNAL_WORKFLOWS_AVAILABLE,
19+
AUTOLOAD_PREVIOUS_WORKFLOW, ANIMATE_LAYOUT_UPDATES]
1820

1921

2022
def _is_float(option):
@@ -32,6 +34,7 @@ def __init__(self):
3234
self._options = {
3335
SHOW_STEP_NAMES: True, CLOSE_AFTER: 2.0, METRICS_PERMISSION: False,
3436
DONT_CREATE_VIRTUAL_ENV: False, CHECK_TOOLS_ON_STARTUP: True,
37+
ANIMATE_LAYOUT_UPDATES: True,
3538
USE_EXTERNAL_GIT: False, USE_EXTERNAL_RCC: False, USE_EXTERNAL_UIC: False,
3639
RECENTS_ABSOLUTE_PATHS: False, RECENTS_LENGTH: 10,
3740
VIRTUAL_ENV_PATH: get_virtualenv_directory(), GIT_EXE: which('git'),

src/mapclient/core/managers/pluginmanager.py

Lines changed: 75 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
44
@author: hsorby
55
"""
6-
import io
76
import json
87
import os
98
import sys
@@ -16,37 +15,38 @@
1615
import types
1716
import importlib
1817

19-
from contextlib import redirect_stdout
20-
21-
22-
from mapclient.core.utils import which, FileTypeObject, grep, is_frozen, determine_step_name, determine_step_class_name
18+
from mapclient.application import get_app_path
19+
from mapclient.core.utils import which, FileTypeObject, grep, is_frozen, determine_step_name, determine_step_class_name, \
20+
stable_hash
2321
from mapclient.settings.definitions import VIRTUAL_ENV_PATH, \
2422
PLUGINS_PACKAGE_NAME, PLUGINS_PTH
2523
from mapclient.core.checks import getPipExecutable
2624

2725
from importlib import import_module
2826

29-
from mapclient.settings.general import get_virtualenv_site_packages_directory
27+
from mapclient.settings.general import get_virtualenv_site_packages_directory, get_settings
3028

3129
logger = logging.getLogger(__name__)
3230

31+
CONST_DEFAULT_PROFILE = 'Default'
32+
3333

3434
def getVirtualEnvCandidates():
3535
"""Return a list of strings which contains possible names
3636
of the virtualenv program for this environment.
3737
"""
38-
if sys.version_info < (3, 0):
39-
virtualenv_candidates = [which('virtualenv'), which('virtualenv2')]
40-
else:
41-
virtualenv_candidates = [which('virtualenv'), which('virtualenv3')]
38+
return [which('virtualenv'), which('virtualenv3')]
4239

43-
return virtualenv_candidates
40+
41+
def _get_app_profile_key():
42+
return f'current_profile_{stable_hash(get_app_path())}'
4443

4544

4645
class PluginManager:
4746

4847
def __init__(self):
49-
self._directories = []
48+
self._current_profile = CONST_DEFAULT_PROFILE
49+
self._profile_directories = {}
5050
self._virtualenv_enabled = True
5151
self._virtualenv_dir = None
5252
self._virtualenv_setup_attempted = False
@@ -74,7 +74,13 @@ def getVirtualEnvDirectory(self):
7474
return self._virtualenv_dir
7575

7676
def directories(self):
77-
return self._directories
77+
return self._profile_directories.get(self._current_profile, [])
78+
79+
def current_profile(self):
80+
return self._current_profile
81+
82+
def set_current_profile(self, profile_name):
83+
self._current_profile = profile_name
7884

7985
def setReloadPlugins(self, state=True):
8086
self._reload_plugins = state
@@ -105,14 +111,15 @@ def list(self):
105111
def setOptions(self, options):
106112
self._virtualenv_dir = options[VIRTUAL_ENV_PATH]
107113

108-
def setDirectories(self, directories):
114+
def set_directories(self, directories):
109115
"""
110116
Set the list of directories to be searched for
111117
plugins. Returns true if the directories listing
112118
was updated and false otherwise.
113119
"""
114-
if self._directories != directories:
115-
self._directories = directories
120+
current_directories = self._profile_directories.get(self._current_profile, [])
121+
if current_directories != directories:
122+
self._profile_directories[self._current_profile] = directories
116123
self._reload_plugins = True
117124

118125
def virtualenvSetupAttempted(self):
@@ -165,11 +172,6 @@ def setupVirtualEnv(self):
165172
def getPluginDatabase(self):
166173
return self._plugin_database
167174

168-
def allDirectories(self):
169-
plugin_dirs = self._directories[:]
170-
171-
return plugin_dirs
172-
173175
def _addPluginDir(self, directory):
174176
added = False
175177
if isMapClientPluginsDir(directory):
@@ -223,7 +225,7 @@ def load(self):
223225

224226
len_package_modules_prior = len(sys.modules[PLUGINS_PACKAGE_NAME].__path__) if PLUGINS_PACKAGE_NAME in sys.modules else 0
225227
new_plugin_directories = []
226-
for directory in self.allDirectories():
228+
for directory in self.directories():
227229
if self._addPluginDir(directory):
228230
new_plugin_directories.append(directory)
229231
else:
@@ -328,17 +330,47 @@ def getPluginErrors(self):
328330
return {'ImportError': self._import_errors, 'TypeError': self._type_errors, 'SyntaxError': self._syntax_errors, 'TabError': self._tab_errors,
329331
'directories': self._plugin_error_directories}
330332

331-
def readSettings(self, settings):
332-
self._directories = []
333+
def set_profile_directories(self, profile_directories):
334+
"""
335+
Set the directories for the given profile name.
336+
"""
337+
self._profile_directories = profile_directories
338+
339+
def profile_directories(self):
340+
"""
341+
Get the profile directories information.
342+
"""
343+
return self._profile_directories
344+
345+
def readSettings(self, settings, settings_version):
346+
self._profile_directories = {}
333347
settings.beginGroup('Plugins')
334348
self._doNotShowPluginErrors = settings.value('donot_show_plugin_errors', 'true') == 'true'
335349
self._virtualenv_setup_attempted = settings.value('virtualenv_setup_attempted', 'false') == 'true'
336-
directory_count = settings.beginReadArray('directories')
337-
for i in range(directory_count):
338-
settings.setArrayIndex(i)
339-
self._directories.append(settings.value('directory'))
340-
settings.endArray()
350+
self._current_profile = settings.value(_get_app_profile_key(), CONST_DEFAULT_PROFILE)
351+
if settings_version == '0.0.0':
352+
directory_count = settings.beginReadArray('directories')
353+
directories = []
354+
for i in range(directory_count):
355+
settings.setArrayIndex(i)
356+
directories.append(settings.value('directory'))
357+
settings.endArray()
358+
self._profile_directories[CONST_DEFAULT_PROFILE] = directories
359+
else:
360+
profiles_count = settings.beginReadArray('profiles')
361+
for i in range(profiles_count):
362+
settings.setArrayIndex(i)
363+
profile_name = settings.value('name')
364+
directory_count = settings.beginReadArray('directories')
365+
directories = []
366+
for j in range(directory_count):
367+
settings.setArrayIndex(j)
368+
directories.append(settings.value('directory'))
369+
settings.endArray()
370+
self._profile_directories[profile_name] = directories
371+
settings.endArray()
341372
settings.endGroup()
373+
self._profile_directories[CONST_DEFAULT_PROFILE] = self._profile_directories.get(CONST_DEFAULT_PROFILE, [])
342374
settings.beginGroup('Ignored Plugins')
343375
plugin_count = settings.beginReadArray('plugins')
344376
for i in range(plugin_count):
@@ -371,12 +403,18 @@ def writeSettings(self, settings):
371403
settings.beginGroup('Plugins')
372404
settings.setValue('donot_show_plugin_errors', self._doNotShowPluginErrors)
373405
settings.setValue('virtualenv_setup_attempted', self._virtualenv_setup_attempted)
374-
settings.beginWriteArray('directories')
375-
directory_index = 0
376-
for directory in self._directories:
377-
settings.setArrayIndex(directory_index)
378-
settings.setValue('directory', directory)
379-
directory_index += 1
406+
settings.setValue(_get_app_profile_key(), self._current_profile)
407+
settings.beginWriteArray('profiles')
408+
profile_index = 0
409+
for profile_name, profile_directories in self._profile_directories.items():
410+
settings.setArrayIndex(profile_index)
411+
settings.setValue('name', profile_name)
412+
settings.beginWriteArray('directories')
413+
for directory_index, directory in enumerate(profile_directories):
414+
settings.setArrayIndex(directory_index)
415+
settings.setValue('directory', directory)
416+
settings.endArray()
417+
profile_index += 1
380418
settings.endArray()
381419
settings.endGroup()
382420
settings.beginGroup('Ignored Plugins')
@@ -557,8 +595,8 @@ def checkForMissingPlugins(self, to_check):
557595
"""
558596
missing_plugins = {}
559597
for plugin in to_check:
560-
if not (plugin in self._database and \
561-
to_check[plugin]['author'] == self._database[plugin]['author'] and \
598+
if not (plugin in self._database and
599+
to_check[plugin]['author'] == self._database[plugin]['author'] and
562600
to_check[plugin]['version'] == self._database[plugin]['version']):
563601
missing_plugins[plugin] = to_check[plugin]
564602

src/mapclient/core/managers/workflowmanager.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"""
2020
import os
2121
import logging
22+
2223
from packaging import version
2324

2425
from PySide6 import QtCore

src/mapclient/core/utils.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
You should have received a copy of the GNU General Public License
1818
along with MAP Client. If not, see <http://www.gnu.org/licenses/>..
1919
"""
20+
import hashlib
2021
import json
2122
import logging
2223
import os
@@ -379,3 +380,7 @@ def to_exchangeable_path(input_path):
379380

380381
def to_system_path(input_path):
381382
return str(PurePath(input_path))
383+
384+
385+
def stable_hash(s):
386+
return hashlib.sha256(s.encode()).hexdigest()

src/mapclient/core/workflow/layouts/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)