BERATools 0.2.0__py3-none-any.whl → 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- beratools/__init__.py +1 -7
- beratools/core/algo_centerline.py +491 -351
- beratools/core/algo_common.py +497 -0
- beratools/core/algo_cost.py +192 -0
- beratools/core/{dijkstra_algorithm.py → algo_dijkstra.py} +503 -460
- beratools/core/algo_footprint_rel.py +577 -0
- beratools/core/algo_line_grouping.py +944 -0
- beratools/core/algo_merge_lines.py +214 -0
- beratools/core/algo_split_with_lines.py +304 -0
- beratools/core/algo_tiler.py +428 -0
- beratools/core/algo_vertex_optimization.py +469 -0
- beratools/core/constants.py +52 -86
- beratools/core/logger.py +76 -85
- beratools/core/tool_base.py +196 -133
- beratools/gui/__init__.py +11 -15
- beratools/gui/{beratools.json → assets/beratools.json} +2185 -2300
- beratools/gui/batch_processing_dlg.py +513 -463
- beratools/gui/bt_data.py +481 -487
- beratools/gui/bt_gui_main.py +710 -691
- beratools/gui/main.py +26 -0
- beratools/gui/map_window.py +162 -146
- beratools/gui/tool_widgets.py +725 -493
- beratools/tools/Beratools_r_script.r +1120 -1120
- beratools/tools/Ht_metrics.py +116 -116
- beratools/tools/__init__.py +7 -7
- beratools/tools/batch_processing.py +136 -132
- beratools/tools/canopy_threshold_relative.py +672 -670
- beratools/tools/canopycostraster.py +222 -222
- beratools/tools/centerline.py +136 -176
- beratools/tools/common.py +857 -885
- beratools/tools/fl_regen_csf.py +428 -428
- beratools/tools/forest_line_attributes.py +408 -408
- beratools/tools/line_footprint_absolute.py +213 -363
- beratools/tools/line_footprint_fixed.py +436 -282
- beratools/tools/line_footprint_functions.py +733 -720
- beratools/tools/line_footprint_relative.py +73 -64
- beratools/tools/line_grouping.py +45 -0
- beratools/tools/ln_relative_metrics.py +615 -615
- beratools/tools/r_cal_lpi_elai.r +24 -24
- beratools/tools/r_generate_pd_focalraster.r +100 -100
- beratools/tools/r_interface.py +79 -79
- beratools/tools/r_point_density.r +8 -8
- beratools/tools/rpy_chm2trees.py +86 -86
- beratools/tools/rpy_dsm_chm_by.py +81 -81
- beratools/tools/rpy_dtm_by.py +63 -63
- beratools/tools/rpy_find_cellsize.py +43 -43
- beratools/tools/rpy_gnd_csf.py +74 -74
- beratools/tools/rpy_hummock_hollow.py +85 -85
- beratools/tools/rpy_hummock_hollow_raster.py +71 -71
- beratools/tools/rpy_las_info.py +51 -51
- beratools/tools/rpy_laz2las.py +40 -40
- beratools/tools/rpy_lpi_elai_lascat.py +466 -466
- beratools/tools/rpy_normalized_lidar_by.py +56 -56
- beratools/tools/rpy_percent_above_dbh.py +80 -80
- beratools/tools/rpy_points2trees.py +88 -88
- beratools/tools/rpy_vegcoverage.py +94 -94
- beratools/tools/tiler.py +48 -206
- beratools/tools/tool_template.py +69 -54
- beratools/tools/vertex_optimization.py +61 -620
- beratools/tools/zonal_threshold.py +144 -144
- beratools-0.2.1.dist-info/METADATA +109 -0
- beratools-0.2.1.dist-info/RECORD +74 -0
- {beratools-0.2.0.dist-info → beratools-0.2.1.dist-info}/WHEEL +1 -1
- {beratools-0.2.0.dist-info → beratools-0.2.1.dist-info}/licenses/LICENSE +22 -22
- beratools/gui/cli.py +0 -18
- beratools/gui/gui.json +0 -8
- beratools/gui_tk/ASCII Banners.txt +0 -248
- beratools/gui_tk/__init__.py +0 -20
- beratools/gui_tk/beratools_main.py +0 -515
- beratools/gui_tk/bt_widgets.py +0 -442
- beratools/gui_tk/cli.py +0 -18
- beratools/gui_tk/img/BERALogo.png +0 -0
- beratools/gui_tk/img/closed.gif +0 -0
- beratools/gui_tk/img/closed.png +0 -0
- beratools/gui_tk/img/open.gif +0 -0
- beratools/gui_tk/img/open.png +0 -0
- beratools/gui_tk/img/tool.gif +0 -0
- beratools/gui_tk/img/tool.png +0 -0
- beratools/gui_tk/main.py +0 -14
- beratools/gui_tk/map_window.py +0 -144
- beratools/gui_tk/runner.py +0 -1481
- beratools/gui_tk/tooltip.py +0 -55
- beratools/third_party/pyqtlet2/__init__.py +0 -9
- beratools/third_party/pyqtlet2/leaflet/__init__.py +0 -26
- beratools/third_party/pyqtlet2/leaflet/control/__init__.py +0 -6
- beratools/third_party/pyqtlet2/leaflet/control/control.py +0 -59
- beratools/third_party/pyqtlet2/leaflet/control/draw.py +0 -52
- beratools/third_party/pyqtlet2/leaflet/control/layers.py +0 -20
- beratools/third_party/pyqtlet2/leaflet/core/Parser.py +0 -24
- beratools/third_party/pyqtlet2/leaflet/core/__init__.py +0 -2
- beratools/third_party/pyqtlet2/leaflet/core/evented.py +0 -180
- beratools/third_party/pyqtlet2/leaflet/layer/__init__.py +0 -5
- beratools/third_party/pyqtlet2/leaflet/layer/featuregroup.py +0 -34
- beratools/third_party/pyqtlet2/leaflet/layer/icon/__init__.py +0 -1
- beratools/third_party/pyqtlet2/leaflet/layer/icon/icon.py +0 -30
- beratools/third_party/pyqtlet2/leaflet/layer/imageoverlay.py +0 -18
- beratools/third_party/pyqtlet2/leaflet/layer/layer.py +0 -105
- beratools/third_party/pyqtlet2/leaflet/layer/layergroup.py +0 -45
- beratools/third_party/pyqtlet2/leaflet/layer/marker/__init__.py +0 -1
- beratools/third_party/pyqtlet2/leaflet/layer/marker/marker.py +0 -91
- beratools/third_party/pyqtlet2/leaflet/layer/tile/__init__.py +0 -2
- beratools/third_party/pyqtlet2/leaflet/layer/tile/gridlayer.py +0 -4
- beratools/third_party/pyqtlet2/leaflet/layer/tile/tilelayer.py +0 -16
- beratools/third_party/pyqtlet2/leaflet/layer/vector/__init__.py +0 -5
- beratools/third_party/pyqtlet2/leaflet/layer/vector/circle.py +0 -15
- beratools/third_party/pyqtlet2/leaflet/layer/vector/circlemarker.py +0 -18
- beratools/third_party/pyqtlet2/leaflet/layer/vector/path.py +0 -5
- beratools/third_party/pyqtlet2/leaflet/layer/vector/polygon.py +0 -14
- beratools/third_party/pyqtlet2/leaflet/layer/vector/polyline.py +0 -18
- beratools/third_party/pyqtlet2/leaflet/layer/vector/rectangle.py +0 -14
- beratools/third_party/pyqtlet2/leaflet/map/__init__.py +0 -1
- beratools/third_party/pyqtlet2/leaflet/map/map.py +0 -220
- beratools/third_party/pyqtlet2/mapwidget.py +0 -45
- beratools/third_party/pyqtlet2/web/custom.js +0 -43
- beratools/third_party/pyqtlet2/web/map.html +0 -23
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/layers-2x.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/layers.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/marker-icon-2x.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/marker-icon.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/images/marker-shadow.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/leaflet.css +0 -656
- beratools/third_party/pyqtlet2/web/modules/leaflet_193/leaflet.js +0 -6
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.codeclimate.yml +0 -14
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.editorconfig +0 -4
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.gitattributes +0 -22
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/.travis.yml +0 -43
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/LICENSE +0 -20
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/layers-2x.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/layers.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/marker-icon-2x.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/marker-icon.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/marker-shadow.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/spritesheet-2x.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/spritesheet.png +0 -0
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/images/spritesheet.svg +0 -156
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/leaflet.draw.css +0 -10
- beratools/third_party/pyqtlet2/web/modules/leaflet_draw_414/leaflet.draw.js +0 -10
- beratools/third_party/pyqtlet2/web/modules/leaflet_rotatedMarker_020/LICENSE +0 -22
- beratools/third_party/pyqtlet2/web/modules/leaflet_rotatedMarker_020/leaflet.rotatedMarker.js +0 -57
- beratools/tools/forest_line_ecosite.py +0 -216
- beratools/tools/lapis_all.py +0 -103
- beratools/tools/least_cost_path_from_chm.py +0 -152
- beratools-0.2.0.dist-info/METADATA +0 -63
- beratools-0.2.0.dist-info/RECORD +0 -142
- /beratools/gui/{img → assets}/BERALogo.png +0 -0
- /beratools/gui/{img → assets}/closed.gif +0 -0
- /beratools/gui/{img → assets}/closed.png +0 -0
- /beratools/{gui_tk → gui/assets}/gui.json +0 -0
- /beratools/gui/{img → assets}/open.gif +0 -0
- /beratools/gui/{img → assets}/open.png +0 -0
- /beratools/gui/{img → assets}/tool.gif +0 -0
- /beratools/gui/{img → assets}/tool.png +0 -0
- {beratools-0.2.0.dist-info → beratools-0.2.1.dist-info}/entry_points.txt +0 -0
beratools/gui_tk/runner.py
DELETED
|
@@ -1,1481 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
# This script is part of the BERA Tools.
|
|
4
|
-
# Authors: Richard Zeng
|
|
5
|
-
# Created: 01/03/2023
|
|
6
|
-
# License: MIT
|
|
7
|
-
|
|
8
|
-
# import __future__
|
|
9
|
-
import os
|
|
10
|
-
import sys
|
|
11
|
-
|
|
12
|
-
from os import path
|
|
13
|
-
from sys import platform as _platform
|
|
14
|
-
|
|
15
|
-
if sys.version_info[0] < 3:
|
|
16
|
-
raise Exception("Must be using Python 3")
|
|
17
|
-
|
|
18
|
-
import re # Added by Rachel for snake_to_camel function
|
|
19
|
-
import json
|
|
20
|
-
import platform
|
|
21
|
-
import glob
|
|
22
|
-
|
|
23
|
-
import threading
|
|
24
|
-
import signal
|
|
25
|
-
from time import sleep
|
|
26
|
-
|
|
27
|
-
import tkinter as tk
|
|
28
|
-
from tkinter import ttk
|
|
29
|
-
from tkinter.scrolledtext import ScrolledText
|
|
30
|
-
from tkinter import filedialog
|
|
31
|
-
from tkinter.simpledialog import askinteger
|
|
32
|
-
from tkinter import messagebox
|
|
33
|
-
import webbrowser
|
|
34
|
-
from pathlib import Path
|
|
35
|
-
|
|
36
|
-
from beratools.gui_tk.beratools_main import BeraTools
|
|
37
|
-
from beratools.tools.common import *
|
|
38
|
-
from .tooltip import *
|
|
39
|
-
from PIL import Image, ImageTk
|
|
40
|
-
|
|
41
|
-
bt = BeraTools()
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
class FileSelector(tk.Frame):
|
|
45
|
-
def __init__(self, json_str, runner, master=None):
|
|
46
|
-
# first make sure that the json data has the correct fields
|
|
47
|
-
j = json.loads(json_str)
|
|
48
|
-
self.name = j['name']
|
|
49
|
-
self.description = j['description']
|
|
50
|
-
self.flag = j['flag']
|
|
51
|
-
self.parameter_type = j['parameter_type']
|
|
52
|
-
self.file_type = ""
|
|
53
|
-
if "ExistingFile" in self.parameter_type:
|
|
54
|
-
self.file_type = j['parameter_type']['ExistingFile']
|
|
55
|
-
elif "NewFile" in self.parameter_type:
|
|
56
|
-
self.file_type = j['parameter_type']['NewFile']
|
|
57
|
-
if "Directory" in self.parameter_type:
|
|
58
|
-
self.file_type = j['parameter_type']['Directory']
|
|
59
|
-
self.optional = j['optional']
|
|
60
|
-
# default_value = j['default_value']
|
|
61
|
-
|
|
62
|
-
self.runner = runner
|
|
63
|
-
|
|
64
|
-
ttk.Frame.__init__(self, master, padding='0.02i')
|
|
65
|
-
self.grid()
|
|
66
|
-
|
|
67
|
-
self.label = ttk.Label(self, text=self.name, justify=tk.LEFT)
|
|
68
|
-
self.label.grid(row=0, column=0, sticky=tk.W)
|
|
69
|
-
self.label.columnconfigure(0, weight=1)
|
|
70
|
-
CreateToolTip(self.label, self.description)
|
|
71
|
-
|
|
72
|
-
if not self.optional:
|
|
73
|
-
self.label['text'] = self.label['text'] + "*"
|
|
74
|
-
|
|
75
|
-
fs_frame = ttk.Frame(self, padding='0.0i')
|
|
76
|
-
self.value = tk.StringVar()
|
|
77
|
-
self.entry = ttk.Entry(
|
|
78
|
-
fs_frame, width=45, justify=tk.LEFT, textvariable=self.value)
|
|
79
|
-
self.entry.grid(row=0, column=0, sticky=tk.NSEW)
|
|
80
|
-
self.entry.columnconfigure(0, weight=1)
|
|
81
|
-
# if default_value:
|
|
82
|
-
# self.value.set(default_value)
|
|
83
|
-
|
|
84
|
-
self.open_button = ttk.Button(fs_frame, width=4, text="...", command=self.select_file, padding='0.02i')
|
|
85
|
-
self.open_button.grid(row=0, column=1, sticky=tk.E)
|
|
86
|
-
self.open_button.columnconfigure(0, weight=1)
|
|
87
|
-
fs_frame.grid(row=1, column=0, sticky=tk.NSEW)
|
|
88
|
-
fs_frame.columnconfigure(0, weight=10)
|
|
89
|
-
fs_frame.columnconfigure(1, weight=1)
|
|
90
|
-
# self.pack(fill=tk.BOTH, expand=1)
|
|
91
|
-
self.columnconfigure(0, weight=1)
|
|
92
|
-
self.rowconfigure(0, weight=1)
|
|
93
|
-
self.rowconfigure(1, weight=1)
|
|
94
|
-
|
|
95
|
-
# Add the bindings
|
|
96
|
-
if _platform == "darwin":
|
|
97
|
-
self.entry.bind("<Command-Key-a>", self.select_all)
|
|
98
|
-
else:
|
|
99
|
-
self.entry.bind("<Control-Key-a>", self.select_all)
|
|
100
|
-
self.entry.bind('<Control-c>', lambda _: 'break')
|
|
101
|
-
|
|
102
|
-
def select_file(self):
|
|
103
|
-
try:
|
|
104
|
-
result = self.value.get()
|
|
105
|
-
if "Directory" in self.parameter_type:
|
|
106
|
-
result = filedialog.askdirectory(initialdir=self.runner.working_dir, title="Select directory")
|
|
107
|
-
elif "ExistingFile" in self.parameter_type or "NewFile" in self.parameter_type:
|
|
108
|
-
file_types = [('All files', '*.*')]
|
|
109
|
-
if 'RasterAndVector' in self.file_type:
|
|
110
|
-
file_types = [("Shapefiles", "*.shp"), ('Raster files', ('*.dep', '*.tif', '*.tiff',
|
|
111
|
-
'*.bil', '*.flt', '*.sdat',
|
|
112
|
-
'*.rdc', '*.asc', '*grd'))]
|
|
113
|
-
elif 'Raster' in self.file_type:
|
|
114
|
-
file_types = [('Tiff raster files', ('*.tif', '*.tiff')),
|
|
115
|
-
('Other raster files', ('*.dep', '*.bil', '*.flt',
|
|
116
|
-
'*.sdat', '*.rdc', '*.asc', '*.grd'))]
|
|
117
|
-
elif 'Lidar' in self.file_type:
|
|
118
|
-
file_types = [("LiDAR files", ('*.las', '*.zlidar', '*.laz', '*.zip'))]
|
|
119
|
-
elif 'Vector' in self.file_type:
|
|
120
|
-
file_types = [("Shapefiles", "*.shp")]
|
|
121
|
-
elif 'Text' in self.file_type:
|
|
122
|
-
file_types = [("Text files", "*.txt"), ("all files", "*.*")]
|
|
123
|
-
elif 'Csv' in self.file_type:
|
|
124
|
-
file_types = [("CSC files", "*.csv"), ("all files", "*.*")]
|
|
125
|
-
elif 'Dat' in self.file_type:
|
|
126
|
-
file_types = [("Binary data files", "*.dat"), ("all files", "*.*")]
|
|
127
|
-
elif 'Html' in self.file_type:
|
|
128
|
-
file_types = [("HTML files", "*.html")]
|
|
129
|
-
elif 'json' in self.file_type or 'JSON' in self.file_type:
|
|
130
|
-
file_types = [("JSON files", "*.json"), ("CSV files", "*.csv")]
|
|
131
|
-
|
|
132
|
-
# choose default extension to file name
|
|
133
|
-
first_ext = file_types[0][1]
|
|
134
|
-
if type(first_ext) is str:
|
|
135
|
-
default_ext = first_ext
|
|
136
|
-
elif type(first_ext) is tuple:
|
|
137
|
-
default_ext = first_ext[0]
|
|
138
|
-
|
|
139
|
-
default_ext = default_ext.replace('*', '')
|
|
140
|
-
|
|
141
|
-
if "ExistingFile" in self.parameter_type:
|
|
142
|
-
result = filedialog.askopenfilename(
|
|
143
|
-
initialdir=self.runner.working_dir, title="Select "+self.name, filetypes=file_types)
|
|
144
|
-
else:
|
|
145
|
-
result = filedialog.asksaveasfilename(title="Save "+self.name, filetypes=file_types,
|
|
146
|
-
defaultextension=default_ext)
|
|
147
|
-
|
|
148
|
-
# elif "NewFile" in self.parameter_type:
|
|
149
|
-
# result = filedialog.asksaveasfilename()
|
|
150
|
-
|
|
151
|
-
if result != '':
|
|
152
|
-
self.value.set(result)
|
|
153
|
-
self.runner.working_dir = os.path.dirname(result)
|
|
154
|
-
|
|
155
|
-
except:
|
|
156
|
-
t = "file"
|
|
157
|
-
if self.parameter_type == "Directory":
|
|
158
|
-
t = "directory"
|
|
159
|
-
messagebox.showinfo("Warning", "Could not find {}".format(t))
|
|
160
|
-
|
|
161
|
-
def get_value(self):
|
|
162
|
-
if self.value.get():
|
|
163
|
-
v = self.value.get()
|
|
164
|
-
# Do some quality assurance here.
|
|
165
|
-
# Is there a directory included?
|
|
166
|
-
if not path.dirname(v):
|
|
167
|
-
v = path.join(self.runner.working_dir, v)
|
|
168
|
-
|
|
169
|
-
# What about a file extension?
|
|
170
|
-
ext = os.path.splitext(v)[-1].lower().strip()
|
|
171
|
-
if not ext:
|
|
172
|
-
ext = ""
|
|
173
|
-
if 'RasterAndVector' in self.file_type:
|
|
174
|
-
ext = '.tif'
|
|
175
|
-
elif 'Raster' in self.file_type:
|
|
176
|
-
ext = '.tif'
|
|
177
|
-
elif 'Lidar' in self.file_type:
|
|
178
|
-
ext = '.las'
|
|
179
|
-
elif 'Vector' in self.file_type:
|
|
180
|
-
ext = '.shp'
|
|
181
|
-
elif 'Text' in self.file_type:
|
|
182
|
-
ext = '.txt'
|
|
183
|
-
elif 'Csv' in self.file_type:
|
|
184
|
-
ext = '.csv'
|
|
185
|
-
elif 'Html' in self.file_type:
|
|
186
|
-
ext = '.html'
|
|
187
|
-
|
|
188
|
-
v += ext
|
|
189
|
-
|
|
190
|
-
v = path.normpath(v)
|
|
191
|
-
|
|
192
|
-
# return "{}='{}'".format(self.flag, v)
|
|
193
|
-
return self.flag, v
|
|
194
|
-
else:
|
|
195
|
-
t = "file"
|
|
196
|
-
if self.parameter_type == "Directory":
|
|
197
|
-
t = "directory"
|
|
198
|
-
if not self.optional:
|
|
199
|
-
# messagebox.showinfo("Error", "FileSelector: Unspecified {} parameter {}.".format(t, self.flag))
|
|
200
|
-
print("FileSelector: Unspecified {} parameter {}.".format(t, self.flag))
|
|
201
|
-
|
|
202
|
-
return self.flag, ''
|
|
203
|
-
|
|
204
|
-
return None
|
|
205
|
-
|
|
206
|
-
def select_all(self, event):
|
|
207
|
-
self.entry.select_range(0, tk.END)
|
|
208
|
-
return 'break'
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
class FileOrFloat(tk.Frame):
|
|
212
|
-
def __init__(self, json_str, runner, master=None):
|
|
213
|
-
# first make sure that the json data has the correct fields
|
|
214
|
-
j = json.loads(json_str)
|
|
215
|
-
self.name = j['name']
|
|
216
|
-
self.description = j['description']
|
|
217
|
-
self.flag = j['flag']
|
|
218
|
-
self.parameter_type = j['parameter_type']
|
|
219
|
-
self.file_type = j['parameter_type']['ExistingFileOrFloat']
|
|
220
|
-
self.optional = j['optional']
|
|
221
|
-
# default_value = j['default_value']
|
|
222
|
-
|
|
223
|
-
self.runner = runner
|
|
224
|
-
|
|
225
|
-
ttk.Frame.__init__(self, master)
|
|
226
|
-
self.grid()
|
|
227
|
-
self['padding'] = '0.02i'
|
|
228
|
-
|
|
229
|
-
self.label = ttk.Label(self, text=self.name, justify=tk.LEFT)
|
|
230
|
-
self.label.grid(row=0, column=0, sticky=tk.W)
|
|
231
|
-
self.label.columnconfigure(0, weight=1)
|
|
232
|
-
|
|
233
|
-
if not self.optional:
|
|
234
|
-
self.label['text'] = self.label['text'] + "*"
|
|
235
|
-
|
|
236
|
-
fs_frame = ttk.Frame(self, padding='0.0i')
|
|
237
|
-
self.value = tk.StringVar()
|
|
238
|
-
self.entry = ttk.Entry(
|
|
239
|
-
fs_frame, width=35, justify=tk.LEFT, textvariable=self.value)
|
|
240
|
-
self.entry.grid(row=0, column=0, sticky=tk.NSEW)
|
|
241
|
-
self.entry.columnconfigure(0, weight=1)
|
|
242
|
-
# if default_value:
|
|
243
|
-
# self.value.set(default_value)
|
|
244
|
-
|
|
245
|
-
self.open_button = ttk.Button(
|
|
246
|
-
fs_frame, width=4, text="...", command=self.select_file)
|
|
247
|
-
self.open_button.grid(row=0, column=1, sticky=tk.E)
|
|
248
|
-
|
|
249
|
-
self.label = ttk.Label(fs_frame, text='OR', justify=tk.LEFT)
|
|
250
|
-
self.label.grid(row=0, column=2, sticky=tk.W)
|
|
251
|
-
|
|
252
|
-
self.value2 = tk.StringVar()
|
|
253
|
-
self.entry2 = ttk.Entry(
|
|
254
|
-
fs_frame, width=10, justify=tk.LEFT, textvariable=self.value2)
|
|
255
|
-
self.entry2.grid(row=0, column=3, sticky=tk.NSEW)
|
|
256
|
-
self.entry2.columnconfigure(0, weight=1)
|
|
257
|
-
self.entry2['justify'] = 'right'
|
|
258
|
-
|
|
259
|
-
fs_frame.grid(row=1, column=0, sticky=tk.NSEW)
|
|
260
|
-
fs_frame.columnconfigure(0, weight=10)
|
|
261
|
-
fs_frame.columnconfigure(1, weight=1)
|
|
262
|
-
# self.pack(fill=tk.BOTH, expand=1)
|
|
263
|
-
self.columnconfigure(0, weight=1)
|
|
264
|
-
self.rowconfigure(0, weight=1)
|
|
265
|
-
self.rowconfigure(1, weight=1)
|
|
266
|
-
|
|
267
|
-
# Add the bindings
|
|
268
|
-
if _platform == "darwin":
|
|
269
|
-
self.entry.bind("<Command-Key-a>", self.select_all)
|
|
270
|
-
else:
|
|
271
|
-
self.entry.bind("<Control-Key-a>", self.select_all)
|
|
272
|
-
self.entry.bind('<Control-c>', lambda _: 'break')
|
|
273
|
-
|
|
274
|
-
def select_file(self):
|
|
275
|
-
try:
|
|
276
|
-
result = self.value.get()
|
|
277
|
-
file_types = [('All files', '*.*')]
|
|
278
|
-
if 'RasterAndVector' in self.file_type:
|
|
279
|
-
file_types = [("Shapefiles", "*.shp"), ('Raster files', ('*.dep', '*.tif', '*.tiff', '*.bil',
|
|
280
|
-
'*.flt', '*.sdat', '*.rdc', '*.asc'))]
|
|
281
|
-
elif 'Raster' in self.file_type:
|
|
282
|
-
file_types = [('Raster files', ('*.dep', '*.tif', '*.tiff', '*.bil',
|
|
283
|
-
'*.flt', '*.sdat', '*.rdc', '*.asc'))]
|
|
284
|
-
elif 'Lidar' in self.file_type:
|
|
285
|
-
file_types = [("LiDAR files", ('*.las', '*.zlidar', '*.laz', '*.zip'))]
|
|
286
|
-
elif 'Vector' in self.file_type:
|
|
287
|
-
file_types = [("Shapefiles", "*.shp")]
|
|
288
|
-
elif 'Text' in self.file_type:
|
|
289
|
-
file_types = [("Text files", "*.txt"), ("all files", "*.*")]
|
|
290
|
-
elif 'Csv' in self.file_type:
|
|
291
|
-
file_types = [("CSC files", "*.csv"), ("all files", "*.*")]
|
|
292
|
-
elif 'Html' in self.file_type:
|
|
293
|
-
file_types = [("HTML files", "*.html")]
|
|
294
|
-
|
|
295
|
-
result = filedialog.askopenfilename(
|
|
296
|
-
initialdir=self.runner.working_dir, title="Select file", filetypes=file_types)
|
|
297
|
-
|
|
298
|
-
self.value.set(result)
|
|
299
|
-
|
|
300
|
-
# update the working directory
|
|
301
|
-
self.runner.working_dir = os.path.dirname(result)
|
|
302
|
-
|
|
303
|
-
except:
|
|
304
|
-
t = "file"
|
|
305
|
-
if self.parameter_type == "Directory":
|
|
306
|
-
t = "directory"
|
|
307
|
-
messagebox.showinfo("Warning", "Could not find {}".format(t))
|
|
308
|
-
|
|
309
|
-
def RepresentsFloat(self, s):
|
|
310
|
-
try:
|
|
311
|
-
float(s)
|
|
312
|
-
return True
|
|
313
|
-
except ValueError:
|
|
314
|
-
return False
|
|
315
|
-
|
|
316
|
-
def get_value(self):
|
|
317
|
-
if self.value.get():
|
|
318
|
-
v = self.value.get()
|
|
319
|
-
# Do some quality assurance here.
|
|
320
|
-
# Is there a directory included?
|
|
321
|
-
if not path.dirname(v):
|
|
322
|
-
v = path.join(self.runner.working_dir, v)
|
|
323
|
-
|
|
324
|
-
# What about a file extension?
|
|
325
|
-
ext = os.path.splitext(v)[-1].lower()
|
|
326
|
-
if not ext:
|
|
327
|
-
ext = ""
|
|
328
|
-
if 'RasterAndVector' in self.file_type:
|
|
329
|
-
ext = '.tif'
|
|
330
|
-
elif 'Raster' in self.file_type:
|
|
331
|
-
ext = '.tif'
|
|
332
|
-
elif 'Lidar' in self.file_type:
|
|
333
|
-
ext = '.las'
|
|
334
|
-
elif 'Vector' in self.file_type:
|
|
335
|
-
ext = '.shp'
|
|
336
|
-
elif 'Text' in self.file_type:
|
|
337
|
-
ext = '.txt'
|
|
338
|
-
elif 'Csv' in self.file_type:
|
|
339
|
-
ext = '.csv'
|
|
340
|
-
elif 'Html' in self.file_type:
|
|
341
|
-
ext = '.html'
|
|
342
|
-
|
|
343
|
-
v = v + ext
|
|
344
|
-
|
|
345
|
-
v = path.normpath(v)
|
|
346
|
-
return self.flag, v
|
|
347
|
-
elif self.value2.get():
|
|
348
|
-
v = self.value2.get()
|
|
349
|
-
if self.RepresentsFloat(v):
|
|
350
|
-
return "{}={}".format(self.flag, v)
|
|
351
|
-
else:
|
|
352
|
-
messagebox.showinfo(
|
|
353
|
-
"Error", "Error converting parameter {} to type Float.".format(self.flag))
|
|
354
|
-
else:
|
|
355
|
-
if not self.optional:
|
|
356
|
-
messagebox.showinfo(
|
|
357
|
-
"Error", "Unspecified file/numeric parameter {}.".format(self.flag))
|
|
358
|
-
|
|
359
|
-
return None
|
|
360
|
-
|
|
361
|
-
def select_all(self, event):
|
|
362
|
-
self.entry.select_range(0, tk.END)
|
|
363
|
-
return 'break'
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
class MultifileSelector(tk.Frame):
|
|
367
|
-
def __init__(self, json_str, runner, master=None):
|
|
368
|
-
# first make sure that the json data has the correct fields
|
|
369
|
-
j = json.loads(json_str)
|
|
370
|
-
self.name = j['name']
|
|
371
|
-
self.description = j['description']
|
|
372
|
-
self.flag = j['flag']
|
|
373
|
-
self.parameter_type = j['parameter_type']
|
|
374
|
-
self.file_type = ""
|
|
375
|
-
self.file_type = j['parameter_type']['FileList']
|
|
376
|
-
self.optional = j['optional']
|
|
377
|
-
default_value = j['default_value']
|
|
378
|
-
|
|
379
|
-
self.runner = runner
|
|
380
|
-
|
|
381
|
-
ttk.Frame.__init__(self, master)
|
|
382
|
-
self.grid()
|
|
383
|
-
self['padding'] = '0.05i'
|
|
384
|
-
|
|
385
|
-
self.label = ttk.Label(self, text=self.name, justify=tk.LEFT)
|
|
386
|
-
self.label.grid(row=0, column=0, sticky=tk.W)
|
|
387
|
-
self.label.columnconfigure(0, weight=1)
|
|
388
|
-
|
|
389
|
-
if not self.optional:
|
|
390
|
-
self.label['text'] = self.label['text'] + "*"
|
|
391
|
-
|
|
392
|
-
fs_frame = ttk.Frame(self, padding='0.0i')
|
|
393
|
-
# , variable=self.value)
|
|
394
|
-
self.opt = tk.Listbox(fs_frame, width=44, height=4)
|
|
395
|
-
self.opt.grid(row=0, column=0, sticky=tk.NSEW)
|
|
396
|
-
s = ttk.Scrollbar(fs_frame, orient=tk.VERTICAL, command=self.opt.yview)
|
|
397
|
-
s.grid(row=0, column=1, sticky=(tk.N, tk.S))
|
|
398
|
-
self.opt['yscrollcommand'] = s.set
|
|
399
|
-
|
|
400
|
-
btn_frame = ttk.Frame(fs_frame, padding='0.0i')
|
|
401
|
-
self.open_button = ttk.Button(
|
|
402
|
-
btn_frame, width=4, text="...", command=self.select_file)
|
|
403
|
-
self.open_button.grid(row=0, column=0, sticky=tk.NE)
|
|
404
|
-
self.open_button.columnconfigure(0, weight=1)
|
|
405
|
-
self.open_button.rowconfigure(0, weight=1)
|
|
406
|
-
|
|
407
|
-
self.delete_button = ttk.Button(
|
|
408
|
-
btn_frame, width=4, text="del", command=self.delete_entry)
|
|
409
|
-
self.delete_button.grid(row=1, column=0, sticky=tk.NE)
|
|
410
|
-
self.delete_button.columnconfigure(0, weight=1)
|
|
411
|
-
self.delete_button.rowconfigure(1, weight=1)
|
|
412
|
-
|
|
413
|
-
btn_frame.grid(row=0, column=2, sticky=tk.NE)
|
|
414
|
-
|
|
415
|
-
fs_frame.grid(row=1, column=0, sticky=tk.NSEW)
|
|
416
|
-
fs_frame.columnconfigure(0, weight=10)
|
|
417
|
-
fs_frame.columnconfigure(1, weight=1)
|
|
418
|
-
fs_frame.columnconfigure(2, weight=1)
|
|
419
|
-
# self.pack(fill=tk.BOTH, expand=1)
|
|
420
|
-
self.columnconfigure(0, weight=1)
|
|
421
|
-
self.rowconfigure(0, weight=1)
|
|
422
|
-
self.rowconfigure(1, weight=1)
|
|
423
|
-
|
|
424
|
-
def select_file(self):
|
|
425
|
-
try:
|
|
426
|
-
# result = self.value.get()
|
|
427
|
-
init_dir = self.runner.working_dir
|
|
428
|
-
file_types = [('All files', '*.*')]
|
|
429
|
-
if 'RasterAndVector' in self.file_type:
|
|
430
|
-
file_types = [("Shapefiles", "*.shp"), ('Raster files', ('*.dep', '*.tif', '*.tiff', '*.bil',
|
|
431
|
-
'*.flt', '*.sdat', '*.rdc', '*.asc'))]
|
|
432
|
-
elif 'Raster' in self.file_type:
|
|
433
|
-
file_types = [('Raster files', ('*.dep', '*.tif', '*.tiff', '*.bil',
|
|
434
|
-
'*.flt', '*.sdat', '*.rdc', '*.asc'))]
|
|
435
|
-
elif 'Lidar' in self.file_type:
|
|
436
|
-
file_types = [("LiDAR files", ('*.las', '*.zlidar', '*.laz', '*.zip'))]
|
|
437
|
-
elif 'Vector' in self.file_type:
|
|
438
|
-
file_types = [("Shapefiles", "*.shp")]
|
|
439
|
-
elif 'Text' in self.file_type:
|
|
440
|
-
file_types = [("Text files", "*.txt"), ("all files", "*.*")]
|
|
441
|
-
elif 'Csv' in self.file_type:
|
|
442
|
-
file_types = [("CSC files", "*.csv"), ("all files", "*.*")]
|
|
443
|
-
elif 'Html' in self.file_type:
|
|
444
|
-
file_types = [("HTML files", "*.html")]
|
|
445
|
-
|
|
446
|
-
result = filedialog.askopenfilenames(
|
|
447
|
-
initialdir=init_dir, title="Select files", filetypes=file_types)
|
|
448
|
-
if result:
|
|
449
|
-
for v in result:
|
|
450
|
-
self.opt.insert(tk.END, v)
|
|
451
|
-
|
|
452
|
-
# update the working directory
|
|
453
|
-
self.runner.working_dir = os.path.dirname(result[0])
|
|
454
|
-
except:
|
|
455
|
-
messagebox.showinfo("Warning", "Could not find file")
|
|
456
|
-
|
|
457
|
-
def delete_entry(self):
|
|
458
|
-
self.opt.delete(tk.ANCHOR)
|
|
459
|
-
|
|
460
|
-
def get_value(self):
|
|
461
|
-
try:
|
|
462
|
-
l = self.opt.get(0, tk.END)
|
|
463
|
-
if l:
|
|
464
|
-
s = ""
|
|
465
|
-
for i in range(0, len(l)):
|
|
466
|
-
v = l[i]
|
|
467
|
-
if not path.dirname(v):
|
|
468
|
-
v = path.join(self.runner.working_dir, v)
|
|
469
|
-
v = path.normpath(v)
|
|
470
|
-
if i < len(l) - 1:
|
|
471
|
-
s += "{};".format(v)
|
|
472
|
-
else:
|
|
473
|
-
s += "{}".format(v)
|
|
474
|
-
|
|
475
|
-
# return "{}='{}'".format(self.flag, s)
|
|
476
|
-
return self.flag, v
|
|
477
|
-
else:
|
|
478
|
-
if not self.optional:
|
|
479
|
-
print("Error", "Unspecified non-optional parameter {}.".format(self.flag))
|
|
480
|
-
except:
|
|
481
|
-
messagebox.showinfo(
|
|
482
|
-
"Error", "Error formatting files for parameter {}".format(self.flag))
|
|
483
|
-
|
|
484
|
-
return None
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
class BooleanInput(tk.Frame):
|
|
488
|
-
def __init__(self, json_str, master=None):
|
|
489
|
-
# first make sure that the json data has the correct fields
|
|
490
|
-
j = json.loads(json_str)
|
|
491
|
-
self.name = j['name']
|
|
492
|
-
self.description = j['description']
|
|
493
|
-
self.flag = j['flag']
|
|
494
|
-
self.parameter_type = j['parameter_type']
|
|
495
|
-
# just for quality control. BooleanInputs are always optional.
|
|
496
|
-
self.optional = True
|
|
497
|
-
# default_value = j['default_value']
|
|
498
|
-
|
|
499
|
-
ttk.Frame.__init__(self, master)
|
|
500
|
-
self.grid()
|
|
501
|
-
self['padding'] = '0.05i'
|
|
502
|
-
|
|
503
|
-
frame = ttk.Frame(self, padding='0.0i')
|
|
504
|
-
|
|
505
|
-
self.value = tk.IntVar()
|
|
506
|
-
c = ttk.Checkbutton(frame, text=self.name,
|
|
507
|
-
width=55, variable=self.value)
|
|
508
|
-
c.grid(row=0, column=0, sticky=tk.W)
|
|
509
|
-
CreateToolTip(c, self.description)
|
|
510
|
-
|
|
511
|
-
# set the default value
|
|
512
|
-
# if j['default_value'] is not None and j['default_value'] != 'false':
|
|
513
|
-
# self.value.set(1)
|
|
514
|
-
# else:
|
|
515
|
-
# self.value.set(0)
|
|
516
|
-
|
|
517
|
-
frame.grid(row=1, column=0, sticky=tk.W)
|
|
518
|
-
frame.columnconfigure(0, weight=1)
|
|
519
|
-
|
|
520
|
-
# self.pack(fill=tk.BOTH, expand=1)
|
|
521
|
-
self.columnconfigure(0, weight=1)
|
|
522
|
-
self.rowconfigure(0, weight=1)
|
|
523
|
-
|
|
524
|
-
def get_value(self):
|
|
525
|
-
value = self.value.get()
|
|
526
|
-
if value == 1:
|
|
527
|
-
return self.flag, True
|
|
528
|
-
else:
|
|
529
|
-
return self.flag, False
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
class OptionsInput(tk.Frame):
|
|
533
|
-
def __init__(self, json_str, master=None):
|
|
534
|
-
|
|
535
|
-
# first make sure that the json data has the correct fields
|
|
536
|
-
j = json.loads(json_str)
|
|
537
|
-
self.name = j['name']
|
|
538
|
-
self.description = j['description']
|
|
539
|
-
self.flag = j['flag']
|
|
540
|
-
self.parameter_type = j['parameter_type']
|
|
541
|
-
self.optional = j['optional']
|
|
542
|
-
self.data_type = j['data_type']
|
|
543
|
-
if 'saved_value' in j.keys():
|
|
544
|
-
default_value = str(j['saved_value'])
|
|
545
|
-
else:
|
|
546
|
-
default_value = str(j['default_value'])
|
|
547
|
-
self.value = default_value # initialize in event of no default and no selection
|
|
548
|
-
|
|
549
|
-
ttk.Frame.__init__(self, master)
|
|
550
|
-
self.grid()
|
|
551
|
-
self['padding'] = '0.02i'
|
|
552
|
-
|
|
553
|
-
frame = ttk.Frame(self, padding='0.0i')
|
|
554
|
-
|
|
555
|
-
self.label = ttk.Label(self, text=self.name, justify=tk.LEFT)
|
|
556
|
-
self.label.grid(row=0, column=0, sticky=tk.W)
|
|
557
|
-
self.label.columnconfigure(0, weight=1)
|
|
558
|
-
|
|
559
|
-
frame2 = ttk.Frame(frame, padding='0.0i')
|
|
560
|
-
opt = ttk.Combobox(frame2, width=40)
|
|
561
|
-
opt.grid(row=0, column=0, sticky=tk.NSEW)
|
|
562
|
-
|
|
563
|
-
i = 1
|
|
564
|
-
default_index = -1
|
|
565
|
-
option_list = j['parameter_type']['OptionList']
|
|
566
|
-
if option_list:
|
|
567
|
-
option_list = [str(item) for item in option_list] # convert to strings
|
|
568
|
-
values = ()
|
|
569
|
-
for v in option_list:
|
|
570
|
-
values += (v,)
|
|
571
|
-
if v == str(default_value):
|
|
572
|
-
default_index = i - 1
|
|
573
|
-
i = i + 1
|
|
574
|
-
|
|
575
|
-
opt['values'] = values
|
|
576
|
-
|
|
577
|
-
opt.bind("<<ComboboxSelected>>", self.select)
|
|
578
|
-
if default_index >= 0:
|
|
579
|
-
opt.current(default_index)
|
|
580
|
-
opt.event_generate("<<ComboboxSelected>>")
|
|
581
|
-
|
|
582
|
-
frame2.grid(row=0, column=0, sticky=tk.W)
|
|
583
|
-
frame.grid(row=1, column=0, sticky=tk.W)
|
|
584
|
-
frame.columnconfigure(0, weight=1)
|
|
585
|
-
|
|
586
|
-
self.columnconfigure(0, weight=1)
|
|
587
|
-
self.rowconfigure(0, weight=1)
|
|
588
|
-
|
|
589
|
-
opt.bind('<Control-c>', lambda _: 'break')
|
|
590
|
-
|
|
591
|
-
def get_value(self):
|
|
592
|
-
if self.value is not None:
|
|
593
|
-
value = self.value
|
|
594
|
-
if 'Float' == self.data_type:
|
|
595
|
-
value = float(self.value)
|
|
596
|
-
elif 'Integer' == self.data_type:
|
|
597
|
-
value = int(self.value)
|
|
598
|
-
elif 'Boolean' == self.data_type:
|
|
599
|
-
if type(value) is str:
|
|
600
|
-
value = True if self.value == 'True' else False
|
|
601
|
-
|
|
602
|
-
return self.flag, value
|
|
603
|
-
else:
|
|
604
|
-
if not self.optional:
|
|
605
|
-
print("Error", "Unspecified non-optional parameter {}.".format(self.flag))
|
|
606
|
-
|
|
607
|
-
return None
|
|
608
|
-
|
|
609
|
-
def select(self, event):
|
|
610
|
-
widget = event.widget
|
|
611
|
-
self.value = widget.get() # selection[0])
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
class DataInput(tk.Frame):
|
|
615
|
-
def __init__(self, json_str, master=None):
|
|
616
|
-
|
|
617
|
-
# first make sure that the json data has the correct fields
|
|
618
|
-
j = json.loads(json_str)
|
|
619
|
-
self.name = j['name']
|
|
620
|
-
self.description = j['description']
|
|
621
|
-
self.flag = j['flag']
|
|
622
|
-
self.parameter_type = j['parameter_type']
|
|
623
|
-
self.optional = j['optional']
|
|
624
|
-
# default_value = j['default_value']
|
|
625
|
-
|
|
626
|
-
ttk.Frame.__init__(self, master)
|
|
627
|
-
self.grid()
|
|
628
|
-
self['padding'] = '0.1i'
|
|
629
|
-
|
|
630
|
-
self.label = ttk.Label(self, text=self.name, justify=tk.LEFT)
|
|
631
|
-
self.label.grid(row=0, column=0, sticky=tk.W)
|
|
632
|
-
self.label.columnconfigure(0, weight=1)
|
|
633
|
-
CreateToolTip(self.label, self.description)
|
|
634
|
-
|
|
635
|
-
self.value = tk.StringVar()
|
|
636
|
-
# if default_value:
|
|
637
|
-
# self.value.set(default_value)
|
|
638
|
-
# else:
|
|
639
|
-
# self.value.set("")
|
|
640
|
-
|
|
641
|
-
self.entry = ttk.Entry(self, justify=tk.LEFT, textvariable=self.value)
|
|
642
|
-
self.entry.grid(row=0, column=1, sticky=tk.NSEW)
|
|
643
|
-
self.entry.columnconfigure(1, weight=10)
|
|
644
|
-
|
|
645
|
-
if not self.optional:
|
|
646
|
-
self.label['text'] = self.label['text'] + "*"
|
|
647
|
-
|
|
648
|
-
if ("Integer" in self.parameter_type or
|
|
649
|
-
"Float" in self.parameter_type or
|
|
650
|
-
"Double" in self.parameter_type):
|
|
651
|
-
self.entry['justify'] = 'right'
|
|
652
|
-
|
|
653
|
-
# Add the bindings
|
|
654
|
-
if _platform == "darwin":
|
|
655
|
-
self.entry.bind("<Command-Key-a>", self.select_all)
|
|
656
|
-
else:
|
|
657
|
-
self.entry.bind("<Control-Key-a>", self.select_all)
|
|
658
|
-
self.entry.bind('<Control-c>', lambda _: 'break')
|
|
659
|
-
|
|
660
|
-
# self.pack(fill=tk.BOTH, expand=1)
|
|
661
|
-
self.columnconfigure(0, weight=1)
|
|
662
|
-
self.columnconfigure(1, weight=10)
|
|
663
|
-
self.rowconfigure(0, weight=1)
|
|
664
|
-
|
|
665
|
-
def RepresentsInt(self, s):
|
|
666
|
-
try:
|
|
667
|
-
int(s)
|
|
668
|
-
return True
|
|
669
|
-
except ValueError:
|
|
670
|
-
return False
|
|
671
|
-
|
|
672
|
-
def RepresentsFloat(self, s):
|
|
673
|
-
try:
|
|
674
|
-
float(s)
|
|
675
|
-
return True
|
|
676
|
-
except ValueError:
|
|
677
|
-
return False
|
|
678
|
-
|
|
679
|
-
def get_value(self):
|
|
680
|
-
v = self.value.get()
|
|
681
|
-
if v:
|
|
682
|
-
if "Integer" in self.parameter_type:
|
|
683
|
-
if self.RepresentsInt(self.value.get()):
|
|
684
|
-
# return "{}={}".format(self.flag, self.value.get())
|
|
685
|
-
return self.flag, int(self.value.get())
|
|
686
|
-
else:
|
|
687
|
-
messagebox.showinfo("Error", "Error converting parameter {} to type Integer.".format(self.flag))
|
|
688
|
-
elif "Float" in self.parameter_type:
|
|
689
|
-
if self.RepresentsFloat(self.value.get()):
|
|
690
|
-
# return "{}={}".format(self.flag, self.value.get())
|
|
691
|
-
return self.flag, float(self.value.get())
|
|
692
|
-
else:
|
|
693
|
-
messagebox.showinfo("Error", "Error converting parameter {} to type Float.".format(self.flag))
|
|
694
|
-
elif "Double" in self.parameter_type:
|
|
695
|
-
if self.RepresentsFloat(self.value.get()):
|
|
696
|
-
# return "{}={}".format(self.flag, self.value.get())
|
|
697
|
-
return self.flag, float(self.value.get())
|
|
698
|
-
else:
|
|
699
|
-
messagebox.showinfo("Error", "Error converting parameter {} to type Double.".format(self.flag))
|
|
700
|
-
else: # String or StringOrNumber types
|
|
701
|
-
# return "{}='{}'".format(self.flag, self.value.get())
|
|
702
|
-
return self.flag, self.value.get()
|
|
703
|
-
else:
|
|
704
|
-
if not self.optional:
|
|
705
|
-
messagebox.showinfo("Error", "Unspecified non-optional parameter {}.".format(self.flag))
|
|
706
|
-
|
|
707
|
-
return None
|
|
708
|
-
|
|
709
|
-
def select_all(self, event):
|
|
710
|
-
self.entry.select_range(0, tk.END)
|
|
711
|
-
return 'break'
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
class MainGui(tk.Frame):
|
|
715
|
-
def __init__(self, tool_name=None, master=None):
|
|
716
|
-
self.descriptionList = None
|
|
717
|
-
self.search_string = None
|
|
718
|
-
self.toolbox_open = None
|
|
719
|
-
self.toolbox_name = None
|
|
720
|
-
self.tools_list = None
|
|
721
|
-
self.sorted_tools = None
|
|
722
|
-
self.lower_toolboxes = None
|
|
723
|
-
self.upper_toolboxes = None
|
|
724
|
-
self.file_menu = None
|
|
725
|
-
self.closed_toolbox_icon = None
|
|
726
|
-
self.open_toolbox_icon = None
|
|
727
|
-
self.tool_icon = None
|
|
728
|
-
self.tool_tree = None
|
|
729
|
-
self.progress = None
|
|
730
|
-
self.progress_var = None
|
|
731
|
-
self.progress_label = None
|
|
732
|
-
self.help_button = None
|
|
733
|
-
self.cancel_button = None
|
|
734
|
-
self.run_button = None
|
|
735
|
-
self.arg_scroll_frame = None
|
|
736
|
-
self.view_code_button = None
|
|
737
|
-
self.show_advanced_button = None
|
|
738
|
-
self.current_tool_lbl = None
|
|
739
|
-
self.current_tool_frame = None
|
|
740
|
-
self.search_scroll = None
|
|
741
|
-
self.search_results_listbox = None
|
|
742
|
-
self.search_bar = None
|
|
743
|
-
self.search_label = None
|
|
744
|
-
self.search_frame = None
|
|
745
|
-
self.search_text = None
|
|
746
|
-
self.search_list = None
|
|
747
|
-
self.tools_frame = None
|
|
748
|
-
self.toolbox_list = None
|
|
749
|
-
self.tools_and_toolboxes = None
|
|
750
|
-
self.out_text = None
|
|
751
|
-
self.search_tool_selected = None
|
|
752
|
-
self.reset_button = None
|
|
753
|
-
self.current_tool_api = None
|
|
754
|
-
|
|
755
|
-
if platform.system() == 'Windows':
|
|
756
|
-
self.ext = '.exe'
|
|
757
|
-
else:
|
|
758
|
-
self.ext = ''
|
|
759
|
-
|
|
760
|
-
exe_name = "BERA_tools{}".format(self.ext)
|
|
761
|
-
|
|
762
|
-
# BERA tool list
|
|
763
|
-
self.bera_tools = bt.bera_tools
|
|
764
|
-
self.tools_list = bt.tools_list
|
|
765
|
-
self.sorted_tools = bt.sorted_tools
|
|
766
|
-
self.toolbox_list = bt.toolbox_list
|
|
767
|
-
self.upper_toolboxes = bt.upper_toolboxes
|
|
768
|
-
self.lower_toolboxes = bt.lower_toolboxes
|
|
769
|
-
|
|
770
|
-
self.exe_path = path.dirname(path.abspath(__file__))
|
|
771
|
-
os.chdir(self.exe_path)
|
|
772
|
-
for filename in glob.iglob('**/*', recursive=True):
|
|
773
|
-
if filename.endswith(exe_name):
|
|
774
|
-
self.exe_path = path.dirname(path.abspath(filename))
|
|
775
|
-
break
|
|
776
|
-
|
|
777
|
-
bt.set_bera_dir(self.exe_path)
|
|
778
|
-
|
|
779
|
-
ttk.Frame.__init__(self, master)
|
|
780
|
-
self.script_dir = os.path.dirname(os.path.realpath(__file__))
|
|
781
|
-
self.grid()
|
|
782
|
-
self.tool_name = tool_name
|
|
783
|
-
self.master.title("BERA Tools")
|
|
784
|
-
if _platform == "darwin":
|
|
785
|
-
os.system('''/usr/bin/osascript -e 'tell app "Finder" to set front-most of process "Python" to true' ''')
|
|
786
|
-
self.create_widgets()
|
|
787
|
-
self.working_dir = bt.get_working_dir() # str(Path.home())
|
|
788
|
-
|
|
789
|
-
def root(self):
|
|
790
|
-
return self._root()
|
|
791
|
-
|
|
792
|
-
def create_widgets(self):
|
|
793
|
-
#########################################################
|
|
794
|
-
# Overall/Top level Frame
|
|
795
|
-
#
|
|
796
|
-
# define left-side frame (left_frame) and right-side frame (right_frame)
|
|
797
|
-
self.pack(fill="both", expand=True)
|
|
798
|
-
self.rowconfigure(0, weight=1)
|
|
799
|
-
self.columnconfigure(0, weight=1)
|
|
800
|
-
self.columnconfigure(1, weight=1)
|
|
801
|
-
|
|
802
|
-
left_frame = ttk.Frame(self, padding='0.1i')
|
|
803
|
-
right_frame = ttk.Frame(self, padding='0.1i')
|
|
804
|
-
|
|
805
|
-
# set-up layout
|
|
806
|
-
left_frame.grid(row=0, column=0, sticky=tk.NSEW)
|
|
807
|
-
right_frame.grid(row=0, column=1, sticky=tk.NSEW)
|
|
808
|
-
|
|
809
|
-
left_frame.rowconfigure(0, weight=10)
|
|
810
|
-
left_frame.rowconfigure(1, weight=1)
|
|
811
|
-
left_frame.columnconfigure(0, weight=1)
|
|
812
|
-
|
|
813
|
-
# right_frame.rowconfigure(0, weight=1)
|
|
814
|
-
# right_frame.rowconfigure(1, weight=1)
|
|
815
|
-
# right_frame.rowconfigure(2, weight=1)
|
|
816
|
-
right_frame.rowconfigure(3, weight=1)
|
|
817
|
-
# right_frame.rowconfigure(4, weight=1)
|
|
818
|
-
|
|
819
|
-
right_frame.columnconfigure(0, weight=1)
|
|
820
|
-
|
|
821
|
-
# Icons to be used in tool treeview
|
|
822
|
-
self.tool_icon = tk.PhotoImage(file=self.script_dir + '//img//tool.gif')
|
|
823
|
-
self.open_toolbox_icon = tk.PhotoImage(file=self.script_dir + '//img//open.gif')
|
|
824
|
-
self.closed_toolbox_icon = tk.PhotoImage(file=self.script_dir + '//img//closed.gif')
|
|
825
|
-
|
|
826
|
-
#########################################################
|
|
827
|
-
# Toolboxes Frame
|
|
828
|
-
# define tools_frame and tool_tree
|
|
829
|
-
self.tools_frame = ttk.LabelFrame(left_frame, text="{} Available Tools".format(len(self.tools_list)),
|
|
830
|
-
padding='0.1i')
|
|
831
|
-
self.tool_tree = ttk.Treeview(self.tools_frame, height=21)
|
|
832
|
-
|
|
833
|
-
# Set up layout
|
|
834
|
-
self.tool_tree.grid(row=0, column=0, sticky=tk.NSEW)
|
|
835
|
-
self.tool_tree.column("#0", width=280) # Set width so all tools are readable within the frame
|
|
836
|
-
self.tools_frame.grid(row=0, column=0, sticky=tk.NSEW)
|
|
837
|
-
self.tools_frame.columnconfigure(0, weight=10)
|
|
838
|
-
self.tools_frame.columnconfigure(1, weight=1)
|
|
839
|
-
self.tools_frame.rowconfigure(0, weight=10)
|
|
840
|
-
self.tools_frame.rowconfigure(1, weight=1)
|
|
841
|
-
|
|
842
|
-
# Add toolboxes and tools to treeview
|
|
843
|
-
self.add_tools_to_treeview()
|
|
844
|
-
self.update_selected_bera_tool()
|
|
845
|
-
|
|
846
|
-
# bind tools in treeview to self.tree_update_tool_help function
|
|
847
|
-
# and toolboxes to self.update_toolbox_icon function
|
|
848
|
-
# TODO: BERA tool help
|
|
849
|
-
self.tool_tree.tag_bind('tool', "<<TreeviewSelect>>", self.tree_update_tool_help)
|
|
850
|
-
self.tool_tree.tag_bind('toolbox', "<<TreeviewSelect>>", self.update_toolbox_icon)
|
|
851
|
-
|
|
852
|
-
# Add vertical scrollbar to treeview frame
|
|
853
|
-
s = ttk.Scrollbar(self.tools_frame, orient=tk.VERTICAL, command=self.tool_tree.yview)
|
|
854
|
-
s.grid(row=0, column=1, sticky=tk.NS)
|
|
855
|
-
self.tool_tree['yscrollcommand'] = s.set
|
|
856
|
-
|
|
857
|
-
#########################################################
|
|
858
|
-
# Search Bar
|
|
859
|
-
# create variables for search results and search input
|
|
860
|
-
self.search_list = []
|
|
861
|
-
self.search_text = tk.StringVar()
|
|
862
|
-
|
|
863
|
-
# Create the elements of the search frame
|
|
864
|
-
self.search_frame = ttk.LabelFrame(left_frame, padding='0.1i',
|
|
865
|
-
text="{} Tools Found".format(len(self.search_list)))
|
|
866
|
-
self.search_label = ttk.Label(self.search_frame, text="Search: ")
|
|
867
|
-
self.search_bar = ttk.Entry(self.search_frame, width=30, textvariable=self.search_text)
|
|
868
|
-
self.search_results_listbox = tk.Listbox(self.search_frame, height=11, exportselection=False)
|
|
869
|
-
self.search_scroll = ttk.Scrollbar(self.search_frame, orient=tk.VERTICAL,
|
|
870
|
-
command=self.search_results_listbox.yview)
|
|
871
|
-
self.search_results_listbox['yscrollcommand'] = self.search_scroll.set
|
|
872
|
-
|
|
873
|
-
# Add bindings
|
|
874
|
-
self.search_results_listbox.bind("<<ListboxSelect>>", self.update_search_tool_info)
|
|
875
|
-
self.search_bar.bind('<Return>', self.update_search)
|
|
876
|
-
|
|
877
|
-
# Define layout of the frame
|
|
878
|
-
self.search_frame.grid(row=1, column=0, sticky=tk.NSEW)
|
|
879
|
-
self.search_label.grid(row=0, column=0, sticky=tk.NW)
|
|
880
|
-
self.search_bar.grid(row=0, column=1, sticky=tk.NE)
|
|
881
|
-
self.search_results_listbox.grid(row=1, column=0, columnspan=2, sticky=tk.NSEW, pady=5)
|
|
882
|
-
self.search_scroll.grid(row=1, column=2, sticky=tk.NS)
|
|
883
|
-
|
|
884
|
-
# Configure rows and columns of the frame
|
|
885
|
-
self.search_frame.columnconfigure(0, weight=1)
|
|
886
|
-
self.search_frame.columnconfigure(1, weight=10)
|
|
887
|
-
self.search_frame.columnconfigure(1, weight=1)
|
|
888
|
-
self.search_frame.rowconfigure(0, weight=1)
|
|
889
|
-
self.search_frame.rowconfigure(1, weight=10)
|
|
890
|
-
|
|
891
|
-
# add recent tools to search list
|
|
892
|
-
self.add_recent_tool_to_search()
|
|
893
|
-
|
|
894
|
-
#########################################################
|
|
895
|
-
# Current Tool Frame
|
|
896
|
-
# Create the elements of the current tool frame
|
|
897
|
-
self.current_tool_frame = ttk.Frame(right_frame, padding='0.01i')
|
|
898
|
-
self.current_tool_lbl = ttk.Label(self.current_tool_frame, text="Current Tool: {}".format(self.tool_name),
|
|
899
|
-
justify=tk.LEFT, font=("Helvetica", 11, "bold"))
|
|
900
|
-
self.show_advanced_button = ttk.Button(self.current_tool_frame, text="Show Advanced Options",
|
|
901
|
-
width=24, command=self.show_advanced)
|
|
902
|
-
CreateToolTip(self.show_advanced_button, 'Show/hide tool advanced options')
|
|
903
|
-
self.view_code_button = ttk.Button(self.current_tool_frame, text="View Code", width=12, command=self.view_code)
|
|
904
|
-
CreateToolTip(self.view_code_button, 'Go to the tool code web page')
|
|
905
|
-
|
|
906
|
-
# Define layout of the frame
|
|
907
|
-
self.show_advanced_button.grid(row=0, column=1, sticky=tk.E)
|
|
908
|
-
self.view_code_button.grid(row=0, column=2, sticky=tk.E)
|
|
909
|
-
self.current_tool_lbl.grid(row=0, column=0, sticky=tk.W)
|
|
910
|
-
self.current_tool_frame.grid(row=0, column=0, columnspan=2, sticky=tk.NSEW)
|
|
911
|
-
|
|
912
|
-
# Configure rows and columns of the frame
|
|
913
|
-
self.current_tool_frame.columnconfigure(0, weight=1)
|
|
914
|
-
self.current_tool_frame.columnconfigure(1, weight=1)
|
|
915
|
-
|
|
916
|
-
self.arg_scroll_frame = ttk.Frame(right_frame, padding='0.0i')
|
|
917
|
-
self.arg_scroll_frame.grid(row=1, column=0, sticky=tk.NSEW)
|
|
918
|
-
self.arg_scroll_frame.columnconfigure(0, weight=1)
|
|
919
|
-
|
|
920
|
-
#########################################################
|
|
921
|
-
# Buttons Frame
|
|
922
|
-
#
|
|
923
|
-
# Create the elements of the buttons frame
|
|
924
|
-
buttons_frame = ttk.Frame(right_frame, padding='0.1i')
|
|
925
|
-
self.mpc_label = ttk.Label(buttons_frame, text="Use CPU Cores:")
|
|
926
|
-
max_cores = bt.get_max_cpu_cores()
|
|
927
|
-
if bt.get_max_procs() <= 0:
|
|
928
|
-
bt.set_max_procs(max_cores)
|
|
929
|
-
self.mpc_scale = tk.Scale(buttons_frame, from_=1, to=max_cores, length=180,
|
|
930
|
-
orient='horizontal', command=self.update_procs)
|
|
931
|
-
# multiprocessing core slide
|
|
932
|
-
CreateToolTip(self.mpc_label, 'The number of CPU cores to be used in parallel processes')
|
|
933
|
-
self.mpc_scale.set(bt.get_max_procs())
|
|
934
|
-
|
|
935
|
-
self.reset_button = ttk.Button(buttons_frame, text="Clear Arguments", width=16, command=self.reset_tool)
|
|
936
|
-
self.run_button = ttk.Button(buttons_frame, text="Run", width=8, command=lambda: self.start_run_tool_thread())
|
|
937
|
-
self.cancel_button = ttk.Button(buttons_frame, text="Cancel", width=8, command=self.cancel_operation)
|
|
938
|
-
self.help_button = ttk.Button(buttons_frame, text="Help", width=8, command=self.tool_help_button)
|
|
939
|
-
CreateToolTip(self.reset_button, 'Clear all tool arguments and set to default')
|
|
940
|
-
CreateToolTip(self.cancel_button, 'Cancel tool operation')
|
|
941
|
-
CreateToolTip(self.run_button, 'Run the tool')
|
|
942
|
-
CreateToolTip(self.help_button, 'Go to the tool help web page')
|
|
943
|
-
|
|
944
|
-
# Define layout of the frame
|
|
945
|
-
self.reset_button.grid(row=0, column=0, padx=4)
|
|
946
|
-
self.mpc_label.grid(row=0, column=1, padx=4)
|
|
947
|
-
self.mpc_scale.grid(row=0, column=2, padx=5, ipady=10)
|
|
948
|
-
self.run_button.grid(row=0, column=3)
|
|
949
|
-
self.cancel_button.grid(row=0, column=4)
|
|
950
|
-
self.help_button.grid(row=0, column=5)
|
|
951
|
-
buttons_frame.grid(row=2, column=0, columnspan=2, sticky=tk.E)
|
|
952
|
-
buttons_frame.rowconfigure(2, weight=1)
|
|
953
|
-
|
|
954
|
-
#########################################################
|
|
955
|
-
# Output Frame
|
|
956
|
-
# Create the elements of the output frame
|
|
957
|
-
output_frame = ttk.Frame(right_frame)
|
|
958
|
-
out_label = ttk.Label(output_frame, text="Output:", justify=tk.LEFT)
|
|
959
|
-
self.out_text = ScrolledText(output_frame, width=63, height=15, wrap=tk.NONE, padx=7, pady=7, exportselection=0)
|
|
960
|
-
output_scrollbar = ttk.Scrollbar(output_frame, orient=tk.HORIZONTAL, command=self.out_text.xview)
|
|
961
|
-
self.out_text['xscrollcommand'] = output_scrollbar.set
|
|
962
|
-
|
|
963
|
-
# color theme for text output
|
|
964
|
-
self.out_text.tag_config('missing', foreground='red')
|
|
965
|
-
# Retrieve and insert the text for the current tool
|
|
966
|
-
|
|
967
|
-
# BERA Tools help text
|
|
968
|
-
k = bt.get_bera_tool_info(self.tool_name)
|
|
969
|
-
if k:
|
|
970
|
-
self.out_text.insert(tk.END, k)
|
|
971
|
-
|
|
972
|
-
# Define layout of the frame
|
|
973
|
-
output_frame.grid(row=3, column=0, columnspan=2, sticky=tk.NSEW) # inside right_frame
|
|
974
|
-
|
|
975
|
-
out_label.grid(row=0, column=0, sticky=tk.NW)
|
|
976
|
-
self.out_text.grid(row=1, column=0, sticky=tk.NSEW)
|
|
977
|
-
output_scrollbar.grid(row=2, column=0, sticky=tk.EW)
|
|
978
|
-
|
|
979
|
-
output_frame.rowconfigure(1, weight=1)
|
|
980
|
-
output_frame.columnconfigure(0, weight=1)
|
|
981
|
-
|
|
982
|
-
# Add the binding
|
|
983
|
-
if _platform == "darwin":
|
|
984
|
-
self.out_text.bind("<Command-Key-a>", self.select_all)
|
|
985
|
-
else:
|
|
986
|
-
self.out_text.bind("<Control-Key-a>", self.select_all)
|
|
987
|
-
|
|
988
|
-
# disable copy, paste and delete keys
|
|
989
|
-
self.out_text.bind('<Control-v>', lambda _: 'break')
|
|
990
|
-
self.out_text.bind('<Control-c>', lambda _: 'break')
|
|
991
|
-
self.out_text.bind('<BackSpace>', lambda _: 'break')
|
|
992
|
-
|
|
993
|
-
# edit context menu
|
|
994
|
-
self.edit_context_menu = tk.Menu(self, tearoff=False)
|
|
995
|
-
self.edit_context_menu.add_command(label="Copy",
|
|
996
|
-
command=lambda: self.focus_get().event_generate("<<Copy>>"))
|
|
997
|
-
self.out_text.bind("<Button-3>", self.display_popup)
|
|
998
|
-
|
|
999
|
-
#########################################################
|
|
1000
|
-
# Progress Frame
|
|
1001
|
-
#
|
|
1002
|
-
# Create the elements of the progress frame
|
|
1003
|
-
progress_frame = ttk.Frame(right_frame, padding='0.1i')
|
|
1004
|
-
self.progress_label = ttk.Label(progress_frame, text="Progress:", justify=tk.LEFT)
|
|
1005
|
-
self.progress_var = tk.DoubleVar()
|
|
1006
|
-
self.progress = ttk.Progressbar(progress_frame, orient="horizontal", variable=self.progress_var, length=200,
|
|
1007
|
-
maximum=100)
|
|
1008
|
-
CreateToolTip(self.progress_label, 'Show tool operation progress')
|
|
1009
|
-
CreateToolTip(self.progress, 'Show tool operation progress')
|
|
1010
|
-
|
|
1011
|
-
# Define layout of the frame
|
|
1012
|
-
self.progress_label.grid(row=0, column=0, sticky=tk.E, padx=5)
|
|
1013
|
-
self.progress.grid(row=0, column=1, sticky=tk.E)
|
|
1014
|
-
progress_frame.grid(row=4, column=0, columnspan=2, sticky=tk.SE)
|
|
1015
|
-
|
|
1016
|
-
progress_frame.rowconfigure(4, weight=1)
|
|
1017
|
-
progress_frame.columnconfigure(0, weight=1)
|
|
1018
|
-
|
|
1019
|
-
#########################################################
|
|
1020
|
-
# Tool Selection
|
|
1021
|
-
#
|
|
1022
|
-
# Select the appropriate tool, if specified, otherwise the first tool
|
|
1023
|
-
self.tool_tree.focus(self.tool_name)
|
|
1024
|
-
self.tool_tree.selection_set(self.tool_name)
|
|
1025
|
-
self.tool_tree.event_generate("<<TreeviewSelect>>")
|
|
1026
|
-
|
|
1027
|
-
#########################################################
|
|
1028
|
-
# Menus
|
|
1029
|
-
menubar = tk.Menu(self)
|
|
1030
|
-
|
|
1031
|
-
self.file_menu = tk.Menu(menubar, tearoff=0)
|
|
1032
|
-
self.file_menu.add_command(label="Set Working Directory", command=self.set_directory)
|
|
1033
|
-
|
|
1034
|
-
if bt.get_verbose_mode():
|
|
1035
|
-
self.file_menu.add_command(label="Do Not Print Tool Output", command=self.update_verbose)
|
|
1036
|
-
else:
|
|
1037
|
-
self.file_menu.add_command(label="Print Tool Output", command=self.update_verbose)
|
|
1038
|
-
|
|
1039
|
-
self.file_menu.add_command(label="Set Num. Processors", command=self.set_procs)
|
|
1040
|
-
|
|
1041
|
-
self.file_menu.add_separator()
|
|
1042
|
-
self.file_menu.add_command(label="Exit", command=self.quit)
|
|
1043
|
-
menubar.add_cascade(label="File", menu=self.file_menu)
|
|
1044
|
-
|
|
1045
|
-
editmenu = tk.Menu(menubar, tearoff=0)
|
|
1046
|
-
editmenu.add_command(label="Cut", command=lambda: self.focus_get().event_generate("<<Cut>>"))
|
|
1047
|
-
editmenu.add_command(label="Copy", command=lambda: self.focus_get().event_generate("<<Copy>>"))
|
|
1048
|
-
editmenu.add_command(label="Paste", command=lambda: self.focus_get().event_generate("<<Paste>>"))
|
|
1049
|
-
menubar.add_cascade(label="Edit ", menu=editmenu)
|
|
1050
|
-
|
|
1051
|
-
helpmenu = tk.Menu(menubar, tearoff=0)
|
|
1052
|
-
helpmenu.add_command(label="About", command=self.about)
|
|
1053
|
-
helpmenu.add_command(label="License", command=self.license)
|
|
1054
|
-
menubar.add_cascade(label="Help ", menu=helpmenu)
|
|
1055
|
-
|
|
1056
|
-
self.master.config(menu=menubar)
|
|
1057
|
-
|
|
1058
|
-
def display_popup(self, event):
|
|
1059
|
-
self.edit_context_menu.post(event.x_root, event.y_root)
|
|
1060
|
-
|
|
1061
|
-
def update_verbose(self):
|
|
1062
|
-
if bt.get_verbose_mode():
|
|
1063
|
-
bt.set_verbose_mode(False)
|
|
1064
|
-
self.file_menu.entryconfig(1, label="Print Tool Output")
|
|
1065
|
-
else:
|
|
1066
|
-
bt.set_verbose_mode(True)
|
|
1067
|
-
self.file_menu.entryconfig(1, label="Do Not Print Tool Output")
|
|
1068
|
-
|
|
1069
|
-
def update_selected_bera_tool(self):
|
|
1070
|
-
selected_item = -1
|
|
1071
|
-
for toolbox in self.bera_tools['toolbox']:
|
|
1072
|
-
for item in toolbox['tools']:
|
|
1073
|
-
if item['name']:
|
|
1074
|
-
if item == self.tool_name: # update selected_item it tool found
|
|
1075
|
-
selected_item = len(self.tools_list) - 1
|
|
1076
|
-
|
|
1077
|
-
if selected_item == -1: # set self.tool_name as default tool
|
|
1078
|
-
selected_item = 0
|
|
1079
|
-
self.tool_name = self.tools_list[0]
|
|
1080
|
-
|
|
1081
|
-
def save_tool_parameter(self):
|
|
1082
|
-
data_path = Path(__file__).resolve().cwd().parent.parent.joinpath(r'.data')
|
|
1083
|
-
if not data_path.exists():
|
|
1084
|
-
data_path.mkdir()
|
|
1085
|
-
json_file = data_path.joinpath(data_path, 'saved_tool_parameters.json')
|
|
1086
|
-
|
|
1087
|
-
# Retrieve tool parameters from GUI
|
|
1088
|
-
args = self.get_widgets_arguments()
|
|
1089
|
-
|
|
1090
|
-
tool_params = {}
|
|
1091
|
-
if json_file.exists():
|
|
1092
|
-
with open(json_file, 'r') as open_file:
|
|
1093
|
-
data = json.load(open_file)
|
|
1094
|
-
if data:
|
|
1095
|
-
tool_params = data
|
|
1096
|
-
|
|
1097
|
-
with open(json_file, 'w') as new_file:
|
|
1098
|
-
tool_params[self.current_tool_api] = args
|
|
1099
|
-
json.dump(tool_params, new_file, indent=4)
|
|
1100
|
-
|
|
1101
|
-
def get_current_tool_parameters(self):
|
|
1102
|
-
tool_params = bt.get_bera_tool_parameters(self.tool_name)
|
|
1103
|
-
self.current_tool_api = tool_params['tool_api']
|
|
1104
|
-
return tool_params
|
|
1105
|
-
|
|
1106
|
-
# read selection when tool selected from treeview then call self.update_tool_help
|
|
1107
|
-
def tree_update_tool_help(self, event):
|
|
1108
|
-
cur_item = self.tool_tree.focus()
|
|
1109
|
-
self.tool_name = self.tool_tree.item(cur_item).get('text').replace(" ", "")
|
|
1110
|
-
self.update_tool_info()
|
|
1111
|
-
|
|
1112
|
-
# read selection when tool selected from search results then call self.update_tool_help
|
|
1113
|
-
def update_search_tool_info(self, event):
|
|
1114
|
-
selection = self.search_results_listbox.curselection()
|
|
1115
|
-
self.tool_name = self.search_results_listbox.get(selection[0])
|
|
1116
|
-
|
|
1117
|
-
self.update_tool_info()
|
|
1118
|
-
if self.search_tool_selected:
|
|
1119
|
-
print("Index {} selected".format(self.search_tool_selected[0]))
|
|
1120
|
-
|
|
1121
|
-
def update_tool_info(self):
|
|
1122
|
-
self.out_text.delete('1.0', tk.END)
|
|
1123
|
-
for widget in self.arg_scroll_frame.winfo_children():
|
|
1124
|
-
widget.destroy()
|
|
1125
|
-
|
|
1126
|
-
k = bt.get_bera_tool_info(self.tool_name)
|
|
1127
|
-
self.print_to_output(k)
|
|
1128
|
-
self.print_to_output('\n')
|
|
1129
|
-
|
|
1130
|
-
j = self.get_current_tool_parameters()
|
|
1131
|
-
|
|
1132
|
-
param_num = 0
|
|
1133
|
-
for p in j['parameters']:
|
|
1134
|
-
json_str = json.dumps(p, sort_keys=True, indent=2, separators=(',', ': '))
|
|
1135
|
-
pt = p['parameter_type']
|
|
1136
|
-
widget = None
|
|
1137
|
-
|
|
1138
|
-
if 'ExistingFileOrFloat' in pt:
|
|
1139
|
-
widget = FileOrFloat(json_str, self, self.arg_scroll_frame)
|
|
1140
|
-
widget.grid(row=param_num, column=0, sticky=tk.NSEW)
|
|
1141
|
-
param_num = param_num + 1
|
|
1142
|
-
elif 'ExistingFile' in pt or 'NewFile' in pt or 'Directory' in pt:
|
|
1143
|
-
widget = FileSelector(json_str, self, self.arg_scroll_frame)
|
|
1144
|
-
widget.grid(row=param_num, column=0, sticky=tk.NSEW)
|
|
1145
|
-
param_num = param_num + 1
|
|
1146
|
-
elif 'FileList' in pt:
|
|
1147
|
-
widget = MultifileSelector(json_str, self, self.arg_scroll_frame)
|
|
1148
|
-
widget.grid(row=param_num, column=0, sticky=tk.W)
|
|
1149
|
-
param_num = param_num + 1
|
|
1150
|
-
elif 'OptionList' in pt:
|
|
1151
|
-
if 'data_type' in p.keys():
|
|
1152
|
-
if p['data_type'] == 'Boolean':
|
|
1153
|
-
widget = BooleanInput(json_str, self.arg_scroll_frame)
|
|
1154
|
-
widget.grid(row=param_num, column=0, sticky=tk.W)
|
|
1155
|
-
param_num = param_num + 1
|
|
1156
|
-
else:
|
|
1157
|
-
widget = OptionsInput(json_str, self.arg_scroll_frame)
|
|
1158
|
-
widget.grid(row=param_num, column=0, sticky=tk.W)
|
|
1159
|
-
param_num = param_num + 1
|
|
1160
|
-
elif ('Float' in pt or 'Integer' in pt or
|
|
1161
|
-
'Text' in pt or 'String' in pt or 'StringOrNumber' in pt or
|
|
1162
|
-
'StringList' in pt or 'VectorAttributeField' in pt):
|
|
1163
|
-
widget = DataInput(json_str, self.arg_scroll_frame)
|
|
1164
|
-
widget.grid(row=param_num, column=0, sticky=tk.NSEW)
|
|
1165
|
-
param_num = param_num + 1
|
|
1166
|
-
else:
|
|
1167
|
-
messagebox.showinfo("Error", "Unsupported parameter type: {}.".format(pt))
|
|
1168
|
-
|
|
1169
|
-
param_value = None
|
|
1170
|
-
if 'saved_value' in p.keys():
|
|
1171
|
-
param_value = p['saved_value']
|
|
1172
|
-
if param_value is None:
|
|
1173
|
-
param_value = p['default_value']
|
|
1174
|
-
if param_value is not None:
|
|
1175
|
-
if type(widget) is OptionsInput:
|
|
1176
|
-
widget.value = param_value
|
|
1177
|
-
elif widget:
|
|
1178
|
-
widget.value.set(param_value)
|
|
1179
|
-
else:
|
|
1180
|
-
print('No default value found: {}'.format(p['name']))
|
|
1181
|
-
|
|
1182
|
-
# hide optional widgets
|
|
1183
|
-
if widget:
|
|
1184
|
-
if widget.optional and hasattr(widget, 'label'):
|
|
1185
|
-
widget.label.config(foreground='blue')
|
|
1186
|
-
|
|
1187
|
-
if widget.optional and not bt.show_advanced:
|
|
1188
|
-
widget.grid_forget()
|
|
1189
|
-
|
|
1190
|
-
self.update_args_box()
|
|
1191
|
-
self.out_text.see("%d.%d" % (1, 0))
|
|
1192
|
-
|
|
1193
|
-
def update_toolbox_icon(self, event):
|
|
1194
|
-
cur_item = self.tool_tree.focus()
|
|
1195
|
-
dict_tool = self.tool_tree.item(cur_item) # retrieve the toolbox name
|
|
1196
|
-
self.toolbox_name = dict_tool.get('text').replace(" ", "") # delete the space between the icon and text
|
|
1197
|
-
self.toolbox_open = dict_tool.get('open') # retrieve whether the toolbox is open or not
|
|
1198
|
-
if self.toolbox_open: # set image accordingly
|
|
1199
|
-
self.tool_tree.item(self.toolbox_name, image=self.open_toolbox_icon)
|
|
1200
|
-
else:
|
|
1201
|
-
self.tool_tree.item(self.toolbox_name, image=self.closed_toolbox_icon)
|
|
1202
|
-
|
|
1203
|
-
def update_search(self, event):
|
|
1204
|
-
self.search_list = []
|
|
1205
|
-
self.search_string = self.search_text.get().lower()
|
|
1206
|
-
self.search_results_listbox.delete(0, 'end') # empty the search results
|
|
1207
|
-
num_results = 0
|
|
1208
|
-
for tool in self.tools_list: # search tool names
|
|
1209
|
-
tool_lower = tool.lower()
|
|
1210
|
-
# search string found within tool name
|
|
1211
|
-
if tool_lower.find(self.search_string) != (-1):
|
|
1212
|
-
num_results = num_results + 1
|
|
1213
|
-
# tool added to listbox and to search results string
|
|
1214
|
-
self.search_results_listbox.insert(num_results, tool)
|
|
1215
|
-
self.search_list.append(tool)
|
|
1216
|
-
index = 0
|
|
1217
|
-
|
|
1218
|
-
# update label to show tools found
|
|
1219
|
-
self.search_frame.config(text="{} Tools Found".format(len(self.search_list)))
|
|
1220
|
-
|
|
1221
|
-
def tool_help_button(self):
|
|
1222
|
-
# open the user manual section for the current tool
|
|
1223
|
-
webbrowser.open_new_tab(self.get_current_tool_parameters()['tech_link'])
|
|
1224
|
-
|
|
1225
|
-
def add_tools_to_treeview(self):
|
|
1226
|
-
# Add toolboxes and tools to treeview
|
|
1227
|
-
index = 0
|
|
1228
|
-
for toolbox in self.lower_toolboxes:
|
|
1229
|
-
if toolbox.find('/') != (-1): # toolboxes
|
|
1230
|
-
self.tool_tree.insert(toolbox[:toolbox.find('/')], 0, text=" " + toolbox[toolbox.find('/') + 1:],
|
|
1231
|
-
iid=toolbox[toolbox.find('/') + 1:], tags='toolbox',
|
|
1232
|
-
image=self.closed_toolbox_icon)
|
|
1233
|
-
for tool in self.sorted_tools[index]: # add tools within toolbox
|
|
1234
|
-
self.tool_tree.insert(toolbox[toolbox.find('/') + 1:], 'end', text=" " + tool,
|
|
1235
|
-
tags='tool', iid=tool, image=self.tool_icon)
|
|
1236
|
-
else: # sub toolboxes
|
|
1237
|
-
self.tool_tree.insert('', 'end', text=" " + toolbox, iid=toolbox, tags='toolbox',
|
|
1238
|
-
image=self.closed_toolbox_icon)
|
|
1239
|
-
for tool in self.sorted_tools[index]: # add tools within sub toolbox
|
|
1240
|
-
self.tool_tree.insert(toolbox, 'end', text=" " + tool, iid=tool, tags='tool', image=self.tool_icon)
|
|
1241
|
-
index = index + 1
|
|
1242
|
-
|
|
1243
|
-
def add_recent_tool_to_search(self):
|
|
1244
|
-
if bt.recent_tool:
|
|
1245
|
-
self.search_results_listbox.delete(0, 'end')
|
|
1246
|
-
self.search_list.append(bt.recent_tool)
|
|
1247
|
-
self.search_results_listbox.insert(END, bt.recent_tool)
|
|
1248
|
-
|
|
1249
|
-
self.search_frame.config(text='Recent used tool')
|
|
1250
|
-
self.tool_name = self.search_results_listbox.get(0)
|
|
1251
|
-
|
|
1252
|
-
#########################################################
|
|
1253
|
-
# Functions (original)
|
|
1254
|
-
def about(self):
|
|
1255
|
-
self.out_text.delete('1.0', tk.END)
|
|
1256
|
-
self.print_to_output(bt.about())
|
|
1257
|
-
|
|
1258
|
-
def license(self):
|
|
1259
|
-
self.out_text.delete('1.0', tk.END)
|
|
1260
|
-
self.print_to_output(bt.license())
|
|
1261
|
-
|
|
1262
|
-
def set_directory(self):
|
|
1263
|
-
try:
|
|
1264
|
-
self.working_dir = filedialog.askdirectory(initialdir=self.working_dir)
|
|
1265
|
-
bt.set_working_dir(self.working_dir)
|
|
1266
|
-
except:
|
|
1267
|
-
messagebox.showinfo("Warning", "Could not set the working directory.")
|
|
1268
|
-
|
|
1269
|
-
def set_procs(self):
|
|
1270
|
-
try:
|
|
1271
|
-
max_cpu_cores = bt.get_max_cpu_cores()
|
|
1272
|
-
max_procs = askinteger(
|
|
1273
|
-
title="Max CPU cores used",
|
|
1274
|
-
prompt="Set the number of processors to be used (maximum: {}, -1: all):".format(max_cpu_cores),
|
|
1275
|
-
parent=self, initialvalue=bt.get_max_procs(), minvalue=-1, maxvalue=max_cpu_cores)
|
|
1276
|
-
if max_procs:
|
|
1277
|
-
self.update_procs(max_procs)
|
|
1278
|
-
self.mpc_scale.set(max_procs)
|
|
1279
|
-
except:
|
|
1280
|
-
messagebox.showinfo("Warning", "Could not set the number of processors.")
|
|
1281
|
-
|
|
1282
|
-
def update_procs(self, value):
|
|
1283
|
-
self.__max_procs = int(value)
|
|
1284
|
-
bt.set_max_procs(self.__max_procs)
|
|
1285
|
-
|
|
1286
|
-
def get_widgets_arguments(self):
|
|
1287
|
-
args = {}
|
|
1288
|
-
param_missing = False
|
|
1289
|
-
for widget in self.arg_scroll_frame.winfo_children():
|
|
1290
|
-
v = widget.get_value()
|
|
1291
|
-
if v and len(v) == 2:
|
|
1292
|
-
args[v[0]] = v[1]
|
|
1293
|
-
else:
|
|
1294
|
-
self.print_line_to_output('[Missing argument]:'+widget.name+": parameter not specified.", 'missing')
|
|
1295
|
-
param_missing = True
|
|
1296
|
-
|
|
1297
|
-
if param_missing:
|
|
1298
|
-
args = None
|
|
1299
|
-
|
|
1300
|
-
return args
|
|
1301
|
-
|
|
1302
|
-
def reset_tool(self):
|
|
1303
|
-
for widget in self.arg_scroll_frame.winfo_children():
|
|
1304
|
-
args = bt.get_bera_tool_parameters(self.tool_name)
|
|
1305
|
-
for param in args['parameters']:
|
|
1306
|
-
default_value = param['default_value']
|
|
1307
|
-
if widget.flag == param['flag']:
|
|
1308
|
-
if type(widget) is OptionsInput:
|
|
1309
|
-
widget.value = default_value
|
|
1310
|
-
else:
|
|
1311
|
-
widget.value.set(default_value)
|
|
1312
|
-
|
|
1313
|
-
def start_run_tool_thread(self):
|
|
1314
|
-
t = threading.Thread(target=self.run_tool, args=())
|
|
1315
|
-
t.daemon = True
|
|
1316
|
-
t.start()
|
|
1317
|
-
|
|
1318
|
-
def run_tool(self):
|
|
1319
|
-
bt.set_working_dir(self.working_dir)
|
|
1320
|
-
|
|
1321
|
-
args = self.get_widgets_arguments()
|
|
1322
|
-
if not args:
|
|
1323
|
-
print('Please check the parameters.')
|
|
1324
|
-
return
|
|
1325
|
-
|
|
1326
|
-
self.print_line_to_output("")
|
|
1327
|
-
self.print_line_to_output('Staring tool {} ...'.format(self.tool_name))
|
|
1328
|
-
self.print_line_to_output(bt.ascii_art)
|
|
1329
|
-
self.print_line_to_output("Tool arguments:")
|
|
1330
|
-
self.print_line_to_output(json.dumps(args, indent=4))
|
|
1331
|
-
self.print_line_to_output("")
|
|
1332
|
-
self.save_tool_parameter()
|
|
1333
|
-
bt.recent_tool = self.tool_name
|
|
1334
|
-
bt.save_recent_tool()
|
|
1335
|
-
|
|
1336
|
-
# Run the tool and check the return value for an error
|
|
1337
|
-
for key in args.keys():
|
|
1338
|
-
if type(args[key]) is not str:
|
|
1339
|
-
args[key] = str(args[key])
|
|
1340
|
-
|
|
1341
|
-
# disable button
|
|
1342
|
-
# self.run_button.config(text='Running', state='disabled')
|
|
1343
|
-
if bt.run_tool_bt(self.current_tool_api, args, self.custom_callback) == 1:
|
|
1344
|
-
print("Error running {}".format(self.tool_name))
|
|
1345
|
-
# restore Run button
|
|
1346
|
-
# self.run_button.config(text='Run', state='enable')
|
|
1347
|
-
else:
|
|
1348
|
-
self.progress_var.set(0)
|
|
1349
|
-
self.progress_label['text'] = "Progress:"
|
|
1350
|
-
self.progress.update_idletasks()
|
|
1351
|
-
# restore Run button
|
|
1352
|
-
# self.run_button.config(text='Run', state='enable')
|
|
1353
|
-
|
|
1354
|
-
return
|
|
1355
|
-
|
|
1356
|
-
def print_to_output(self, value):
|
|
1357
|
-
self.out_text.insert(tk.END, value)
|
|
1358
|
-
self.out_text.see(tk.END)
|
|
1359
|
-
|
|
1360
|
-
def print_line_to_output(self, value, tag=None):
|
|
1361
|
-
self.out_text.insert(tk.END, value + "\n", tag)
|
|
1362
|
-
self.out_text.see(tk.END)
|
|
1363
|
-
|
|
1364
|
-
def cancel_operation(self):
|
|
1365
|
-
bt.cancel_op = True
|
|
1366
|
-
self.print_line_to_output('------------------------------------')
|
|
1367
|
-
self.print_line_to_output("Tool operation cancelling...")
|
|
1368
|
-
self.progress.update_idletasks()
|
|
1369
|
-
|
|
1370
|
-
def show_advanced(self):
|
|
1371
|
-
if not self.show_advanced_button or len(self.arg_scroll_frame.winfo_children()) <= 0:
|
|
1372
|
-
return
|
|
1373
|
-
|
|
1374
|
-
if bt.show_advanced:
|
|
1375
|
-
bt.show_advanced = False
|
|
1376
|
-
else:
|
|
1377
|
-
bt.show_advanced = True
|
|
1378
|
-
|
|
1379
|
-
if bt.show_advanced:
|
|
1380
|
-
self.show_advanced_button.config(text="Hide Advanced Options")
|
|
1381
|
-
self.save_tool_parameter()
|
|
1382
|
-
self.update_tool_info()
|
|
1383
|
-
else:
|
|
1384
|
-
self.show_advanced_button.config(text="Show Advanced Options")
|
|
1385
|
-
for widget in self.arg_scroll_frame.winfo_children():
|
|
1386
|
-
if widget.optional:
|
|
1387
|
-
widget.grid_forget()
|
|
1388
|
-
|
|
1389
|
-
def view_code(self):
|
|
1390
|
-
webbrowser.open_new_tab(self.get_current_tool_parameters()['tech_link'])
|
|
1391
|
-
|
|
1392
|
-
def update_args_box(self):
|
|
1393
|
-
s = ""
|
|
1394
|
-
self.current_tool_lbl['text'] = "Current Tool: {}".format(
|
|
1395
|
-
self.tool_name)
|
|
1396
|
-
|
|
1397
|
-
# self.spacer['width'] = width=(35-len(self.tool_name))
|
|
1398
|
-
# for item in bt.tool_help(self.tool_name).splitlines():
|
|
1399
|
-
for item in bt.get_bera_tool_info(self.tool_name).splitlines():
|
|
1400
|
-
if item.startswith("-"):
|
|
1401
|
-
k = item.split(" ")
|
|
1402
|
-
if "--" in k[1]:
|
|
1403
|
-
value = k[1].replace(",", "")
|
|
1404
|
-
else:
|
|
1405
|
-
value = k[0].replace(",", "")
|
|
1406
|
-
|
|
1407
|
-
if "flag" in item.lower():
|
|
1408
|
-
s = s + value + " "
|
|
1409
|
-
else:
|
|
1410
|
-
if "file" in item.lower():
|
|
1411
|
-
s = s + value + "='{}' "
|
|
1412
|
-
else:
|
|
1413
|
-
s = s + value + "={} "
|
|
1414
|
-
|
|
1415
|
-
# self.args_value.set(s.strip())
|
|
1416
|
-
|
|
1417
|
-
def custom_callback(self, value):
|
|
1418
|
-
"""
|
|
1419
|
-
A custom callback for dealing with tool output.
|
|
1420
|
-
"""
|
|
1421
|
-
value = str(value)
|
|
1422
|
-
|
|
1423
|
-
if "%" in value:
|
|
1424
|
-
try:
|
|
1425
|
-
str_progress = extract_string_from_printout(value, '%')
|
|
1426
|
-
value = value.replace(str_progress, '').strip() # remove progress string
|
|
1427
|
-
progress = float(str_progress.replace("%", "").strip())
|
|
1428
|
-
self.progress_var.set(int(progress))
|
|
1429
|
-
except ValueError as e:
|
|
1430
|
-
print("custom_callback: Problem converting parsed data into number: ", e)
|
|
1431
|
-
except Exception as e:
|
|
1432
|
-
print(e)
|
|
1433
|
-
elif 'PROGRESS_LABEL' in value:
|
|
1434
|
-
str_label = extract_string_from_printout(value, 'PROGRESS_LABEL')
|
|
1435
|
-
value = value.replace(str_label, '').strip() # remove progress string
|
|
1436
|
-
value = value.replace('"', '')
|
|
1437
|
-
str_label = str_label.replace("PROGRESS_LABEL", "").strip()
|
|
1438
|
-
self.progress_label['text'] = str_label
|
|
1439
|
-
|
|
1440
|
-
if value != '':
|
|
1441
|
-
self.print_line_to_output(value)
|
|
1442
|
-
|
|
1443
|
-
self.update() # this is needed for cancelling and updating the progress bar
|
|
1444
|
-
|
|
1445
|
-
def select_all(self, event):
|
|
1446
|
-
self.out_text.tag_add(tk.SEL, "1.0", tk.END)
|
|
1447
|
-
self.out_text.mark_set(tk.INSERT, "1.0")
|
|
1448
|
-
self.out_text.see(tk.INSERT)
|
|
1449
|
-
return 'break'
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
# handle debugging exit signal and kill sub-process
|
|
1453
|
-
def handler(event):
|
|
1454
|
-
# root.destroy()
|
|
1455
|
-
print('Caught ^C')
|
|
1456
|
-
bt.cancel_op = True
|
|
1457
|
-
sleep(3000)
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
def check(btr):
|
|
1461
|
-
btr.root.after(1000, check) # time in ms.
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
def main_runner():
|
|
1465
|
-
tool_name = None
|
|
1466
|
-
if len(sys.argv) > 1:
|
|
1467
|
-
tool_name = str(sys.argv[1])
|
|
1468
|
-
btr = MainGui(tool_name)
|
|
1469
|
-
|
|
1470
|
-
signal.signal(signal.SIGINT, lambda x, y: print('terminal ^C') or handler(None))
|
|
1471
|
-
btr.bind_all('<Control-c>', handler)
|
|
1472
|
-
|
|
1473
|
-
ico = Image.open(r'img\BERALogo.png')
|
|
1474
|
-
photo = ImageTk.PhotoImage(ico)
|
|
1475
|
-
btr.root().wm_iconphoto(False, photo)
|
|
1476
|
-
btr.root().eval('tk::PlaceWindow . center')
|
|
1477
|
-
btr.mainloop()
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
if __name__ == '__main__':
|
|
1481
|
-
main_runner()
|