def __init__(self, parent=None, settings_dict=None, wms_connected=False): """ Arguments: parent -- Qt widget that is parent to this widget. settings_dict -- dictionary containing topview options. """ super(MSS_TV_MapAppearanceDialog, self).__init__(parent) self.setupUi(self) if settings_dict is None: settings_dict = {"draw_graticule": True, "draw_coastlines": True, "fill_waterbodies": True, "fill_continents": True, "draw_flighttrack": True, "label_flighttrack": True, "colour_water": (0, 0, 0, 0), "colour_land": (0, 0, 0, 0), "colour_ft_vertices": (0, 0, 0, 0), "colour_ft_waypoints": (0, 0, 0, 0)} settings_dict["fill_waterbodies"] = True # removing water bodies does not work properly self.wms_connected = wms_connected # check parent.wms_connected to disable cbFillWaterBodies and cbFillContinents if self.wms_connected: self.cbFillContinents.setChecked(False) self.cbFillWaterBodies.setChecked(False) self.cbFillContinents.setEnabled(False) self.cbFillContinents.setStyleSheet("color: black") self.cbFillWaterBodies.setStyleSheet("color: black") else: self.cbFillWaterBodies.setChecked(settings_dict["fill_waterbodies"]) self.cbFillWaterBodies.setEnabled(False) self.cbFillContinents.setChecked(settings_dict["fill_continents"]) self.cbFillContinents.setEnabled(True) self.cbDrawGraticule.setChecked(settings_dict["draw_graticule"]) self.cbDrawCoastlines.setChecked(settings_dict["draw_coastlines"]) self.cbDrawFlightTrack.setChecked(settings_dict["draw_flighttrack"]) self.cbLabelFlightTrack.setChecked(settings_dict["label_flighttrack"]) for button, ids in [(self.btWaterColour, "colour_water"), (self.btLandColour, "colour_land"), (self.btWaypointsColour, "colour_ft_waypoints"), (self.btVerticesColour, "colour_ft_vertices")]: palette = QtGui.QPalette(button.palette()) colour = QtGui.QColor() colour.setRgbF(*settings_dict[ids]) palette.setColor(QtGui.QPalette.Button, colour) button.setPalette(palette) # Connect colour button signals. self.btWaterColour.clicked.connect(functools.partial(self.setColour, "water")) self.btLandColour.clicked.connect(functools.partial(self.setColour, "land")) self.btWaypointsColour.clicked.connect(functools.partial(self.setColour, "ft_waypoints")) self.btVerticesColour.clicked.connect(functools.partial(self.setColour, "ft_vertices"))
def __init__(self, parent=None, view=None): """ Arguments: parent -- Qt widget that is parent to this widget. view -- reference to mpl canvas class """ super(RemoteSensingControlWidget, self).__init__(parent) self.setupUi(self) self.view = view self.load = Loader(MSS_CONFIG_PATH, verbose=False) self.planets = self.load('de421.bsp') self.timescale = self.load.timescale(builtin=True) # don't download files, use shipped files button = self.btTangentsColour palette = QtGui.QPalette(button.palette()) colour = QtGui.QColor() colour.setRgbF(1, 0, 0, 1) palette.setColor(QtGui.QPalette.Button, colour) button.setPalette(palette) self.dsbTangentHeight.setValue(10.) self.dsbObsAngleAzimuth.setValue(90.) self.dsbObsAngleElevation.setValue(-1.0) # update plot on every value change self.cbDrawTangents.stateChanged.connect(self.update_settings) self.cbShowSolarAngle.stateChanged.connect(self.update_settings) self.btTangentsColour.clicked.connect(self.set_tangentpoint_colour) self.dsbTangentHeight.valueChanged.connect(self.update_settings) self.dsbObsAngleAzimuth.valueChanged.connect(self.update_settings) self.dsbObsAngleElevation.valueChanged.connect(self.update_settings) self.cbSolarBody.currentIndexChanged.connect(self.update_settings) self.cbSolarAngleType.currentIndexChanged.connect(self.update_settings) self.lbSolarCmap.setText( "Solar angle colours, dark to light: reds (0-15), violets (15-45), greens (45-180)" ) self.solar_cmap = ListedColormap([(1.00, 0.00, 0.00, 1.0), (1.00, 0.45, 0.00, 1.0), (1.00, 0.75, 0.00, 1.0), (0.47, 0.10, 1.00, 1.0), (0.72, 0.38, 1.00, 1.0), (1.00, 0.55, 1.00, 1.0), (0.00, 0.70, 0.00, 1.0), (0.33, 0.85, 0.33, 1.0), (0.65, 1.00, 0.65, 1.0)]) self.solar_norm = BoundaryNorm( [0, 5, 10, 15, 25, 35, 45, 90, 135, 180], self.solar_cmap.N) self.update_settings()
def open_customize_kml_dialog(self): file = self.listWidget.currentItem().text() # Set the colour of the Colour button to the colour of specific KML plot if self.dict_files[file]["color"] is not None: palette = QtGui.QPalette(self.dialog.pushButton_colour.palette()) colour = QtGui.QColor() colour.setRgbF(*self.set_color(file)) palette.setColor(QtGui.QPalette.Button, colour) self.dialog.pushButton_colour.setPalette(palette) # Set the linewidth value to the linewidth of specific KML plot if self.dict_files[file]["linewidth"] is not None: self.dialog.dsb_linewidth.setValue(self.set_linewidth(file)) self.dialog.show()
def paint(self, painter, option, index): """Colours waypoints with a minor waypoint number (i.e. intermediate waypoints generated by the flight performance service) in red. """ wpnumber_minor = index.model().waypoint_data( index.row()).wpnumber_minor if wpnumber_minor is not None and wpnumber_minor > 0: newpalette = QtGui.QPalette(option.palette) colour = QtGui.QColor(170, 0, 0) # dark red newpalette.setColor(QtGui.QPalette.Text, colour) colour = QtGui.QColor(255, 255, 0) # yellow newpalette.setColor(QtGui.QPalette.HighlightedText, colour) option.palette = newpalette QtWidgets.QItemDelegate.paint(self, painter, option, index)
def __init__(self, parent=None, model=None, _id=None): """ """ super(MSSTableViewWindow, self).__init__(parent, model, _id) self.setupUi(self) self.setWindowIcon(QtGui.QIcon(icons('64x64'))) self.setFlightTrackModel(model) self.tableWayPoints.setItemDelegate(ft.WaypointDelegate(self)) toolitems = ["(select to open control)", "Hexagon Control"] self.cbTools.clear() self.cbTools.addItems(toolitems) self.tableWayPoints.dropEvent = types.MethodType( dropEvent, self.tableWayPoints) self.tableWayPoints.dragEnterEvent = types.MethodType( dragEnterEvent, self.tableWayPoints) # Dock windows [Hexagon]. self.docks = [None] # Connect slots and signals. self.btAddWayPointToFlightTrack.clicked.connect(self.addWayPoint) self.btCloneWaypoint.clicked.connect(self.cloneWaypoint) self.btDeleteWayPoint.clicked.connect(self.removeWayPoint) self.btInvertDirection.clicked.connect(self.invertDirection) self.btViewPerformance.clicked.connect(self.settingsDlg) # Tool opener. self.cbTools.currentIndexChanged.connect(self.openTool) self.resizeColumns()
def __init__(self, parent=None, model=None, _id=None): """Set up user interface, connect signal/slots. """ super(MSSTopViewWindow, self).__init__(parent, model, _id) logging.debug(_id) self.setupUi(self) self.setWindowIcon(QtGui.QIcon(icons('64x64'))) # Dock windows [WMS, Satellite, Trajectories, Remote Sensing, KML Overlay]: self.docks = [None, None, None, None, None] self.settings_tag = "topview" self.load_settings() # Initialise the GUI elements (map view, items of combo boxes etc.). self.setup_top_view() # Boolean to store active wms connection self.wms_connected = False # Connect slots and signals. # ========================== # Map controls. self.btMapRedraw.clicked.connect(self.mpl.canvas.redraw_map) self.cbChangeMapSection.activated.connect(self.changeMapSection) # Settings self.btSettings.clicked.connect(self.settings_dialogue) # Tool opener. self.cbTools.currentIndexChanged.connect(self.openTool)
def setup_message_box_layout(self): container_layout = QtWidgets.QHBoxLayout() text_area_layout = QtWidgets.QVBoxLayout() if self.chat_window.user["username"] == self.username: text_area_layout.addWidget(self.messageBox) self.textArea.setLayout(text_area_layout) container_layout.addStretch() container_layout.addWidget(self.textArea) else: username_label = QtWidgets.QLabel(f"{self.username}") username_label.setContentsMargins(5, 5, 5, 0) label_font = QtGui.QFont() label_font.setBold(True) username_label.setFont(label_font) text_area_layout.addWidget(username_label) text_area_layout.addWidget(self.messageBox) self.textArea.setLayout(text_area_layout) container_layout.addWidget(self.textArea) container_layout.addStretch() for reply in self.replies: self.add_message_reply(reply) self.textArea.layout().setSpacing(0) self.textArea.layout().setContentsMargins(0, 0, 0, 0) container_layout.setSpacing(0) container_layout.setContentsMargins(5, 5, 5, 5) self.set_message_style() self.setLayout(container_layout)
def get_color(self): """ Returns the colour of the 'pushButton_colour' Button """ button = self.dialog.pushButton_colour return QtGui.QPalette(button.palette()).color( QtGui.QPalette.Button).getRgbF()
def __init__(self, parent=None, model=None, _id=None): """Set up user interface, connect signal/slots. """ super(MSSSideViewWindow, self).__init__(parent, model, _id) self.setupUi(self) self.setWindowIcon(QtGui.QIcon(icons('64x64'))) # Dock windows [WMS]: self.cbTools.clear() self.cbTools.addItems(["(select to open control)", "Vertical Section WMS"]) self.docks = [None] self.setFlightTrackModel(model) self.settings_tag = "sideview" self.load_settings() # Connect slots and signals. # ========================== # Buttons to set sideview options. self.btOptions.clicked.connect(self.set_options) # Tool opener. self.cbTools.currentIndexChanged.connect(self.openTool)
def setup_image_message_box(self): MAX_WIDTH = MAX_HEIGHT = 300 self.messageBox = QtWidgets.QLabel() img_url = url_join(self.chat_window.mscolab_server_url, self.attachment_path) data = requests.get(img_url).content image = QtGui.QImage() image.loadFromData(data) self.message_image = image width, height = image.size().width(), image.size().height() if width > height and width > MAX_WIDTH: image = image.scaledToWidth(MAX_WIDTH) elif height > width and height > MAX_HEIGHT: image = image.scaledToHeight(MAX_HEIGHT) self.messageBox.setPixmap(QtGui.QPixmap(image)) self.messageBox.setContentsMargins(0, 5, 0, 5) self.messageBox.show()
def display_uploaded_img(self, file_path): self.messageText.clear() image_uri = QtCore.QUrl(f"file://{file_path}") image = QtGui.QImage(QtGui.QImageReader(file_path).read()) self.messageText.document().addResource( QtGui.QTextDocument.ImageResource, image_uri, QtCore.QVariant(image)) img_width, img_height = self.get_img_dimensions(image) image_format = QtGui.QTextImageFormat() image_format.setWidth(img_width) image_format.setHeight(img_height) image_format.setName(image_uri.toString()) cursor = self.messageText.textCursor() cursor.movePosition(QtGui.QTextCursor.End, QtGui.QTextCursor.MoveAnchor) cursor.insertImage(image_format) self.messageText.setReadOnly(True)
def add_message_reply(self, reply): if self.replyArea is None: self.insert_reply_area() reply_username_label = QtWidgets.QLabel(f'{reply["username"]}:') label_font = QtGui.QFont() label_font.setBold(True) reply_username_label.setFont(label_font) reply_message_box = self.get_text_browser(reply["text"]) self.replyArea.layout().addRow(reply_username_label, reply_message_box)
def _icon(self, name, *args): """ wrapper around base method to inject our own icons. """ myname = icons("32x32", name) if os.path.exists(myname): return QtGui.QIcon(myname) else: return super(NavigationToolbar, self)._icon(name, *args)
def __init__(self, parent=None): """ Arguments: parent -- Qt widget that is parent to this widget. """ super(MSS_AboutDialog, self).__init__(parent) self.setupUi(self) self.lblVersion.setText("Version: {}".format(__version__)) blub = QtGui.QPixmap(python_powered()) self.lblPython.setPixmap(blub)
def get_settings(self): """ """ settings_dict = { "draw_graticule": self.cbDrawGraticule.isChecked(), "draw_coastlines": self.cbDrawCoastlines.isChecked(), "fill_waterbodies": self.cbFillWaterBodies.isChecked(), "fill_continents": self.cbFillContinents.isChecked(), "draw_flighttrack": self.cbDrawFlightTrack.isChecked(), "label_flighttrack": self.cbLabelFlightTrack.isChecked(), "colour_water": QtGui.QPalette(self.btWaterColour.palette()).color(QtGui.QPalette.Button).getRgbF(), "colour_land": QtGui.QPalette(self.btLandColour.palette()).color(QtGui.QPalette.Button).getRgbF(), "colour_ft_vertices": QtGui.QPalette(self.btVerticesColour.palette()).color(QtGui.QPalette.Button).getRgbF(), "colour_ft_waypoints": QtGui.QPalette(self.btWaypointsColour.palette()).color(QtGui.QPalette.Button).getRgbF(), } return settings_dict
def set_tangentpoint_colour(self): """Slot for the colour buttons: Opens a QColorDialog and sets the new button face colour. """ button = self.btTangentsColour palette = QtGui.QPalette(button.palette()) colour = palette.color(QtGui.QPalette.Button) colour = QtWidgets.QColorDialog.getColor(colour) if colour.isValid(): palette.setColor(QtGui.QPalette.Button, colour) button.setPalette(palette) self.update_settings()
def set_active_pid(self, item): if item.p_id == self.active_pid: return # close all hanging window self.force_close_view_windows() self.close_external_windows() # Turn off work locally toggle self.workLocallyCheckBox.blockSignals(True) self.workLocallyCheckBox.setChecked(False) self.workLocallyCheckBox.blockSignals(False) self.save_ft.setEnabled(False) self.fetch_ft.setEnabled(False) # set active_pid here self.active_pid = item.p_id self.access_level = item.access_level self.active_project_name = item.text().split("-")[0].strip() self.waypoints_model = None # set active flightpath here self.load_wps_from_server() # enable project specific buttons self.helperTextLabel.setVisible(True) self.helperTextLabel.setText(self.tr("Working On: Shared File. All your changes will be shared with everyone." "Turn on work locally to work on local flight track file")) self.importBtn.setEnabled(True) self.exportBtn.setEnabled(True) self.topview.setEnabled(True) self.sideview.setEnabled(True) self.tableview.setEnabled(True) self.workLocallyCheckBox.setEnabled(True) if self.access_level == "viewer" or self.access_level == "collaborator": if self.access_level == "viewer": self.chatWindowBtn.setEnabled(False) else: self.chatWindowBtn.setEnabled(True) self.adminWindowBtn.setEnabled(False) self.versionHistoryBtn.setEnabled(False) else: self.adminWindowBtn.setEnabled(True) self.chatWindowBtn.setEnabled(True) self.versionHistoryBtn.setEnabled(True) if self.access_level == "creator": self.deleteProjectBtn.setEnabled(True) else: self.deleteProjectBtn.setEnabled(False) # change font style for selected font = QtGui.QFont() for i in range(self.listProjects.count()): self.listProjects.item(i).setFont(font) font.setBold(True) item.setFont(font)
def get_settings(self): """Return settings dictionary with values from the GUI elements. """ settings_dict = { "vertical_extent": (float(self.sbPbot.value()), float(self.sbPtop.value())), "vertical_axis": self.cbVerticalAxis.currentText(), "flightlevels": self.get_flight_levels(), "draw_ceiling": self.cbDrawCeiling.isChecked(), "draw_flightlevels": self.cbDrawFlightLevels.isChecked(), "draw_flighttrack": self.cbDrawFlightTrack.isChecked(), "fill_flighttrack": self.cbFillFlightTrack.isChecked(), "label_flighttrack": self.cbLabelFlightTrack.isChecked(), "colour_ft_vertices": QtGui.QPalette(self.btVerticesColour.palette()).color(QtGui.QPalette.Button).getRgbF(), "colour_ft_waypoints": QtGui.QPalette(self.btWaypointsColour.palette()).color(QtGui.QPalette.Button).getRgbF(), "colour_ft_fill": QtGui.QPalette(self.btFillColour.palette()).color(QtGui.QPalette.Button).getRgbF(), "colour_ceiling": QtGui.QPalette(self.btCeilingColour.palette()).color(QtGui.QPalette.Button).getRgbF(), } return settings_dict
def compute_tangent_lines(self, bmap, wp_vertices, wp_heights): """ Computes Tangent points of limb sounders aboard the aircraft Args: bmap: Projection of TopView wp_vertices: waypoints of the flight path wp_heights: altitude of the waypoints of flight path Returns: LineCollection of dotted lines at tangent point locations """ x, y = list(zip(*wp_vertices)) wp_lons, wp_lats = bmap(x, y, inverse=True) fine_lines = [ bmap.gcpoints2(wp_lons[i], wp_lats[i], wp_lons[i + 1], wp_lats[i + 1], del_s=10., map_coords=False) for i in range(len(wp_lons) - 1) ] line_heights = [ np.linspace(wp_heights[i], wp_heights[i + 1], num=len(fine_lines[i][0])) for i in range(len(fine_lines)) ] # fine_lines = list of tuples with x-list and y-list for each segment tplines = [ self.tangent_point_coordinates( fine_lines[i][0], fine_lines[i][1], line_heights[i], cut_height=self.dsbTangentHeight.value()) for i in range(len(fine_lines)) ] dirlines = self.direction_coordinates(wp_lons, wp_lats) lines = tplines + dirlines for i, line in enumerate(lines): for j, (lon, lat) in enumerate(line): line[j] = bmap(lon, lat) lines[i] = line return LineCollection( lines, colors=QtGui.QPalette(self.btTangentsColour.palette()).color( QtGui.QPalette.Button).getRgbF(), zorder=2, animated=True, linewidth=3, linestyles=[':'] * len(tplines) + ['-'] * len(dirlines))
class Test_MSS_SV_OptionsDialog(object): def setup(self): self.application = QtWidgets.QApplication(sys.argv) self.window = tv.MSS_SV_OptionsDialog() self.window.show() QtWidgets.QApplication.processEvents() QtTest.QTest.qWaitForWindowExposed(self.window) QtWidgets.QApplication.processEvents() def teardown(self): self.window.hide() QtWidgets.QApplication.processEvents() self.application.quit() QtWidgets.QApplication.processEvents() @mock.patch("mslib.msui.mss_qt.QtWidgets.QMessageBox") def test_show(self, mockcrit): assert mockcrit.critical.call_count == 0 @mock.patch("mslib.msui.mss_qt.QtWidgets.QMessageBox") def test_get(self, mockcrit): self.window.get_settings() assert mockcrit.critical.call_count == 0 @mock.patch("mslib.msui.mss_qt.QtWidgets.QMessageBox") def test_addLevel(self, mockcrit): QtTest.QTest.mouseClick(self.window.btAdd, QtCore.Qt.LeftButton) QtWidgets.QApplication.processEvents() assert mockcrit.critical.call_count == 0 @mock.patch("mslib.msui.mss_qt.QtWidgets.QMessageBox") def test_removeLevel(self, mockcrit): QtTest.QTest.mouseClick(self.window.btDelete, QtCore.Qt.LeftButton) QtWidgets.QApplication.processEvents() assert mockcrit.critical.call_count == 0 def test_getFlightLevels(self): levels = self.window.get_flight_levels() assert all(x == y for x, y in zip(levels, [300, 320, 340])) QtTest.QTest.mouseClick(self.window.btAdd, QtCore.Qt.LeftButton) QtWidgets.QApplication.processEvents() levels = self.window.get_flight_levels() assert all(x == y for x, y in zip(levels, [0, 300, 320, 340])) @mock.patch("mslib.msui.mss_qt.QtWidgets.QColorDialog.getColor", return_value=QtGui.QColor()) def test_setColour(self, mockdlg): QtTest.QTest.mouseClick(self.window.btFillColour, QtCore.Qt.LeftButton) QtWidgets.QApplication.processEvents() assert mockdlg.call_count == 1
def activate_flight_track(self, item): """Set the currently selected flight track to be the active one, i.e. the one that is displayed in the views (only one flight track can be displayed at a time). """ self.active_flight_track = item.flighttrack_model for i in range(self.listViews.count()): view_item = self.listViews.item(i) view_item.window.setFlightTrackModel(self.active_flight_track) font = QtGui.QFont() for i in range(self.listFlightTracks.count()): self.listFlightTracks.item(i).setFont(font) font.setBold(True) item.setFont(font)
def select_color(self): """ Stores current selected file; select colour using Palette """ file = self.listWidget.currentItem().text() button = self.dialog.pushButton_colour palette = QtGui.QPalette(button.palette()) colour = palette.color(QtGui.QPalette.Button) colour = QtWidgets.QColorDialog.getColor( colour) # opens select colour palette if colour.isValid(): palette.setColor(QtGui.QPalette.Button, colour) button.setPalette(palette) # finally sets the colour of the button self.set_attribute_color(file)
def setColour(self, which): """Slot for the colour buttons: Opens a QColorDialog and sets the new button face colour. """ if which == "water": button = self.btWaterColour elif which == "land": button = self.btLandColour elif which == "ft_vertices": button = self.btVerticesColour elif which == "ft_waypoints": button = self.btWaypointsColour palette = QtGui.QPalette(button.palette()) colour = palette.color(QtGui.QPalette.Button) colour = QtWidgets.QColorDialog.getColor(colour) if colour.isValid(): palette.setColor(QtGui.QPalette.Button, colour) button.setPalette(palette)
def preview_change(self, current_item, previous_item): font = QtGui.QFont() if previous_item is not None: previous_item.setFont(font) if current_item is None: self.changePreviewTable.setModel(None) self.deleteVersionNameBtn.setVisible(False) self.toggle_version_buttons(False) return font.setBold(True) current_item.setFont(font) data = {"token": self.token, "ch_id": current_item.id} url = url_join(self.mscolab_server_url, 'get_change_content') res = requests.get(url, data=data).json() waypoint_model = WaypointsTableModel(xml_content=res["content"]) self.changePreviewTable.setModel(waypoint_model) if current_item.version_name is not None: self.deleteVersionNameBtn.setVisible(True) else: self.deleteVersionNameBtn.setVisible(False) self.toggle_version_buttons(True)
def setColour(self, which): """Slot for the colour buttons: Opens a QColorDialog and sets the new button face colour. """ if which == "ft_fill": button = self.btFillColour elif which == "ft_vertices": button = self.btVerticesColour elif which == "ft_waypoints": button = self.btWaypointsColour elif which == "ceiling": button = self.btCeilingColour palette = QtGui.QPalette(button.palette()) colour = palette.color(QtGui.QPalette.Button) colour = QtWidgets.QColorDialog.getColor(colour) if colour.isValid(): if which == "ft_fill": # Fill colour is transparent with an alpha value of 0.15. If # you like to change this, modify the PathInteractor class. colour.setAlphaF(0.15) palette.setColor(QtGui.QPalette.Button, colour) button.setPalette(palette)
def __init__(self, *args): super(MSSMainWindow, self).__init__(*args) self.setupUi(self) self.setWindowIcon(QtGui.QIcon(icons('32x32'))) # This code is required in Windows 7 to use the icon set by setWindowIcon in taskbar # instead of the default Icon of python/pythonw try: import ctypes myappid = "mss.mss_pyui.{}".format(__version__) # arbitrary string ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid) except (ImportError, AttributeError) as error: logging.debug("AttributeError, ImportError Exception %s", error) # Reference to the flight track that is currently displayed in the # views. self.active_flight_track = None self.last_save_directory = config_loader(dataset="data_dir", default=mss_default.data_dir) self.mscolab_window = None self.config_editor = None # Connect Qt SIGNALs: # =================== # File menu. self.actionNewFlightTrack.triggered.connect(functools.partial(self.create_new_flight_track, None, None)) self.actionOpenFlightTrack.triggered.connect(self.open_flight_track) self.actionActivateSelectedFlightTrack.triggered.connect(self.activate_selected_flight_track) self.actionCloseSelectedFlightTrack.triggered.connect(self.close_selected_flight_track) self.actionSaveActiveFlightTrack.triggered.connect(self.save_flight_track) self.actionSaveActiveFlightTrackAs.triggered.connect(self.save_flight_track_as) # Views menu. self.actionTopView.triggered.connect(self.create_new_view) self.actionSideView.triggered.connect(self.create_new_view) self.actionTableView.triggered.connect(self.create_new_view) # mscolab menu self.actionMscolabProjects.triggered.connect(self.activate_mscolab_window) # Help menu. self.actionOnlineHelp.triggered.connect(self.show_online_help) self.actionAboutMSUI.triggered.connect(self.show_about_dialog) # Config self.actionConfiguration.triggered.connect(self.open_config_file) # Flight Tracks. self.listFlightTracks.itemActivated.connect(self.activate_flight_track) # Views. self.listViews.itemActivated.connect(self.activate_sub_window) self.add_import_filter("CSV", "csv", load_from_csv, pickertag="filepicker_flightrack") self.add_export_filter("CSV", "csv", save_to_csv, pickertag="filepicker_flightrack") self._imported_plugins, self._exported_plugins = {}, {} self.add_plugins() preload_urls = config_loader(dataset="WMS_preload", default=[]) self.preload_wms(preload_urls) # Status Bar self.labelStatusbar.setText(self.status())
class Test_KmlOverlayDockWidget(object): def setup(self): self.application = QtWidgets.QApplication(sys.argv) self.view = mock.Mock() self.view.map = mock.Mock(side_effect=lambda x, y: (x, y)) self.view.map.plot = mock.Mock(return_value=[mock.Mock()]) self.window = kd.KMLOverlayControlWidget(view=self.view) self.window.show() QtWidgets.QApplication.processEvents() QtTest.QTest.qWaitForWindowExposed(self.window) # start load test self.window.select_all() self.window.remove_file() QtWidgets.QApplication.processEvents() def teardown(self): QtWidgets.QApplication.processEvents() self.application.quit() QtWidgets.QApplication.processEvents() self.window.close() if os.path.exists(save_kml): os.remove(save_kml) def select_file(self, file): # Utility function for single file path = fs.path.join(sample_path, "kml", file) filename = (path, ) # converted to tuple self.window.select_file(filename) QtWidgets.QApplication.processEvents() return path def select_files(self): # Utility function for multiple files for sample in [ "folder.kml", "line.kml", "color.kml", "style.kml", "features.kml" ]: path = fs.path.join(sample_path, "kml", sample) filename = (path, ) # converted to tuple self.window.select_file(filename) QtWidgets.QApplication.processEvents() @mock.patch("mslib.msui.kmloverlay_dockwidget.get_open_filenames", return_value=[fs.path.join(sample_path, "kml", "line.kml")]) def test_get_file(self, mockopen): # Tests opening of QFileDialog QtTest.QTest.mouseClick(self.window.btSelectFile, QtCore.Qt.LeftButton) QtWidgets.QApplication.processEvents() assert mockopen.call_count == 1 @mock.patch("mslib.msui.mss_qt.QtWidgets.QMessageBox") def test_select_file(self, mockbox): """ Test All geometries and styles are being parsed without crashing """ index = 0 assert self.window.listWidget.count() == 0 for sample in [ "folder.kml", "line.kml", "color.kml", "style.kml", "features.kml", "geometry_collection.kml", "Multilinestrings.kml", "polygon_inner.kml", "World_Map.kml" ]: path = self.select_file(sample) QtTest.QTest.qWait(250) assert self.window.listWidget.item( index).checkState() == QtCore.Qt.Checked index = index + 1 assert self.window.directory_location == path assert mockbox.critical.call_count == 0 assert self.window.listWidget.count() == index assert len(self.window.dict_files) == index assert self.window.patch is not None self.window.select_all() self.window.remove_file() @mock.patch("mslib.msui.mss_qt.QtWidgets.QMessageBox") def test_select_file_error(self, mockbox): """ Test that program mitigates loading a non-existing file """ # load a non existing path self.window.select_all() self.window.remove_file() path = fs.path.join(sample_path, "satellite_tracks", "satellite_predictor.txt") filename = (path, ) # converted to tuple self.window.select_file(filename) QtWidgets.QApplication.processEvents() assert mockbox.critical.call_count == 1 self.window.listWidget.clear() self.window.dict_files = {} def test_remove_file(self): """ Test removing all files except one """ self.select_files() QtWidgets.QApplication.processEvents() self.window.listWidget.item(0).setCheckState(QtCore.Qt.Unchecked) QtTest.QTest.mouseClick(self.window.pushButton_remove, QtCore.Qt.LeftButton) assert self.window.listWidget.count() == 1 assert len(self.window.dict_files) == 1 self.window.select_all() self.window.remove_file() def test_remove_all_files(self): """ Test removing all files """ self.select_files() QtWidgets.QApplication.processEvents() assert self.window.listWidget.count() == 5 QtTest.QTest.mouseClick(self.window.pushButton_remove, QtCore.Qt.LeftButton) QtWidgets.QApplication.processEvents() assert self.window.listWidget.count() == 0 # No items in list assert self.window.dict_files == {} # Dictionary should be empty assert self.window.patch is None # Patch should be None @mock.patch("mslib.msui.mss_qt.QtWidgets.QMessageBox") @mock.patch("mslib.msui.kmloverlay_dockwidget.get_save_filename", return_value=save_kml) def test_merge_file(self, mocksave, mockbox): """ Test merging files into a single file without crashing """ self.select_files() QtWidgets.QApplication.processEvents() QtTest.QTest.mouseClick(self.window.pushButton_merge, QtCore.Qt.LeftButton) QtWidgets.QApplication.processEvents() assert mocksave.call_count == 1 assert os.path.exists(save_kml) @mock.patch("mslib.msui.mss_qt.QtWidgets.QColorDialog.getColor", return_value=QtGui.QColor()) def test_customize_kml(self, mock_colour_dialog): """ Test opening Customize KML Dialogue and checking specific file gets desired linewidth and colour """ path = self.select_file("line.kml") # selects file and returns path assert self.window.listWidget.count() == 1 item = self.window.listWidget.item(0) rect = self.window.listWidget.visualItemRect(item) # in testing, need to add mouseclick before double click QtTest.QTest.mouseClick(self.window.listWidget.viewport(), QtCore.Qt.LeftButton, pos=rect.center()) QtWidgets.QApplication.processEvents() # Double click feature QtTest.QTest.mouseDClick(self.window.listWidget.viewport(), QtCore.Qt.LeftButton, pos=rect.center()) QtWidgets.QApplication.processEvents() # Clicking on Push Button Colour QtTest.QTest.mouseClick(self.window.dialog.pushButton_colour, QtCore.Qt.LeftButton) QtWidgets.QApplication.processEvents() assert mock_colour_dialog.call_count == 1 # Testing the Double Spin Box self.window.dialog.dsb_linewidth.setValue(3) assert self.window.dialog.dsb_linewidth.value() == 3 # clicking on OK Button okWidget = self.window.dialog.buttonBox.button( self.window.dialog.buttonBox.Ok) QtTest.QTest.mouseClick(okWidget, QtCore.Qt.LeftButton) QtWidgets.QApplication.processEvents() assert self.window.dict_files[path]["color"] == self.window.get_color() assert self.window.dict_files[path]["linewidth"] == 3 self.window.remove_file() assert self.window.listWidget.count() == 0 def test_check_uncheck(self): """ Tests 'Displays plot on map when file is checked' and vice versa """ self.select_file("line.kml") assert self.window.listWidget.item(0).checkState() == QtCore.Qt.Checked assert len(self.window.patch.patches) == 1 self.window.listWidget.item(0).setCheckState(QtCore.Qt.Unchecked) assert self.window.listWidget.item( 0).checkState() == QtCore.Qt.Unchecked assert len(self.window.patch.patches) == 0 self.window.select_all() self.window.remove_file() # Matplotlib Plots Testing def test_kml_patches(self): """ Tests the type of patches plotted by each Test Sample File """ self.select_file("line.kml") assert len( self.window.patch.patches) == 1 # 1 LineString Geometry Patch self.window.remove_file() self.select_file("folder.kml") assert len( self.window.patch.patches) == 3 # 1 Point, 1 Polygon, 1 Text Patch self.window.remove_file() self.select_file("color.kml") assert len(self.window.patch.patches) == 1 # 1 Polygon Patch self.window.remove_file() self.select_file("style.kml") assert len(self.window.patch.patches ) == 4 # 1 Point, 1 Text, 1 Polygon, 1 LineString Patch self.window.remove_file() self.select_file("features.kml") assert len(self.window.patch.patches ) == 17 # 3 Points, 11 LineStrings, 3 Polygons Patch self.window.remove_file() self.select_file("polygon_inner.kml") assert len(self.window.patch.patches) == 5 # 5 Polygons Patch self.window.remove_file() self.select_file("Multilinestrings.kml") assert len(self.window.patch.patches) == 10 # 10 LineStrings Patch self.window.remove_file() self.select_file("geometry_collection.kml") assert len( self.window.patch.patches) == 3 # 1 Point, 1 Text, 1 Polygon Patch self.window.remove_file() self.select_file("World_Map.kml") assert len(self.window.patch.patches) == 292 # 292 Polygons Patch self.window.remove_file()
def __init__(self, parent=None, settings_dict=None): """ Arguments: parent -- Qt widget that is parent to this widget. settings_dict -- dictionary containing sideview options. """ _translate = QtCore.QCoreApplication.translate super(MSS_SV_OptionsDialog, self).__init__(parent) self.setupUi(self) default_settings_dict = { "vertical_extent": (1050, 180), "vertical_axis": "pressure", "flightlevels": [300, 320, 340], "draw_flightlevels": True, "draw_flighttrack": True, "fill_flighttrack": True, "label_flighttrack": True, "colour_ft_vertices": (0, 0, 0, 0), "colour_ft_waypoints": (0, 0, 0, 0), "colour_ft_fill": (0, 0, 0, 0), "draw_ceiling": True, "colour_ceiling": (0.1, 0.5, 0.1, 0), } suffixes = [' hpa', ' km', ' hft'] if settings_dict is not None: default_settings_dict.update(settings_dict) settings_dict = default_settings_dict self.setBotTopLimits(settings_dict["vertical_axis"]) self.sbPbot.setValue(settings_dict["vertical_extent"][0]) self.sbPtop.setValue(settings_dict["vertical_extent"][1]) flightlevels = settings_dict["flightlevels"] self.tableWidget.setRowCount(len(flightlevels)) flightlevels.sort() for i, level in enumerate(flightlevels): tableitem = QtWidgets.QTableWidgetItem(str(int(level))) self.tableWidget.setItem(i, 0, tableitem) for i in range(self.cbVerticalAxis.count()): if self.cbVerticalAxis.itemText(i) == settings_dict["vertical_axis"]: self.cbVerticalAxis.setCurrentIndex(i) self.sbPbot.setSuffix(_translate("SideViewOptionsDialog", suffixes[i])) self.sbPtop.setSuffix(_translate("SideViewOptionsDialog", suffixes[i])) self.cbDrawFlightLevels.setChecked(settings_dict["draw_flightlevels"]) self.cbDrawFlightTrack.setChecked(settings_dict["draw_flighttrack"]) self.cbFillFlightTrack.setChecked(settings_dict["fill_flighttrack"]) self.cbLabelFlightTrack.setChecked(settings_dict["label_flighttrack"]) self.cbDrawCeiling.setChecked(settings_dict["draw_ceiling"]) for button, ids in [(self.btFillColour, "colour_ft_fill"), (self.btWaypointsColour, "colour_ft_waypoints"), (self.btVerticesColour, "colour_ft_vertices"), (self.btCeilingColour, "colour_ceiling")]: palette = QtGui.QPalette(button.palette()) colour = QtGui.QColor() colour.setRgbF(*settings_dict[ids]) palette.setColor(QtGui.QPalette.Button, colour) button.setPalette(palette) # Connect colour button signals. self.cbVerticalAxis.view().pressed.connect(self.verticalunitsclicked) self.btFillColour.clicked.connect(functools.partial(self.setColour, "ft_fill")) self.btWaypointsColour.clicked.connect(functools.partial(self.setColour, "ft_waypoints")) self.btVerticesColour.clicked.connect(functools.partial(self.setColour, "ft_vertices")) self.btCeilingColour.clicked.connect(functools.partial(self.setColour, "ceiling")) self.btAdd.clicked.connect(self.addItem) self.btDelete.clicked.connect(self.deleteSelected) self.tableWidget.itemChanged.connect(self.itemChanged)
def __init__(self, parent=None, view=None): super(KMLOverlayControlWidget, self).__init__(parent) self.setupUi(self) self.view = view # canvas self.kml = None self.patch = None # patch refers to plottings on the map self.dict_files = { } # Dictionary of files added; key : patch , color , linewidth # Connect slots and signals. self.btSelectFile.clicked.connect(self.get_file) self.pushButton_remove.clicked.connect(self.remove_file) self.pushButton_select_all.clicked.connect(self.select_all) self.pushButton_unselect_all.clicked.connect(self.unselect_all) self.pushButton_merge.clicked.connect(self.merge_file) self.labelStatusBar.setText( "Status: Click on Add KML Files to get started.") self.dialog = CustomizeKMLWidget( self) # create object of dialog UI Box self.listWidget.itemDoubleClicked.connect( self.open_customize_kml_dialog) self.dialog.pushButton_colour.clicked.connect(self.select_color) self.listWidget.itemChanged.connect( self.load_file) # list of files in ListWidget self.settings_tag = "kmldock" settings = load_settings_qsettings( self.settings_tag, { "filename": "", "linewidth": 5, "colour": (0, 0, 0, 1), "saved_files": {} }) # initial settings self.directory_location = settings["filename"] self.dialog.dsb_linewidth.setValue(settings["linewidth"]) # Restore previously opened files if settings["saved_files"] is not None: delete_files = [] # list to store non-existing files self.dict_files = settings["saved_files"] for file in self.dict_files: if os.path.isfile(file) is True: self.create_list_item(file) else: delete_files.append(file) # add non-existent files to list logging.info(file + " does not exist in the directory anymore") for file in delete_files: del self.dict_files[ file] # remove non-existent files from dictionary self.load_file() palette = QtGui.QPalette(self.dialog.pushButton_colour.palette()) colour = QtGui.QColor() colour.setRgbF(*settings["colour"]) palette.setColor(QtGui.QPalette.Button, colour) self.dialog.pushButton_colour.setPalette( palette) # sets the last colour before closing KML Overlay self.dialog.dsb_linewidth.valueChanged.connect(self.select_linewidth)
def main(): try: prefix = os.environ["CONDA_DEFAULT_ENV"] except KeyError: prefix = "" app_prefix = prefix if prefix: app_prefix = "-{}".format(prefix) icon_hash = hashlib.md5('.'.join([__version__, app_prefix]).encode('utf-8')).hexdigest() parser = argparse.ArgumentParser() parser.add_argument("-v", "--version", help="show version", action="store_true", default=False) parser.add_argument("--debug", help="show debugging log messages on console", action="store_true", default=False) parser.add_argument("--logfile", help="Specify logfile location. Set to empty string to disable.", action="store", default=os.path.join(constants.MSS_CONFIG_PATH, "mss_pyui.log")) parser.add_argument("-m", "--menu", help="adds mss to menu", action="store_true", default=False) parser.add_argument("-d", "--deinstall", help="removes mss from menu", action="store_true", default=False) args = parser.parse_args() if args.version: print("***********************************************************************") print("\n Mission Support System (mss)\n") print("***********************************************************************") print("Documentation: http://mss.rtfd.io") print("Version:", __version__) sys.exit() setup_logging(args) if args.menu: # Experimental feature to get mss into application menu if platform.system() == "Linux": icon_size = '48x48' src_icon_path = icons(icon_size) icon_destination = constants.POSIX["icon_destination"].format(icon_size, icon_hash) dirname = os.path.dirname(icon_destination) if not os.path.exists(dirname): os.makedirs(dirname) shutil.copyfile(src_icon_path, icon_destination) desktop = constants.POSIX["desktop"] application_destination = constants.POSIX["application_destination"].format(app_prefix) dirname = os.path.dirname(application_destination) if not os.path.exists(dirname): os.makedirs(dirname) if prefix: prefix = "({})".format(prefix) desktop = desktop.format(prefix, os.path.join(sys.prefix, "bin", "mss"), icon_destination) with open(application_destination, 'w') as f: f.write(desktop) logging.info("menu entry created") sys.exit() if args.deinstall: application_destination = constants.POSIX["application_destination"].format(app_prefix) if os.path.exists(application_destination): os.remove(application_destination) icon_size = '48x48' icon_destination = constants.POSIX["icon_destination"].format(icon_size, icon_hash) if os.path.exists(icon_destination): os.remove(icon_destination) logging.info("menu entry removed") sys.exit() logging.info("MSS Version: %s", __version__) logging.info("Python Version: %s", sys.version) logging.info("Platform: %s (%s)", platform.platform(), platform.architecture()) logging.info("Launching user interface...") application = QtWidgets.QApplication(sys.argv) application.setWindowIcon(QtGui.QIcon(icons('128x128'))) application.setApplicationDisplayName("MSS") mainwindow = MSSMainWindow() mainwindow.create_new_flight_track() mainwindow.show() sys.exit(application.exec_())