def create_geog_form(self): grid = QGridLayout() self.geog_dataset_form = QGroupBox('Add Dataset') self.geog_dataset_form.setLayout(grid) self.geog_dataset_form.hide() group_name_validator = StringValidator(lambda s: s and re.fullmatch(r'[a-zA-Z0-9_]+', s)) # TODO fix validator if empty interp_validator = StringValidator(lambda s: ' ' not in s) self.geog_dataset_form_group_name = add_grid_lineedit(grid, 0, 'Group Name', validator=group_name_validator, required=True) self.geog_dataset_form_dataset = add_grid_combobox(grid, 1, 'Dataset') self.geog_dataset_form_variable = add_grid_combobox(grid, 2, 'Variable') self.geog_dataset_form_interp = add_grid_combobox(grid, 3, 'Interpolation') self.geog_dataset_form_custom_interp = add_grid_lineedit(grid, 4, 'Custom Interpolation', validator=interp_validator, required=False) self.geog_dataset_form_variable.currentIndexChanged.connect(self.geog_dataset_form_variable_changed) btn_add = QPushButton('Add') btn_cancel = QPushButton('Cancel') btn_add.clicked.connect(self.on_add_geog_dataset_form_button_clicked) btn_cancel.clicked.connect(self.on_cancel_geog_dataset_form_button_clicked) grid.addWidget(btn_cancel, 5, 0) grid.addWidget(btn_add, 5, 1)
def create_parent_group_box(name: str, res: float, unit: str, required: bool = False) -> QGroupBox: """Returns a 'validator-ready' group box to be used by the parent-domain tab.""" parent_child_ratio_box = QGridLayout() # TODO: This should be a spinbox instead with range [1,5]. parent_child_ratio = add_grid_lineedit(parent_child_ratio_box, 0, 'Child-to-Parent Ratio', RATIO_VALIDATOR, required=required) res_label = QLabel( HORIZONTAL_RESOLUTION_LABEL.format(resolution=res, unit=unit)) sub_group_box = QGroupBox("Padding") grid = QGridLayout() top_label = QLabel('Top') top_label.setAlignment(Qt.AlignCenter) grid.addWidget(top_label, 0, 1) left_label = QLabel('Left') left_label.setAlignment(Qt.AlignCenter) grid.addWidget(left_label, 2, 0) right_label = QLabel('Right') right_label.setAlignment(Qt.AlignCenter) grid.addWidget(right_label, 2, 2) bottom_label = QLabel('Bottom') bottom_label.setAlignment(Qt.AlignCenter) grid.addWidget(bottom_label, 4, 1) top = create_lineedit(DIM_VALIDATOR, required) left = create_lineedit(DIM_VALIDATOR, required) right = create_lineedit(DIM_VALIDATOR, required) bottom = create_lineedit(DIM_VALIDATOR, required) grid.addWidget(top, 1, 1) grid.addWidget(left, 3, 0) grid.addWidget(right, 3, 2) grid.addWidget(bottom, 5, 1) sub_group_box.setLayout(grid) vbox = QVBoxLayout() vbox.addLayout(parent_child_ratio_box) vbox.addWidget(res_label) vbox.addWidget(sub_group_box) group_box = QGroupBox(name) group_box.setLayout(vbox) return { 'inputs': { 'ratio': parent_child_ratio, 'top': top, 'left': left, 'right': right, 'bottom': bottom }, 'other': { 'resolution': res_label } }, group_box
def create_interp_input(self) -> None: grid = QGridLayout() self.interp_vert_selector = add_grid_combobox(grid, 0, 'Vertical Variable') self.interp_input = add_grid_lineedit(grid, 1, 'Desired Level', QDoubleValidator(0.0, 10000.0, 50), required=True) self.interp_input.returnPressed.connect(self.on_interp_btn_clicked) btn = QPushButton('Interpolate') btn.clicked.connect(self.on_interp_btn_clicked) grid.addWidget(btn, 2, 1) self.interp_container = QGroupBox('Interpolate Vertical Level') self.interp_container.setCheckable(True) self.interp_container.setChecked(False) self.interp_container.toggled.connect(self.on_interp_toggled) self.interp_container.setLayout(grid) self.interp_container.setHidden(True) self.vbox.addWidget(self.interp_container)
def __init__(self, iface: QgisInterface) -> None: super().__init__() self.iface = iface # Import/Export ## Import from 'namelist.wps' import_from_namelist_button = QPushButton("Import from namelist") import_from_namelist_button.setObjectName('import_from_namelist') ## Export to namelist export_geogrid_namelist_button = QPushButton("Export to namelist") export_geogrid_namelist_button.setObjectName( 'export_geogrid_namelist_button') vbox_import_export = QVBoxLayout() vbox_import_export.addWidget(import_from_namelist_button) vbox_import_export.addWidget(export_geogrid_namelist_button) self.gbox_import_export = QGroupBox("Import/Export") self.gbox_import_export.setLayout(vbox_import_export) # Group: Map Type self.group_box_map_type = QGroupBox("Map Type") vbox_map_type = QVBoxLayout() hbox_map_type = QHBoxLayout() self.projection = QComboBox() self.projection.setObjectName('projection') projs = { 'undefined': '-', # do not use a default projection - let the user pick the projection. 'lat-lon': 'Latitude/Longitude', 'lambert': 'Lambert' } for proj_id, proj_label in projs.items(): self.projection.addItem(proj_label, proj_id) hbox_map_type.addWidget(QLabel('GCS/Projection:')) # TODO: when the user select the type of GCS/Projection # we should automatically change the GCS/Projection for the whole # project. This will do an on-the-fly remapping of any of the other CRS # which are different from the one supported by our tool/WRF. # The Project CRS can be accessed in QGIS under the menu `Project` > `Project Properties` > `CRS.` # -> This is only really possible for Lat/Lon as this one is a CRS, where the others are projections # that only become a full CRS with the additional parameters like truelat1. # TODO: fields should be cleared when the user changes the CRS/Projection. hbox_map_type.addWidget(self.projection) vbox_map_type.addLayout(hbox_map_type) ## Lambert only: show 'True Latitudes' field truelat_grid = QGridLayout() self.truelat1 = add_grid_lineedit(truelat_grid, 0, 'True Latitude 1', LAT_VALIDATOR, unit='°', required=True) self.truelat2 = add_grid_lineedit(truelat_grid, 1, 'True Latitude 2', LAT_VALIDATOR, unit='°', required=True) self.widget_true_lats = QWidget() self.widget_true_lats.setLayout(truelat_grid) vbox_map_type.addWidget(self.widget_true_lats) self.domain_pb_set_projection = QPushButton("Set Map CRS") self.domain_pb_set_projection.setObjectName('set_projection_button') vbox_map_type.addWidget(self.domain_pb_set_projection) self.group_box_map_type.setLayout(vbox_map_type) # Group: Horizontal Resolution self.group_box_resol = QGroupBox("Horizontal Grid Spacing") hbox_resol = QHBoxLayout() self.resolution = MyLineEdit(required=True) self.resolution.setValidator(RESOLUTION_VALIDATOR) self.resolution.textChanged.connect( lambda _: update_input_validation_style(self.resolution)) self.resolution.textChanged.emit(self.resolution.text()) hbox_resol.addWidget(self.resolution) self.resolution_label = QLabel() hbox_resol.addWidget(self.resolution_label) self.group_box_resol.setLayout(hbox_resol) # Group: Automatic Domain Generator self.group_box_auto_domain = QGroupBox("Grid Extent Calculator") vbox_auto_domain = QVBoxLayout() hbox_auto_domain = QHBoxLayout() domain_pb_set_canvas_extent = QPushButton("Set to Canvas Extent") domain_pb_set_canvas_extent.setObjectName('set_canvas_extent_button') domain_pb_set_layer_extent = QPushButton("Set to Active Layer Extent") domain_pb_set_layer_extent.setObjectName('set_layer_extent_button') vbox_auto_domain.addLayout(hbox_auto_domain) vbox_auto_domain.addWidget(domain_pb_set_canvas_extent) vbox_auto_domain.addWidget(domain_pb_set_layer_extent) self.group_box_auto_domain.setLayout(vbox_auto_domain) # Group: Manual Domain Configuration ## Subgroup: Centre Point grid_center_point = QGridLayout() self.center_lon = add_grid_lineedit(grid_center_point, 0, 'Longitude', LON_VALIDATOR, '°', required=True) self.center_lat = add_grid_lineedit(grid_center_point, 1, 'Latitude', LAT_VALIDATOR, '°', required=True) group_box_centre_point = QGroupBox("Center Point") group_box_centre_point.setLayout(grid_center_point) ## Subgroup: Advanced configuration grid_dims = QGridLayout() self.cols = add_grid_lineedit(grid_dims, 0, 'Horizontal', DIM_VALIDATOR, required=True) self.rows = add_grid_lineedit(grid_dims, 1, 'Vertical', DIM_VALIDATOR, required=True) group_box_dims = QGroupBox("Grid Extent") group_box_dims.setLayout(grid_dims) vbox_manual_domain = QVBoxLayout() vbox_manual_domain.addWidget(group_box_centre_point) vbox_manual_domain.addWidget(group_box_dims) self.group_box_manual_domain = QGroupBox("Advanced Configuration") # TODO: make this section collapsable (default state collapsed) # and change the checkbox to arrows like `setArrowType(Qt.RightArrow)` # TODO: the style should be disabled when the 'advanced configuration' box is disabled (default). self.group_box_manual_domain.setCheckable(True) self.group_box_manual_domain.setChecked(False) self.group_box_manual_domain.setLayout(vbox_manual_domain) for field in [ self.resolution, self.center_lat, self.center_lon, self.rows, self.cols, self.truelat1, self.truelat2 ]: # editingFinished is only emitted on user input, not via programmatic changes. # This is important as we want to avoid re-drawing the bbox many times when several # fields get changed while using the automatic domain generator. field.editingFinished.connect(self.on_change_any_field) # Group Box: Parent Domain self.group_box_parent_domain = QGroupBox("Enable Parenting") self.group_box_parent_domain.setObjectName('group_box_parent_domain') self.group_box_parent_domain.setCheckable(True) self.group_box_parent_domain.setChecked(False) # TODO: As it is for the single domain case the generation of the domain should be automatic. # For now leave placeholder values of '3' for Child to Parent Ratio and '2' for padding. # use `calc_parent_lonlat_from_child` in `routines.py` to calculate the coordinate of the domain given the child domain coordinate, # grid_ratio and padding. hbox_parent_num = QHBoxLayout() hbox_parent_num.addWidget(QLabel('Number of Parent Domains:')) self.parent_spin = QSpinBox() self.parent_spin.setObjectName('parent_spin') self.parent_spin.setRange(1, MAX_PARENTS) hbox_parent_num.addWidget(self.parent_spin) self.group_box_parent_domain.setLayout(hbox_parent_num) self.parent_domains = [] # type: list self.parent_vbox = QVBoxLayout() self.parent_vbox.setSizeConstraint(QLayout.SetMinimumSize) go_to_data_tab_btn = QPushButton('Continue to Datasets') go_to_data_tab_btn.clicked.connect(self.go_to_data_tab) # Tabs dom_mgr_layout = QVBoxLayout() dom_mgr_layout.addWidget(self.gbox_import_export) dom_mgr_layout.addWidget(self.group_box_map_type) dom_mgr_layout.addWidget(self.group_box_resol) dom_mgr_layout.addWidget(self.group_box_auto_domain) dom_mgr_layout.addWidget(self.group_box_manual_domain) dom_mgr_layout.addWidget(self.group_box_parent_domain) dom_mgr_layout.addLayout(self.parent_vbox) dom_mgr_layout.addWidget(go_to_data_tab_btn) self.setLayout(dom_mgr_layout) QMetaObject.connectSlotsByName(self) # trigger event for initial layout self.projection.currentIndexChanged.emit( self.projection.currentIndex())
def __init__(self, iface) -> None: super().__init__() self.iface = iface self.options = get_options() self.msg_bar = MessageBar(iface) vbox = QVBoxLayout() self.setLayout(vbox) hbox = QHBoxLayout() vbox.addLayout(hbox) hbox.addWidget(QLabel('Dataset: ')) self.cbox_dataset = QComboBox() self.cbox_dataset.addItem('-') for index, (dataset_name, dataset_label) in enumerate(met_datasets.items()): self.cbox_dataset.addItem(dataset_name, dataset_name) self.cbox_dataset.setItemData(index + 1, dataset_label, Qt.ToolTipRole) self.cbox_dataset.currentIndexChanged.connect(self.on_dataset_changed) hbox.addWidget(self.cbox_dataset) hbox_product_name = QHBoxLayout() vbox.addLayout(hbox_product_name) hbox_product_name.addWidget(QLabel('Product: ')) self.cbox_product = QComboBox() self.cbox_product.currentIndexChanged.connect(self.on_product_changed) hbox_product_name.addWidget(self.cbox_product) hbox_start_datetime = QHBoxLayout() vbox.addLayout(hbox_start_datetime) self.dedit_start_date = QDateTimeEdit() self.dedit_start_date.setCalendarPopup(True) hbox_start_datetime.addWidget(QLabel('Start: ')) hbox_start_datetime.addWidget(self.dedit_start_date) hbox_end_datetime = QHBoxLayout() vbox.addLayout(hbox_end_datetime) self.dedit_end_date = QDateTimeEdit() self.dedit_end_date.setCalendarPopup(True) hbox_end_datetime.addWidget(QLabel('End: ')) hbox_end_datetime.addWidget(self.dedit_end_date) gbox_extent = QGroupBox('Extent') vbox.addWidget(gbox_extent) vbox_extent = QVBoxLayout() gbox_extent.setLayout(vbox_extent) hbox_extent = QHBoxLayout() vbox_extent.addLayout(hbox_extent) self.radio_global = QRadioButton('Global') self.radio_global.toggled.connect(self.on_extent_radio_button_clicked) hbox_extent.addWidget(self.radio_global) self.radio_subset = QRadioButton('Subset') self.radio_subset.toggled.connect(self.on_extent_radio_button_clicked) hbox_extent.addWidget(self.radio_subset) self.widget_extent = QWidget() vbox_extent.addWidget(self.widget_extent) grid_extent = QGridLayout() self.widget_extent.setLayout(grid_extent) self.widget_extent.hide() self.top = add_grid_lineedit(grid_extent, 0, 'North Latitude', LAT_VALIDATOR, '°', required=True) self.right = add_grid_lineedit(grid_extent, 1, 'East Longitude', LON_VALIDATOR, '°', required=True) self.left = add_grid_lineedit(grid_extent, 2, 'West Longitude', LON_VALIDATOR, '°', required=True) self.bottom = add_grid_lineedit(grid_extent, 3, 'South Latitude', LAT_VALIDATOR, '°', required=True) self.extent_from_active_layer = QPushButton('Set from Active Layer') grid_extent.addWidget(self.extent_from_active_layer, 4, 1) self.extent_from_active_layer.clicked.connect( self.on_extent_from_active_layer_button_clicked) self.radio_global.setChecked(True) self.tree = QListWidget() vbox_tree = QVBoxLayout() vbox.addLayout(vbox_tree) vbox_tree.addWidget(self.tree) self.btn_download = QPushButton('Download') self.btn_download.clicked.connect(self.on_download_button_clicked) vbox.addWidget(self.btn_download) self.progress_bar = QProgressBar() self.progress_bar.setRange(0, PROGRESS_BAR_MAX) self.progress_bar.setTextVisible(False) self.progress_bar.hide() vbox.addWidget(self.progress_bar)
def __init__(self, vtable_dir: str, spec: Optional[dict] = None) -> None: super().__init__() self.vtable_dir = vtable_dir self.paths = set() # type: Set[Path] geom = QGuiApplication.primaryScreen().geometry() w, h = geom.width(), geom.height() self.setWindowTitle("Custom Meteorological Dataset") self.setMinimumSize(w * 0.25, h * 0.35) layout = QVBoxLayout() # button to open folder/files dialog hbox = QHBoxLayout() layout.addLayout(hbox) add_folder_btn = QPushButton('Add folder') add_files_btn = QPushButton('Add files') remove_selected_btn = QPushButton('Remove selected') hbox.addWidget(add_folder_btn) hbox.addWidget(add_files_btn) hbox.addWidget(remove_selected_btn) add_folder_btn.clicked.connect(self.on_add_folder_btn_clicked) add_files_btn.clicked.connect(self.on_add_files_btn_clicked) remove_selected_btn.clicked.connect( self.on_remove_selected_btn_clicked) # show added files in a list self.paths_list = QListWidget() self.paths_list.setSelectionMode(QAbstractItemView.ContiguousSelection) layout.addWidget(self.paths_list) grid = QGridLayout() layout.addLayout(grid) # date/time start/end self.start_date_input = QDateTimeEdit() self.start_date_input.setCalendarPopup(True) self.end_date_input = QDateTimeEdit() self.end_date_input.setCalendarPopup(True) add_grid_labeled_widget(grid, 0, 'Start Date/Time', self.start_date_input) add_grid_labeled_widget(grid, 1, 'End Date/Time', self.end_date_input) # interval in seconds interval_validator = QIntValidator() interval_validator.setBottom(1) self.interval_input = add_grid_lineedit(grid, 2, 'Interval in seconds', interval_validator, required=True) # vtable file input self.vtable_input, vtable_hbox = create_file_input( dialog_caption='Select VTable file', is_folder=False, start_folder=vtable_dir) add_grid_labeled_widget(grid, 3, 'VTable', vtable_hbox) btn_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) btn_box.accepted.connect(self.on_ok_clicked) btn_box.rejected.connect(self.reject) layout.addWidget(btn_box) self.setLayout(layout) if spec: self.paths = set(map(Path, spec['paths'])) self.base_folder = spec['base_folder'] self.update_file_list() start_date, end_date = spec['time_range'] for date_input, date in [(self.start_date_input, start_date), (self.end_date_input, end_date)]: date_input.setDateTime( QDateTime(QDate(date.year, date.month, date.day), QTime(date.hour, date.minute))) self.interval_input.set_value(spec['interval_seconds']) self.vtable_input.setText(spec['vtable'])