forked from nens/threedi-results-analysis
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmisc_tools.py
151 lines (122 loc) · 5.21 KB
/
misc_tools.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# (c) Nelen & Schuurmans, see LICENSE.rst.
"""
Miscellaneous tools.
"""
from qgis.core import QgsProject
from ThreeDiToolbox import PLUGIN_DIR
from ThreeDiToolbox.utils import qlogging
from ThreeDiToolbox.utils.layer_from_netCDF import FLOWLINES_LAYER_NAME
from ThreeDiToolbox.utils.layer_from_netCDF import NODES_LAYER_NAME
from ThreeDiToolbox.utils.layer_from_netCDF import PUMPLINES_LAYER_NAME
from ThreeDiToolbox.utils.user_messages import pop_up_info
from ThreeDiToolbox.utils.user_messages import pop_up_question
import logging
import os
# Shotgun approach for removing all problematic layers by their layer name.
# Very ad-hoc. Chance that it removes a layer that was not generated by the
# plugin due to filtering-by-name.
IDENTIFIER_LIKE = [FLOWLINES_LAYER_NAME, NODES_LAYER_NAME, PUMPLINES_LAYER_NAME]
logger = logging.getLogger(__name__)
class About(object):
"""Add 3Di logo and about info."""
def __init__(self, iface):
self.iface = iface
self.icon_path = ":/plugins/ThreeDiToolbox/icons/icon.png"
self.menu_text = "3Di about"
def run(self):
"""Shows dialog with version information."""
# TODO: add link to sites
version_file = PLUGIN_DIR / "version.rst"
version = version_file.read_text().rstrip()
pop_up_info(
"3Di Toolbox version %s" % version, "About", self.iface.mainWindow()
)
def on_unload(self):
pass
class ShowLogfile(object):
"""Show link to the logfile."""
def __init__(self, iface):
self.iface = iface
self.icon_path = ":/plugins/ThreeDiToolbox/icons/icon_logfile.png"
# ^^^ logo: LGPL, made by Oxygen Team, see
# http://www.iconarchive.com/show/oxygen-icons-by-oxygen-icons.org/
self.menu_text = "Show logfile"
def run(self):
"""Show dialog with a simple clickable link to the logfile.
Later on, we could also show the entire logfile inside the dialog. Or
suggest an email. The clickable link is OK for now.
Note: such a link does not work within the development docker.
"""
title = "Show logfile"
location = qlogging.logfile_path()
message = "Logfile location: <a href='file:///%s'>%s</a>" % (location, location)
pop_up_info(message, title, self.iface.mainWindow())
def on_unload(self):
pass
class CacheClearer(object):
"""Tool to delete cache files."""
def __init__(self, iface, ts_datasources):
"""Constructor.
Args:
iface: QGIS interface
ts_datasources: TimeseriesDatasourceModel instance
"""
self.iface = iface
self.icon_path = ":/plugins/ThreeDiToolbox/icons/icon_broom.png"
self.menu_text = "Clear cache"
self.ts_datasources = ts_datasources
def run(self):
"""Find cached spatialite and csv layer files for *ALL* items in the
TimeseriesDatasourceModel (i.e., *ALL* rows) object and delete them.
"""
# TODO: can ts_datasources tell us its cached files? Or can we order it
# to clean up its cache? (Instead of us poking around in its internals).
spatialite_filepaths = [
item.sqlite_gridadmin_filepath()
for item in self.ts_datasources.rows
if os.path.exists(item.sqlite_gridadmin_filepath())
]
# Note: convert to set because duplicates are possible if the same
# datasource is loaded multiple times
cached = set(spatialite_filepaths)
if not cached:
pop_up_info("No cached files found.")
return
# Files linked to the layers in the map registry are held open by
# Windows. You need to delete them manually from the registry to be
# able to remove the underlying data. Note that deleting the layer
# from the legend doesn't necessarily delete the layer from the map
# registry, even though it may appear that no more layers are loaded
# visually.
# The specific error message (for googling):
# "error 32 the process cannot access the file because it is being used
# by another process"
all_layers = list(QgsProject.instance().mapLayers().values())
loaded_layers = [
layer
for layer in all_layers
if any(identifier in layer.name() for identifier in IDENTIFIER_LIKE)
]
loaded_layer_ids = [layer.id() for layer in loaded_layers]
yes = pop_up_question(
"The following files will be deleted:\n"
+ ",\n".join(cached)
+ "\n\nContinue?"
)
if yes:
try:
QgsProject.instance().removeMapLayers(loaded_layer_ids)
except RuntimeError:
logger.exception("Failed to delete map layers")
for cached_spatialite_file in cached:
try:
os.remove(cached_spatialite_file)
except OSError:
msg = "Failed to delete %s." % cached_spatialite_file
logger.exception(msg)
pop_up_info(msg)
pop_up_info(
"Cache cleared. You may need to restart QGIS and reload your data."
)
def on_unload(self):
pass