diff --git a/openlp/core/common/handlers.py b/openlp/core/common/handlers.py
new file mode 100644
index 000000000..a0f2b86d0
--- /dev/null
+++ b/openlp/core/common/handlers.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+
+##########################################################################
+# OpenLP - Open Source Lyrics Projection #
+# ---------------------------------------------------------------------- #
+# Copyright (c) 2008-2022 OpenLP Developers #
+# ---------------------------------------------------------------------- #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see . #
+##########################################################################
+"""
+Some exception handling functions
+"""
+import logging
+from contextlib import contextmanager
+from pathlib import Path
+from typing import Optional
+
+from PyQt5 import QtWidgets
+
+from openlp.core.common.i18n import translate
+
+
+log = logging.getLogger(__name__)
+
+
+@contextmanager
+def handle_permission_error(filepath: Path, parent: Optional[QtWidgets.QWidget] = None):
+ try:
+ yield
+ except PermissionError:
+ log.exception(f'Permission denied when accessing {filepath}')
+ QtWidgets.QMessageBox.critical(
+ parent,
+ translate('OpenLP.Handlers', 'Permission Error'),
+ translate('OpenLP.Handlers', 'There was a permissions error when trying to access '
+ '{filename}').format(filename=filepath)
+ )
diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py
index 06380fa90..96542e0f1 100644
--- a/openlp/plugins/songs/forms/songimportform.py
+++ b/openlp/plugins/songs/forms/songimportform.py
@@ -25,6 +25,7 @@ import logging
from PyQt5 import QtCore, QtWidgets, QtGui
+from openlp.core.common.handlers import handle_permission_error
from openlp.core.common.i18n import UiStrings, translate
from openlp.core.common.mixins import RegistryProperties
from openlp.core.lib.ui import critical_error_message_box
@@ -496,9 +497,10 @@ class SongImportSourcePage(QtWidgets.QWizardPage):
return True
else:
file_path = wizard.format_widgets[this_format]['path_edit'].path
- if file_path:
- if select_mode == SongFormatSelect.SingleFile and file_path.is_file():
- return True
- elif select_mode == SongFormatSelect.SingleFolder and file_path.is_dir():
- return True
+ if file_path and file_path.exists():
+ with handle_permission_error(file_path):
+ if select_mode == SongFormatSelect.SingleFile and file_path.is_file():
+ return True
+ elif select_mode == SongFormatSelect.SingleFolder and file_path.is_dir():
+ return True
return False
diff --git a/tests/openlp_core/common/test_handlers.py b/tests/openlp_core/common/test_handlers.py
new file mode 100644
index 000000000..2f38fed2f
--- /dev/null
+++ b/tests/openlp_core/common/test_handlers.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+
+##########################################################################
+# OpenLP - Open Source Lyrics Projection #
+# ---------------------------------------------------------------------- #
+# Copyright (c) 2008-2022 OpenLP Developers #
+# ---------------------------------------------------------------------- #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see . #
+##########################################################################
+"""
+Test the exception handling functions
+"""
+from unittest.mock import patch
+
+from openlp.core.common.handlers import handle_permission_error
+
+
+@patch('openlp.core.common.handlers.QtWidgets.QMessageBox')
+def test_handle_permission_error(MockQMessageBox):
+ """Test the handle_permission_error() function to make sure it catches PermissionError"""
+ # GIVEN: A mocked QMessageBox class and a file path
+ file_path = 'mocked_file_path'
+
+ # WHEN: the handle_permission_error() context manager is used
+ try:
+ with handle_permission_error(file_path):
+ raise PermissionError('Bad mojo')
+ except PermissionError:
+ assert False, 'PermissionError was not caught'
+
+ MockQMessageBox.critical.assert_called_once_with(
+ None, 'Permission Error',
+ 'There was a permissions error when trying to access mocked_file_path'
+ )