BERATools 0.2.3__py3-none-any.whl → 0.2.4__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 +8 -3
- beratools/core/{algo_footprint_rel.py → algo_canopy_footprint_exp.py} +176 -139
- beratools/core/algo_centerline.py +61 -77
- beratools/core/algo_common.py +48 -57
- beratools/core/algo_cost.py +18 -25
- beratools/core/algo_dijkstra.py +37 -45
- beratools/core/algo_line_grouping.py +100 -100
- beratools/core/algo_merge_lines.py +40 -8
- beratools/core/algo_split_with_lines.py +289 -304
- beratools/core/algo_vertex_optimization.py +25 -46
- beratools/core/canopy_threshold_relative.py +755 -0
- beratools/core/constants.py +8 -9
- beratools/{tools → core}/line_footprint_functions.py +411 -258
- beratools/core/logger.py +18 -2
- beratools/core/tool_base.py +17 -75
- beratools/gui/assets/BERALogo.ico +0 -0
- beratools/gui/assets/BERA_Splash.gif +0 -0
- beratools/gui/assets/BERA_WizardImage.png +0 -0
- beratools/gui/assets/beratools.json +475 -2171
- beratools/gui/bt_data.py +585 -234
- beratools/gui/bt_gui_main.py +129 -91
- beratools/gui/main.py +4 -7
- beratools/gui/tool_widgets.py +530 -354
- beratools/tools/__init__.py +0 -7
- beratools/tools/{line_footprint_absolute.py → canopy_footprint_absolute.py} +81 -56
- beratools/tools/canopy_footprint_exp.py +113 -0
- beratools/tools/centerline.py +30 -37
- beratools/tools/check_seed_line.py +127 -0
- beratools/tools/common.py +65 -586
- beratools/tools/{line_footprint_fixed.py → ground_footprint.py} +140 -117
- beratools/tools/line_footprint_relative.py +64 -35
- beratools/tools/tool_template.py +48 -40
- beratools/tools/vertex_optimization.py +20 -34
- beratools/utility/env_checks.py +53 -0
- beratools/utility/spatial_common.py +210 -0
- beratools/utility/tool_args.py +138 -0
- beratools-0.2.4.dist-info/METADATA +134 -0
- beratools-0.2.4.dist-info/RECORD +50 -0
- {beratools-0.2.3.dist-info → beratools-0.2.4.dist-info}/WHEEL +1 -1
- beratools-0.2.4.dist-info/entry_points.txt +3 -0
- beratools-0.2.4.dist-info/licenses/LICENSE +674 -0
- beratools/core/algo_tiler.py +0 -428
- beratools/gui/__init__.py +0 -11
- beratools/gui/batch_processing_dlg.py +0 -513
- beratools/gui/map_window.py +0 -162
- beratools/tools/Beratools_r_script.r +0 -1120
- beratools/tools/Ht_metrics.py +0 -116
- beratools/tools/batch_processing.py +0 -136
- beratools/tools/canopy_threshold_relative.py +0 -672
- beratools/tools/canopycostraster.py +0 -222
- beratools/tools/fl_regen_csf.py +0 -428
- beratools/tools/forest_line_attributes.py +0 -408
- beratools/tools/line_grouping.py +0 -45
- beratools/tools/ln_relative_metrics.py +0 -615
- beratools/tools/r_cal_lpi_elai.r +0 -25
- beratools/tools/r_generate_pd_focalraster.r +0 -101
- beratools/tools/r_interface.py +0 -80
- beratools/tools/r_point_density.r +0 -9
- beratools/tools/rpy_chm2trees.py +0 -86
- beratools/tools/rpy_dsm_chm_by.py +0 -81
- beratools/tools/rpy_dtm_by.py +0 -63
- beratools/tools/rpy_find_cellsize.py +0 -43
- beratools/tools/rpy_gnd_csf.py +0 -74
- beratools/tools/rpy_hummock_hollow.py +0 -85
- beratools/tools/rpy_hummock_hollow_raster.py +0 -71
- beratools/tools/rpy_las_info.py +0 -51
- beratools/tools/rpy_laz2las.py +0 -40
- beratools/tools/rpy_lpi_elai_lascat.py +0 -466
- beratools/tools/rpy_normalized_lidar_by.py +0 -56
- beratools/tools/rpy_percent_above_dbh.py +0 -80
- beratools/tools/rpy_points2trees.py +0 -88
- beratools/tools/rpy_vegcoverage.py +0 -94
- beratools/tools/tiler.py +0 -48
- beratools/tools/zonal_threshold.py +0 -144
- beratools-0.2.3.dist-info/METADATA +0 -108
- beratools-0.2.3.dist-info/RECORD +0 -74
- beratools-0.2.3.dist-info/entry_points.txt +0 -2
- beratools-0.2.3.dist-info/licenses/LICENSE +0 -22
beratools/gui/bt_gui_main.py
CHANGED
|
@@ -12,44 +12,38 @@ Description:
|
|
|
12
12
|
|
|
13
13
|
The purpose of this script is to provide main GUI functions.
|
|
14
14
|
"""
|
|
15
|
+
|
|
15
16
|
import json
|
|
16
17
|
import os
|
|
18
|
+
import shlex
|
|
17
19
|
import sys
|
|
18
20
|
import webbrowser
|
|
19
21
|
from pathlib import Path
|
|
20
|
-
from re import compile
|
|
21
|
-
|
|
22
|
-
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
23
22
|
|
|
24
23
|
import beratools.core.constants as bt_const
|
|
25
|
-
import beratools.tools.common as bt_common
|
|
26
24
|
from beratools.gui import bt_data
|
|
25
|
+
from beratools.utility import env_checks
|
|
27
26
|
from beratools.gui.tool_widgets import ToolWidgets
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
progress_re = compile("Total complete: (\d+)%")
|
|
31
|
-
bt = bt_data.BTData()
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def simple_percent_parser(output):
|
|
35
|
-
"""
|
|
36
|
-
Match lines using the progress_re regex.
|
|
28
|
+
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
37
29
|
|
|
38
|
-
|
|
39
|
-
"""
|
|
40
|
-
m = progress_re.search(output)
|
|
41
|
-
if m:
|
|
42
|
-
pc_complete = m.group(1)
|
|
43
|
-
return int(pc_complete)
|
|
30
|
+
bt = bt_data.BTData()
|
|
44
31
|
|
|
32
|
+
def extract_string_from_printout(str_print, str_extract):
|
|
33
|
+
str_array = shlex.split(str_print) # keep string in double quotes
|
|
34
|
+
str_array_enum = enumerate(str_array)
|
|
35
|
+
index = 0
|
|
36
|
+
for item in str_array_enum:
|
|
37
|
+
if str_extract in item[1]:
|
|
38
|
+
index = item[0]
|
|
39
|
+
break
|
|
40
|
+
str_out = str_array[index]
|
|
41
|
+
return str_out.strip()
|
|
45
42
|
|
|
46
43
|
class _SearchProxyModel(QtCore.QSortFilterProxyModel):
|
|
47
|
-
|
|
48
44
|
def setFilterRegExp(self, pattern):
|
|
49
45
|
if isinstance(pattern, str):
|
|
50
|
-
pattern = QtCore.QRegExp(
|
|
51
|
-
pattern, QtCore.Qt.CaseInsensitive, QtCore.QRegExp.FixedString
|
|
52
|
-
)
|
|
46
|
+
pattern = QtCore.QRegExp(pattern, QtCore.Qt.CaseInsensitive, QtCore.QRegExp.FixedString)
|
|
53
47
|
super(_SearchProxyModel, self).setFilterRegExp(pattern)
|
|
54
48
|
|
|
55
49
|
def _accept_index(self, idx):
|
|
@@ -77,7 +71,7 @@ class BTTreeView(QtWidgets.QWidget):
|
|
|
77
71
|
|
|
78
72
|
# controls
|
|
79
73
|
self.tool_search = QtWidgets.QLineEdit()
|
|
80
|
-
self.tool_search.setPlaceholderText(
|
|
74
|
+
self.tool_search.setPlaceholderText("Search...")
|
|
81
75
|
|
|
82
76
|
self.tags_model = _SearchProxyModel()
|
|
83
77
|
self.tree_model = QtGui.QStandardItemModel()
|
|
@@ -110,7 +104,7 @@ class BTTreeView(QtWidgets.QWidget):
|
|
|
110
104
|
self.tree_view.setFirstColumnSpanned(0, self.tree_view.rootIndex(), True)
|
|
111
105
|
self.tree_view.setUniformRowHeights(True)
|
|
112
106
|
|
|
113
|
-
self.tree_model.setHorizontalHeaderLabels([
|
|
107
|
+
self.tree_model.setHorizontalHeaderLabels(["Tools"])
|
|
114
108
|
self.tree_sel_model = self.tree_view.selectionModel()
|
|
115
109
|
self.tree_sel_model.selectionChanged.connect(self.tree_view_selection_changed)
|
|
116
110
|
|
|
@@ -146,9 +140,7 @@ class BTTreeView(QtWidgets.QWidget):
|
|
|
146
140
|
QtGui.QIcon(os.path.join(bt_const.ASSETS_PATH, "close.gif")), toolbox
|
|
147
141
|
)
|
|
148
142
|
for j, tool in enumerate(sorted_tools[i]):
|
|
149
|
-
child = QtGui.QStandardItem(
|
|
150
|
-
QtGui.QIcon(os.path.join(bt_const.ASSETS_PATH, "tool.gif")), tool
|
|
151
|
-
)
|
|
143
|
+
child = QtGui.QStandardItem(QtGui.QIcon(os.path.join(bt_const.ASSETS_PATH, "tool.gif")), tool)
|
|
152
144
|
if i == 0 and j == 0:
|
|
153
145
|
first_child = child
|
|
154
146
|
|
|
@@ -178,21 +170,19 @@ class BTTreeView(QtWidgets.QWidget):
|
|
|
178
170
|
return
|
|
179
171
|
|
|
180
172
|
if item.hasChildren():
|
|
181
|
-
item.setIcon(QtGui.QIcon(os.path.join(bt_const.ASSETS_PATH,
|
|
173
|
+
item.setIcon(QtGui.QIcon(os.path.join(bt_const.ASSETS_PATH, "open.gif")))
|
|
182
174
|
|
|
183
175
|
def tree_item_collapsed(self, index):
|
|
184
176
|
source_index = self.tags_model.mapToSource(index)
|
|
185
177
|
item = self.tree_model.itemFromIndex(source_index)
|
|
186
178
|
if not item:
|
|
187
179
|
return
|
|
188
|
-
|
|
180
|
+
|
|
189
181
|
if item.hasChildren():
|
|
190
|
-
item.setIcon(QtGui.QIcon(os.path.join(bt_const.ASSETS_PATH,
|
|
182
|
+
item.setIcon(QtGui.QIcon(os.path.join(bt_const.ASSETS_PATH, "close.gif")))
|
|
191
183
|
|
|
192
184
|
def get_tool_index(self, tool_name):
|
|
193
|
-
item = self.tree_model.findItems(
|
|
194
|
-
tool_name, QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive
|
|
195
|
-
)
|
|
185
|
+
item = self.tree_model.findItems(tool_name, QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive)
|
|
196
186
|
if len(item) > 0:
|
|
197
187
|
item = item[0]
|
|
198
188
|
|
|
@@ -201,13 +191,9 @@ class BTTreeView(QtWidgets.QWidget):
|
|
|
201
191
|
|
|
202
192
|
def select_tool_by_index(self, index):
|
|
203
193
|
proxy_index = self.tags_model.mapFromSource(index)
|
|
204
|
-
self.tree_sel_model.select(
|
|
205
|
-
proxy_index, QtCore.QItemSelectionModel.ClearAndSelect
|
|
206
|
-
)
|
|
194
|
+
self.tree_sel_model.select(proxy_index, QtCore.QItemSelectionModel.ClearAndSelect)
|
|
207
195
|
self.tree_view.expand(proxy_index.parent())
|
|
208
|
-
self.tree_sel_model.setCurrentIndex(
|
|
209
|
-
proxy_index, QtCore.QItemSelectionModel.Current
|
|
210
|
-
)
|
|
196
|
+
self.tree_sel_model.setCurrentIndex(proxy_index, QtCore.QItemSelectionModel.Current)
|
|
211
197
|
|
|
212
198
|
def select_tool_by_name(self, name):
|
|
213
199
|
index = self.get_tool_index(name)
|
|
@@ -276,15 +262,15 @@ class BTSlider(QtWidgets.QWidget):
|
|
|
276
262
|
self.slider.sliderMoved.connect(self.slider_moved)
|
|
277
263
|
|
|
278
264
|
def slider_moved(self, value):
|
|
279
|
-
bt.
|
|
280
|
-
QtWidgets.QToolTip.showText(QtGui.QCursor.pos(), f
|
|
265
|
+
bt.set_selected_cpu_cores(value)
|
|
266
|
+
QtWidgets.QToolTip.showText(QtGui.QCursor.pos(), f"{value}")
|
|
281
267
|
self.label.setText(self.generate_label_text())
|
|
282
268
|
|
|
283
269
|
def generate_label_text(self, value=None):
|
|
284
270
|
if not value:
|
|
285
271
|
value = self.slider.value()
|
|
286
272
|
|
|
287
|
-
return f
|
|
273
|
+
return f"Use CPU Cores: {value:3d}"
|
|
288
274
|
|
|
289
275
|
|
|
290
276
|
class BTListView(QtWidgets.QWidget):
|
|
@@ -303,8 +289,8 @@ class BTListView(QtWidgets.QWidget):
|
|
|
303
289
|
btn_clear = QtWidgets.QPushButton()
|
|
304
290
|
btn_delete.setIcon(delete_icon)
|
|
305
291
|
btn_clear.setIcon(clear_icon)
|
|
306
|
-
btn_delete.setToolTip(
|
|
307
|
-
btn_clear.setToolTip(
|
|
292
|
+
btn_delete.setToolTip("Delete selected tool history")
|
|
293
|
+
btn_clear.setToolTip("clear all tool history")
|
|
308
294
|
btn_delete.setFixedWidth(40)
|
|
309
295
|
btn_clear.setFixedWidth(40)
|
|
310
296
|
|
|
@@ -363,11 +349,11 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
363
349
|
super().__init__()
|
|
364
350
|
|
|
365
351
|
self.script_dir = os.path.dirname(os.path.realpath(__file__))
|
|
366
|
-
self.title =
|
|
352
|
+
self.title = "BERA Tools"
|
|
367
353
|
self.setWindowTitle(self.title)
|
|
368
354
|
self.working_dir = bt.work_dir
|
|
369
355
|
self.tool_api = None
|
|
370
|
-
self.tool_name =
|
|
356
|
+
self.tool_name = "Centerline"
|
|
371
357
|
self.recent_tool = bt.recent_tool
|
|
372
358
|
if self.recent_tool:
|
|
373
359
|
self.tool_name = self.recent_tool
|
|
@@ -396,7 +382,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
396
382
|
|
|
397
383
|
# group box for tree view
|
|
398
384
|
tree_box = QtWidgets.QGroupBox()
|
|
399
|
-
tree_box.setTitle(
|
|
385
|
+
tree_box.setTitle("Tools available")
|
|
400
386
|
tree_layout = QtWidgets.QVBoxLayout()
|
|
401
387
|
tree_layout.addWidget(self.tree_view)
|
|
402
388
|
tree_box.setLayout(tree_layout)
|
|
@@ -410,7 +396,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
410
396
|
tool_history_box = QtWidgets.QGroupBox()
|
|
411
397
|
tool_history_layout = QtWidgets.QVBoxLayout()
|
|
412
398
|
tool_history_layout.addWidget(self.tool_history)
|
|
413
|
-
tool_history_box.setTitle(
|
|
399
|
+
tool_history_box.setTitle("Tool history")
|
|
414
400
|
tool_history_box.setLayout(tool_history_layout)
|
|
415
401
|
|
|
416
402
|
# left layout
|
|
@@ -422,35 +408,35 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
422
408
|
self.left_layout.addWidget(tool_history_box)
|
|
423
409
|
|
|
424
410
|
# top buttons
|
|
425
|
-
label = QtWidgets.QLabel(f
|
|
426
|
-
label.setFont(QtGui.QFont(
|
|
427
|
-
self.btn_advanced = QtWidgets.QPushButton(
|
|
411
|
+
label = QtWidgets.QLabel(f"{self.tool_name}")
|
|
412
|
+
label.setFont(QtGui.QFont("Consolas", 14))
|
|
413
|
+
self.btn_advanced = QtWidgets.QPushButton("Show Advanced Options")
|
|
428
414
|
self.btn_advanced.setFixedWidth(180)
|
|
429
|
-
btn_help = QtWidgets.QPushButton(
|
|
430
|
-
|
|
431
|
-
btn_help.setFixedWidth(250)
|
|
432
|
-
btn_code.setFixedWidth(100)
|
|
415
|
+
btn_help = QtWidgets.QPushButton("help")
|
|
416
|
+
btn_help.setFixedWidth(100)
|
|
433
417
|
|
|
434
418
|
self.btn_layout_top = QtWidgets.QHBoxLayout()
|
|
435
419
|
self.btn_layout_top.setAlignment(QtCore.Qt.AlignRight)
|
|
436
420
|
self.btn_layout_top.addWidget(label)
|
|
437
421
|
self.btn_layout_top.addStretch(1)
|
|
438
422
|
self.btn_layout_top.addWidget(self.btn_advanced)
|
|
439
|
-
self.btn_layout_top.addWidget(
|
|
423
|
+
self.btn_layout_top.addWidget(btn_help)
|
|
440
424
|
|
|
441
425
|
# ToolWidgets
|
|
442
426
|
tool_args = bt.get_bera_tool_args(self.tool_name)
|
|
443
427
|
self.tool_widget = ToolWidgets(self.recent_tool, tool_args, bt.show_advanced)
|
|
444
428
|
|
|
445
429
|
# bottom buttons
|
|
446
|
-
slider = BTSlider(bt.
|
|
447
|
-
btn_default_args = QtWidgets.QPushButton(
|
|
448
|
-
self.btn_run = QtWidgets.QPushButton(
|
|
449
|
-
btn_cancel = QtWidgets.QPushButton(
|
|
430
|
+
slider = BTSlider(bt.selected_cpu_cores, bt.max_cpu_cores)
|
|
431
|
+
btn_default_args = QtWidgets.QPushButton("Load Default Arguments")
|
|
432
|
+
self.btn_run = QtWidgets.QPushButton("Run")
|
|
433
|
+
btn_cancel = QtWidgets.QPushButton("Cancel")
|
|
434
|
+
btn_exit = QtWidgets.QPushButton("Exit")
|
|
450
435
|
btn_default_args.setFixedWidth(150)
|
|
451
436
|
slider.setFixedWidth(250)
|
|
452
437
|
self.btn_run.setFixedWidth(120)
|
|
453
438
|
btn_cancel.setFixedWidth(120)
|
|
439
|
+
btn_exit.setFixedWidth(120)
|
|
454
440
|
|
|
455
441
|
btn_layout_bottom = QtWidgets.QHBoxLayout()
|
|
456
442
|
btn_layout_bottom.setAlignment(QtCore.Qt.AlignRight)
|
|
@@ -459,17 +445,18 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
459
445
|
btn_layout_bottom.addWidget(slider)
|
|
460
446
|
btn_layout_bottom.addWidget(self.btn_run)
|
|
461
447
|
btn_layout_bottom.addWidget(btn_cancel)
|
|
448
|
+
btn_layout_bottom.addWidget(btn_exit)
|
|
462
449
|
|
|
463
450
|
self.top_right_layout = QtWidgets.QVBoxLayout()
|
|
464
451
|
self.top_right_layout.addLayout(self.btn_layout_top)
|
|
465
452
|
self.top_right_layout.addWidget(self.tool_widget)
|
|
466
453
|
self.top_right_layout.addLayout(btn_layout_bottom)
|
|
467
|
-
tool_widget_grp = QtWidgets.QGroupBox(
|
|
454
|
+
tool_widget_grp = QtWidgets.QGroupBox("Tool")
|
|
468
455
|
tool_widget_grp.setLayout(self.top_right_layout)
|
|
469
456
|
|
|
470
457
|
# Text widget
|
|
471
458
|
self.text_edit = QtWidgets.QPlainTextEdit()
|
|
472
|
-
self.text_edit.setFont(QtGui.QFont(
|
|
459
|
+
self.text_edit.setFont(QtGui.QFont("Consolas", 9))
|
|
473
460
|
self.text_edit.setReadOnly(True)
|
|
474
461
|
self.print_about()
|
|
475
462
|
|
|
@@ -494,15 +481,33 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
494
481
|
# signals and slots
|
|
495
482
|
self.btn_advanced.clicked.connect(self.show_advanced)
|
|
496
483
|
btn_help.clicked.connect(self.show_help)
|
|
497
|
-
btn_code.clicked.connect(self.view_code)
|
|
498
484
|
btn_default_args.clicked.connect(self.load_default_args)
|
|
499
485
|
self.btn_run.clicked.connect(self.start_process)
|
|
500
486
|
btn_cancel.clicked.connect(self.stop_process)
|
|
487
|
+
btn_exit.clicked.connect(self.close)
|
|
501
488
|
|
|
502
489
|
widget = QtWidgets.QWidget(self)
|
|
503
490
|
widget.setLayout(page_layout)
|
|
504
491
|
self.setCentralWidget(widget)
|
|
505
492
|
|
|
493
|
+
def closeEvent(self, event):
|
|
494
|
+
self.cancel_op = True
|
|
495
|
+
if self.process is None:
|
|
496
|
+
window_msg="Are you sure you want to quit?"
|
|
497
|
+
else:
|
|
498
|
+
window_msg="Work in progress. Are you sure you want to quit?"
|
|
499
|
+
|
|
500
|
+
reply= QtWidgets.QMessageBox.question(self,'Confirmation:',window_msg,
|
|
501
|
+
QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No,
|
|
502
|
+
QtWidgets.QMessageBox.StandardButton.No)
|
|
503
|
+
|
|
504
|
+
if reply == QtWidgets.QMessageBox.StandardButton.Yes:
|
|
505
|
+
if self.process is not None:
|
|
506
|
+
self.process.kill()
|
|
507
|
+
event.accept()
|
|
508
|
+
else:
|
|
509
|
+
event.ignore()
|
|
510
|
+
|
|
506
511
|
def set_tool(self, tool=None):
|
|
507
512
|
if tool:
|
|
508
513
|
self.tool_name = tool
|
|
@@ -539,19 +544,33 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
539
544
|
|
|
540
545
|
def show_help(self):
|
|
541
546
|
# open the user manual section for the current tool
|
|
542
|
-
|
|
547
|
+
tech_link = self.get_current_tool_parameters()["tech_link"]
|
|
548
|
+
if isinstance(tech_link, list):
|
|
549
|
+
if tech_link:
|
|
550
|
+
tech_link = tech_link[0]
|
|
551
|
+
else:
|
|
552
|
+
tech_link = ""
|
|
553
|
+
webbrowser.open_new_tab(str(tech_link))
|
|
543
554
|
|
|
544
555
|
def print_about(self):
|
|
545
556
|
self.text_edit.clear()
|
|
546
557
|
self.print_to_output(bt.about())
|
|
558
|
+
self.show_startup_warnings()
|
|
559
|
+
|
|
560
|
+
def show_startup_warnings(self):
|
|
561
|
+
warning_message = env_checks.get_gdal_proj_env_warning()
|
|
562
|
+
if warning_message:
|
|
563
|
+
self.print_line_to_output("")
|
|
564
|
+
self.print_line_to_output("[Warning]")
|
|
565
|
+
self.print_line_to_output(warning_message)
|
|
547
566
|
|
|
548
567
|
def print_license(self):
|
|
549
568
|
self.text_edit.clear()
|
|
550
569
|
self.print_to_output(bt.license())
|
|
551
570
|
|
|
552
571
|
def update_procs(self, value):
|
|
553
|
-
|
|
554
|
-
bt.
|
|
572
|
+
selected_cpu_cores = int(value)
|
|
573
|
+
bt.set_selected_cpu_cores(selected_cpu_cores)
|
|
555
574
|
|
|
556
575
|
def print_to_output(self, text):
|
|
557
576
|
self.text_edit.moveCursor(QtGui.QTextCursor.End)
|
|
@@ -560,7 +579,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
560
579
|
|
|
561
580
|
def print_line_to_output(self, text, tag=None):
|
|
562
581
|
self.text_edit.moveCursor(QtGui.QTextCursor.End)
|
|
563
|
-
self.text_edit.insertPlainText(text +
|
|
582
|
+
self.text_edit.insertPlainText(text + "\n")
|
|
564
583
|
self.text_edit.moveCursor(QtGui.QTextCursor.End)
|
|
565
584
|
|
|
566
585
|
def show_advanced(self):
|
|
@@ -573,35 +592,33 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
573
592
|
|
|
574
593
|
self.set_tool()
|
|
575
594
|
|
|
576
|
-
def view_code(self):
|
|
577
|
-
webbrowser.open_new_tab(self.get_current_tool_parameters()['tech_link'])
|
|
578
595
|
|
|
579
596
|
def custom_callback(self, value):
|
|
580
597
|
"""Define custom callback that deals with tool output."""
|
|
581
598
|
value = str(value)
|
|
582
599
|
value.strip()
|
|
583
|
-
if value !=
|
|
600
|
+
if value != "":
|
|
584
601
|
# remove esc string which origin is unknown
|
|
585
|
-
rm_str =
|
|
602
|
+
rm_str = "\x1b[0m"
|
|
586
603
|
if rm_str in value:
|
|
587
|
-
value = value.replace(rm_str,
|
|
604
|
+
value = value.replace(rm_str, "")
|
|
588
605
|
|
|
589
606
|
if "%" in value:
|
|
590
607
|
try:
|
|
591
|
-
str_progress =
|
|
608
|
+
str_progress = extract_string_from_printout(value, "%")
|
|
592
609
|
|
|
593
610
|
# remove progress string
|
|
594
|
-
value = value.replace(str_progress,
|
|
611
|
+
value = value.replace(str_progress, "").strip()
|
|
595
612
|
progress = float(str_progress.replace("%", "").strip())
|
|
596
613
|
self.progress_bar.setValue(int(progress))
|
|
597
614
|
except ValueError as e:
|
|
598
615
|
print("custom_callback: Problem parsing data into number: ", e)
|
|
599
616
|
except Exception as e:
|
|
600
617
|
print(e)
|
|
601
|
-
elif
|
|
602
|
-
str_label =
|
|
603
|
-
value = value.replace(str_label,
|
|
604
|
-
value = value.replace('"',
|
|
618
|
+
elif "PROGRESS_LABEL" in value:
|
|
619
|
+
str_label = extract_string_from_printout(value, "PROGRESS_LABEL")
|
|
620
|
+
value = value.replace(str_label, "").strip() # remove progress string
|
|
621
|
+
value = value.replace('"', "")
|
|
605
622
|
str_label = str_label.replace("PROGRESS_LABEL", "").strip()
|
|
606
623
|
self.progress_label.setText(str_label)
|
|
607
624
|
|
|
@@ -617,12 +634,12 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
617
634
|
def start_process(self):
|
|
618
635
|
args = self.tool_widget.get_widgets_arguments()
|
|
619
636
|
if not args:
|
|
620
|
-
print(
|
|
637
|
+
print("Please check the parameters.")
|
|
621
638
|
return
|
|
622
639
|
|
|
623
640
|
self.print_line_to_output("")
|
|
624
|
-
self.print_line_to_output(f
|
|
625
|
-
self.print_line_to_output(
|
|
641
|
+
self.print_line_to_output(f"Starting tool {self.tool_name} ... \n")
|
|
642
|
+
self.print_line_to_output("-----------------------------")
|
|
626
643
|
self.print_line_to_output("Tool arguments:")
|
|
627
644
|
self.print_line_to_output(json.dumps(args, indent=4))
|
|
628
645
|
self.print_line_to_output("")
|
|
@@ -635,7 +652,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
635
652
|
if type(args[key]) is not str:
|
|
636
653
|
args[key] = str(args[key])
|
|
637
654
|
|
|
638
|
-
tool_type, tool_args = bt.
|
|
655
|
+
tool_type, tool_args = bt.prepare_tool_run(self.tool_api, args, self.custom_callback)
|
|
639
656
|
|
|
640
657
|
if self.process is None: # No process running.
|
|
641
658
|
self.print_line_to_output(f"Tool {self.tool_name} started")
|
|
@@ -646,7 +663,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
646
663
|
self.process.stateChanged.connect(self.handle_state)
|
|
647
664
|
|
|
648
665
|
# Clean up once complete.
|
|
649
|
-
self.process.finished.connect(self.process_finished)
|
|
666
|
+
self.process.finished.connect(self.process_finished)
|
|
650
667
|
self.process.start(tool_type, tool_args)
|
|
651
668
|
|
|
652
669
|
while self.process is not None:
|
|
@@ -667,10 +684,6 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
667
684
|
data = self.process.readAllStandardError()
|
|
668
685
|
stderr = bytes(data).decode("utf8")
|
|
669
686
|
|
|
670
|
-
# Extract progress if it is in the data.
|
|
671
|
-
progress = simple_percent_parser(stderr)
|
|
672
|
-
if progress:
|
|
673
|
-
self.progress_bar.setValue(progress)
|
|
674
687
|
self.message(stderr)
|
|
675
688
|
|
|
676
689
|
def handle_stdout(self):
|
|
@@ -688,11 +701,11 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
688
701
|
QtCore.QProcess.Running: "Running",
|
|
689
702
|
}
|
|
690
703
|
state_name = states[state]
|
|
691
|
-
if state_name ==
|
|
704
|
+
if state_name == "Not running":
|
|
692
705
|
self.btn_run.setEnabled(True)
|
|
693
706
|
if self.cancel_op:
|
|
694
|
-
self.message(
|
|
695
|
-
elif state_name ==
|
|
707
|
+
self.message("Tool operation canceled")
|
|
708
|
+
elif state_name == "Starting":
|
|
696
709
|
self.btn_run.setEnabled(False)
|
|
697
710
|
|
|
698
711
|
def process_finished(self):
|
|
@@ -704,7 +717,32 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
704
717
|
|
|
705
718
|
def runner():
|
|
706
719
|
app = QtWidgets.QApplication(sys.argv)
|
|
720
|
+
|
|
721
|
+
# Use absolute path for icons (works with embedded Python on Windows)
|
|
722
|
+
assets_path = Path(__file__).parent / "assets"
|
|
723
|
+
app.setWindowIcon(QtGui.QIcon(str(assets_path / "BERALogo.ico")))
|
|
707
724
|
window = MainWindow()
|
|
708
725
|
window.setMinimumSize(1024, 768)
|
|
709
726
|
window.show()
|
|
710
|
-
|
|
727
|
+
|
|
728
|
+
# Cross-platform tray icon (Windows: .ico, macOS: .png)
|
|
729
|
+
import platform
|
|
730
|
+
if platform.system() == "Darwin":
|
|
731
|
+
tray_icon_path = assets_path / "BERALogo.png"
|
|
732
|
+
else:
|
|
733
|
+
tray_icon_path = assets_path / "BERALogo.ico"
|
|
734
|
+
tray_icon = QtWidgets.QSystemTrayIcon(QtGui.QIcon(str(tray_icon_path)), app)
|
|
735
|
+
tray_icon.setToolTip("BERA Tools")
|
|
736
|
+
tray_icon.show()
|
|
737
|
+
|
|
738
|
+
def signal_ready():
|
|
739
|
+
ready_flag = os.getenv("BERA_SPLASH_READY")
|
|
740
|
+
if ready_flag:
|
|
741
|
+
try:
|
|
742
|
+
from pathlib import Path
|
|
743
|
+
Path(ready_flag).touch()
|
|
744
|
+
except Exception:
|
|
745
|
+
pass
|
|
746
|
+
|
|
747
|
+
QtCore.QTimer.singleShot(100, signal_ready)
|
|
748
|
+
app.exec_()
|
beratools/gui/main.py
CHANGED
|
@@ -12,15 +12,12 @@ Description:
|
|
|
12
12
|
|
|
13
13
|
Main entry point of BERA Tools.
|
|
14
14
|
"""
|
|
15
|
-
import sys
|
|
16
|
-
from pathlib import Path
|
|
17
|
-
|
|
18
|
-
if __name__ == "__main__":
|
|
19
|
-
current_file = Path(__file__).resolve()
|
|
20
|
-
btool_dir = current_file.parents[2]
|
|
21
|
-
sys.path.insert(0, btool_dir.as_posix())
|
|
22
15
|
|
|
23
16
|
from beratools.gui.bt_gui_main import runner
|
|
24
17
|
|
|
18
|
+
|
|
19
|
+
def gui_main():
|
|
20
|
+
runner()
|
|
21
|
+
|
|
25
22
|
if __name__ == "__main__":
|
|
26
23
|
runner()
|