-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgeomelba_spirit_dialog.py
213 lines (198 loc) · 11.7 KB
/
geomelba_spirit_dialog.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# -*- coding: utf-8 -*-
"""
/***************************************************************************
GeomelbaSpirit
A QGIS plugin
Based on GeoMelba software, meant to be used with the serious game CAUSERIE.
This file contains the class of the dock widget dialog with all the buttons, tab widget, image and text.
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
-------------------
begin : 2021-08-24
git sha : $Format:%H$
copyright : (C) 2021 by Jules Grillot / INRAE
email : [email protected]
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
import os
from PyQt5.QtCore import Qt
from PyQt5.Qt import QMessageBox
from PyQt5.QtWidgets import QDialog, QLabel, QPushButton, QLineEdit, QButtonGroup, QFileDialog
from qgis.gui import QgsProjectionSelectionWidget
from qgis.core import QgsUnitTypes
from qgis.PyQt import uic
from .dictionnaire import regular_font, create_watershed_button_name, crs_selection_label_name, \
output_selection_label, output_button_name, watershed_selection_label, information_crs_text_pt1, \
information_crs_text_pt2, information_crs_text_pt3, folder_selection_text, information_folder_text_pt1, \
information_folder_text_pt2, serious_game_data_folder, watershed_prefix
# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
FORM_CLASS, _ = uic.loadUiType(os.path.join(
os.path.dirname(__file__), 'geomelba_spirit_dialog_base.ui'))
class GeomelbaSpiritDialog(QDialog, FORM_CLASS):
def __init__(self, parent=None):
"""Creation of the dialog interface appearing when clicking on the plugin button.
The interface contains :
- watershed selection buttons (based on folders in the plugin directory)
- a "create your watershed folder" button to add a new area
- a crs selector
- a directory output selector
"""
super(GeomelbaSpiritDialog, self).__init__(parent)
self.path = os.path.dirname(__file__) + serious_game_data_folder
self.setupUi(self)
# Add window tool, like minimize, maximize and close in top right corner.
self.setWindowFlags(Qt.Window |
Qt.WindowSystemMenuHint |
Qt.WindowMinMaxButtonsHint |
Qt.WindowCloseButtonHint)
# Creation of a group of buttons, easier to enable or disable all the buttons.
self.watershed_button_group = QButtonGroup()
self.watershed_button_group.setExclusive(True)
# Function to dynamically create buttons of the different watershed in the plugins.
self.init_button_watershed(watershed_prefix)
# Creation of a button ton add another watershed to the plugin
button_create_watershed = QPushButton(self)
button_create_watershed.setText(create_watershed_button_name)
button_create_watershed.setAccessibleName("create_watershed")
button_create_watershed.setGeometry(30, 300, 340, 30)
button_create_watershed.setCheckable(True)
self.watershed_button_group.addButton(button_create_watershed)
button_create_watershed.setFont(regular_font)
# Connexion of the watershed button group with a function to check if the path chose by the user is valid.
self.watershed_button_group.buttonToggled.connect(self.valid_path)
# Label creation
label_crs = QLabel(self)
label_crs.setFont(regular_font)
label_crs.setGeometry(30, 350, 400, 30)
label_crs.setText(crs_selection_label_name)
# Creation of the CRS selector
self.crs_selector = QgsProjectionSelectionWidget(self)
self.crs_selector.setFont(regular_font)
self.crs_selector.setGeometry(180, 350, 190, 30)
# Function connected to the signal emitted when CRS is changed
self.crs_selector.crsChanged.connect(self.crs_manager)
# Label creation
label_output = QLabel(self)
label_output.setFont(regular_font)
label_output.setGeometry(30, 410, 400, 30)
label_output.setText(output_selection_label)
# Line edit for the output folder
self.output_text = QLineEdit(self)
self.output_text.setFont(regular_font)
self.output_text.setGeometry(180, 410, 160, 30)
self.output_text.setEnabled(False)
# Connexion of the output path text with a function to check if the path chose by the user is valid.
self.output_text.textChanged.connect(self.valid_path)
# Button to find the output folder
self.output_button = QPushButton(self)
self.output_button.setFont(regular_font)
self.output_button.setGeometry(340, 410, 30, 30)
self.output_button.setText(output_button_name)
self.output_button.setEnabled(False)
# Function connected to the signal emitted by the button.
self.output_button.clicked.connect(self.select_output_folder)
# User cannot validate his selection while it's not valid, the start button is disabled.
self.button_box.setEnabled(False)
def init_button_watershed(self, value_to_test):
"""Function to place the different watershed buttons in the dialog. They are based on folders in the
plugin directory. They allow the user to select a watershed to analyze.
The mandatory arguments are :
- the prefix of the folders
For each folder with the prefix in the directory a button is created with the suffix as label and value.
The first button as a determined position, the other buttons are placed based on the first one
and the place left on the line. If there is no place left, the button begins another line.
The label are modified to fit the buttons, if its too long line breaks are added.
There is only 2 columns of buttons. Buttons need to be checkable.
"""
# Label creation
label_top = QLabel(self)
label_top.setFont(regular_font)
label_top.setGeometry(15, 10, 400, 30)
label_top.setText(watershed_selection_label)
# Position of the first button.
x_place = 45
y_place = 50
i = 0
# Loop on all the folder in the path to create a button for every element.
for name in os.listdir(self.path):
if os.path.isdir(os.path.join(self.path, name)):
# Check if the folder has the prefix.
if len(name.split(value_to_test, 1)) > 1:
button = QPushButton(self)
button_name = name.split(value_to_test, 1)[1]
# Change the name if it's too long for the button size.
if len(button_name) > 15:
# Get indexes where there is a '_', so we can cut the labels between words and not in the
# middle of one.
res = [i for i in range(len(button_name)) if button_name.startswith('_', i)]
for i in range(len(res)):
if res[i] > 17:
button_name = button_name[0:res[i]] + '\n' + button_name[res[i] + 1:]
while (res[i] < 30 and res[i] < len(
res)): # Loop to avoid too much \n and potentially add one if >30.
i += 1
if res[i] > 30:
button_name = button_name[0:res[i]] + '\n' + button_name[res[i] + 1:]
break
break
button_name = str(button_name.replace('_', ' ').capitalize()) # Transform last '_' to spaces.
button.setText(button_name)
button.setAccessibleName(str(button_name)) # The action name is stocked inside the button.
button.setGeometry(x_place, y_place, 140, 60)
button.setCheckable(True)
self.watershed_button_group.addButton(button)
# Position of the next button
i = i + 1
if i % 2 == 0:
# After a certain value on the x-axis it's a new line is started.
x_place = 45
y_place += 80
else:
# While the limit on the x-axis is not outmoded a button is added on the same line.
x_place += 170
def crs_manager(self):
"""Function to manage the modification of the CRS by the user.
If the crs is not in a metric system some error can occur with the tools allowing the user to click on the map.
A message is shown to inform the user that the CRS he chose is not covered by the plugin.
"""
crs = self.crs_selector.crs()
# 0 is the value of the metric system for the method mapUnits of the QgsCoordinateReferenceSystem class
if crs.mapUnits() != 0:
unit = QgsUnitTypes.encodeUnit(crs.mapUnits())
QMessageBox.information(None, information_crs_text_pt1, information_crs_text_pt2 + str(crs.authid()) +
information_crs_text_pt3 + str(unit) + ".")
def select_output_folder(self):
"""Function to make a dialog box with a list of directories when a button is clicked.
Once the user chose a directory, it's written in textline. The path can be written directly in this line text.
"""
folder = QFileDialog.getExistingDirectory(self, folder_selection_text, "", QFileDialog.ShowDirsOnly)
self.output_text.setText(folder)
def valid_path(self):
"""Function to check if all the conditions required to make the plugin works are good.
As long as a watershed button is not checked, the output buttons are disabled.
The output path is also check to be sure the path exist.
If the output does not exist the button to validate the user's choice and launch the plugin is disabled.
"""
# Check if a watershed button is pressed
if self.watershed_button_group.checkedButton() is not None:
# Enable the widgets to get the output path.
self.output_button.setEnabled(True)
self.output_text.setEnabled(True)
# If the output path exist, the user can launch the plugin.
if os.path.exists(self.output_text.text()):
self.button_box.setEnabled(True)
# If the folder has already been used by the user to create a simulation, error message to tell the user
# data might be deleted.
if os.path.exists(self.output_text.text() + "/" + self.watershed_button_group.button(
self.watershed_button_group.checkedId()).accessibleName().lower()):
QMessageBox.information(None, information_folder_text_pt1, information_folder_text_pt2)
else:
# if the path doesn't exist, the user cannot launch the plugin.
self.button_box.setEnabled(False)