class CaseList(QWidget): def __init__(self, facade: LibresFacade, notifier: ErtNotifier): self.facade = facade self.notifier = notifier QWidget.__init__(self) addHelpToWidget(self, "init/case_list") layout = QVBoxLayout() self._list = QListWidget(self) self._list.setMinimumHeight(100) self._list.setMaximumHeight(250) self._default_selection_mode = self._list.selectionMode() self.setSelectable(False) layout.addWidget(QLabel("Available cases:")) layout.addWidget(self._list) self._addRemoveWidget = AddRemoveWidget(self.addItem, self.removeItem, horizontal=True) self._addRemoveWidget.enableRemoveButton(False) layout.addWidget(self._addRemoveWidget) self._title = "New keyword" self._description = "Enter name of keyword:" self.setLayout(layout) notifier.ertChanged.connect(self.updateList) self.updateList() def setSelectable(self, selectable): if selectable: self._list.setSelectionMode(self._default_selection_mode) else: self._list.setSelectionMode(QAbstractItemView.NoSelection) def addItem(self): dialog = ValidatedDialog("New case", "Enter name of new case:", getAllCases(self.facade)) new_case_name = dialog.showAndTell() if not new_case_name == "": self.facade.select_or_create_new_case(new_case_name) self.notifier.ertChanged.emit() def removeItem(self): message = "Support for removal of items has not been implemented!" QMessageBox.information(self, "Not implemented!", message) def updateList(self): """Retrieves data from the model and inserts it into the list""" case_list = getAllCases(self.facade) self._list.clear() for case in case_list: self._list.addItem(case)
class MainWindow(QMainWindow): def selectFileToOpen(self): def getPreProcessingChoice(self, filename, filestructure): items = ("Choose the longest", "Merge all") item, okPressed = QInputDialog.getItem( self, "Multiple tracks/segments", "File '" + filename + "' contains more than one track/segment\n\n" + infos + "\nWhat to do?", items, 0, False) if okPressed and item: return items.index(item) else: return 0 # Try to recover the last used directory old_directory = self.settings.value("lastdirectory", str) # Check if the setting exists if old_directory is not None: # Check if it's not empty if old_directory: old_directory = old_directory else: old_directory = bombo.TRACKS_FOLDER else: old_directory = bombo.TRACKS_FOLDER # Open the dialog box fullfilename_list = QFileDialog.getOpenFileNames( self, 'Open .gpx', old_directory, "GPX files (*.gpx)") if os.environ['QT_API'] == 'pyqt': pass elif os.environ['QT_API'] == 'pyqt5': fullfilename_list = fullfilename_list[0] # Process every selected file for i, fullfilename in enumerate(fullfilename_list): # Process filename directory, filename = os.path.split(str(fullfilename)) filename, fileextension = os.path.splitext(filename) # Save the new directory in the application settings (it only # needs to be done once) if i == 0: # print "New directory to be saved: {}\n".format(directory) if os.environ['QT_API'] == 'pyqt': self.settings.setValue("lastdirectory", str(directory)) elif os.environ['QT_API'] == 'pyqt5': self.settings.setValue("lastdirectory", QtCore.QVariant(str(directory))) # Open file and inspect what's inside gpxraw, longest_traseg, Ntracks, Nsegments, infos = bombo.LoadGPX( fullfilename) # If there's more than one track or segment, ask how to proceed if (Ntracks > 1) or (Nsegments > 1): preprocessingchoice = getPreProcessingChoice( self, filename, infos) if preprocessingchoice == 0: preprocessedgpx = bombo.SelectOneTrackAndSegmentFromGPX( gpxraw, longest_traseg[0], longest_traseg[1]) listname = filename + " (longest)" elif preprocessingchoice == 1: preprocessedgpx = bombo.MergeAllTracksAndSegmentsFromGPX( gpxraw) listname = filename + " (merged)" else: preprocessedgpx = gpxraw listname = filename # Append the list of open GPX files using the next available color (that's the size of the list -1) self.gpxlist.append(preprocessedgpx) self.gpxnamelist.append(listname) newitem = QListWidgetItem(listname) newitem.setBackground( QtGui.QColor(self.palette[len(self.gpxlist) - 1])) self.tracklist.addItem(newitem) return def Go(self): if len(self.gpxselectedlist) > 0: # Temporarily change cursor QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) # Clear up global variables self.proc_coords = [] self.proc_measurements = [] self.proc_state_means = [] self.proc_state_vars = [] self.proc_new_coords = [] self.proc_new_gpx = [] self.proc_coords_to_plot = [] self.proc_coords_to_plot2 = [] self.proc_balloondata = [] # For every GPX file that is selected self.textWarningConsole.clear() for i, currentgpx in enumerate(self.gpxselectedlist): # Parse the GPX file gpx, coords, dinfos_before, warnings = bombo.ParseGPX( currentgpx, track_nr=0, segment_nr=0, use_srtm_elevation=bool(self.checkUseSRTM.isChecked())) self.textWarningConsole.append(warnings) # Kalman processing coords, measurements, state_means, state_vars, dinfos_during = bombo.ApplyKalmanFilter( coords, gpx, method=self.comboBoxProcessingMethod.currentIndex(), use_acceleration=self.checkUseAcceleration.isChecked(), extra_smooth=self.checkExtraSmooth.isChecked(), debug_plot=False) # Save data in GPX structure to compute speed and elevations new_coords, new_gpx, dinfos_after = bombo.SaveDataToCoordsAndGPX( coords, state_means) # Update GUI with the computed stats parent = QtGui.QStandardItem(self.gpxselectednamelist[i]) parent_beforeprocessing = QtGui.QStandardItem("Raw GPX stats") parent_beforeprocessing.appendRow([ QtGui.QStandardItem("Total distance"), QtGui.QStandardItem(dinfos_before['total_distance']) ]) parent_beforeprocessing_moving = QtGui.QStandardItem("Moving") parent_beforeprocessing_moving.appendRow([ QtGui.QStandardItem("Time"), QtGui.QStandardItem(dinfos_before['moving_time']) ]) parent_beforeprocessing_moving.appendRow([ QtGui.QStandardItem("Distance"), QtGui.QStandardItem(dinfos_before['moving_distance']) ]) parent_beforeprocessing.appendRow( parent_beforeprocessing_moving) parent_beforeprocessing_idle = QtGui.QStandardItem("Idle") parent_beforeprocessing_idle.appendRow([ QtGui.QStandardItem("Time"), QtGui.QStandardItem(dinfos_before['idle_time']) ]) parent_beforeprocessing_idle.appendRow([ QtGui.QStandardItem("Distance"), QtGui.QStandardItem(dinfos_before['idle_distance']) ]) parent_beforeprocessing.appendRow(parent_beforeprocessing_idle) parent_beforeprocessing.appendRow([ QtGui.QStandardItem("Elevation"), QtGui.QStandardItem(dinfos_before['elevation']) ]) parent_beforeprocessing.appendRow([ QtGui.QStandardItem("Climb"), QtGui.QStandardItem(dinfos_before['climb']) ]) parent.appendRow(parent_beforeprocessing) parent.appendRow([ QtGui.QStandardItem("Samples"), QtGui.QStandardItem(dinfos_during['nsamples']) ]) parent.appendRow([ QtGui.QStandardItem("Total distance"), QtGui.QStandardItem(dinfos_after['total_distance']) ]) parent_moving = QtGui.QStandardItem("Moving") parent_moving.appendRow([ QtGui.QStandardItem("Time"), QtGui.QStandardItem(dinfos_after['moving_time']) ]) parent_moving.appendRow([ QtGui.QStandardItem("Distance"), QtGui.QStandardItem(dinfos_after['moving_distance']) ]) parent.appendRow(parent_moving) parent_idle = QtGui.QStandardItem("Idle") parent_idle.appendRow([ QtGui.QStandardItem("Time"), QtGui.QStandardItem(dinfos_after['idle_time']) ]) parent_idle.appendRow([ QtGui.QStandardItem("Distance"), QtGui.QStandardItem(dinfos_after['idle_distance']) ]) parent.appendRow(parent_idle) parent.appendRow([ QtGui.QStandardItem("Elevation"), QtGui.QStandardItem(dinfos_after['elevation']) ]) parent.appendRow([ QtGui.QStandardItem("Climb"), QtGui.QStandardItem(dinfos_after['climb']) ]) self.treemodel.appendRow(parent) # Create balloondata for the html plot balloondata = { 'distance': np.cumsum( bombo.HaversineDistance(np.asarray(new_coords['lat']), np.asarray( new_coords['lon']))), 'elevation': np.asarray(new_coords['ele']), 'speed': None } # Create extra data for the html plot (fully implemented in bombo, not here) """ data = np.ones((len(lat_cleaned),2)) data[:,0] = h_filtered / np.max(h_filtered) * 0.0004 data[:,1] = np.hstack((np.asarray([0]), speed_h)) / np.max(np.hstack((np.asarray([0]), speed_h))) * 0.0004 tangentdata = {'data': data, 'sides': (0, 1), 'palette': ('blue','red')} """ # Save relevant output in global variables self.proc_coords.append(coords) self.proc_measurements.append(measurements) self.proc_state_means.append(state_means) self.proc_state_vars.append(state_vars) self.proc_new_coords.append(new_coords) self.proc_new_gpx.append(new_gpx) self.proc_coords_to_plot.append( np.vstack((new_coords['lat'], new_coords['lon'])).T) self.proc_coords_to_plot2.append( np.vstack((coords['lat'], coords['lon'])).T) self.proc_balloondata.append(balloondata) # Restore original cursor QApplication.restoreOverrideCursor() # Generate embedded plots if len(self.gpxselectedlist) == 1: self.plotEmbeddedElevationAndSpeed.update_figure( measurements, state_means, new_gpx.tracks[0].segments[0]) self.plotEmbeddedDetails.update_figure( measurements, state_means, state_vars, new_gpx.tracks[0].segments[0]) else: # Commentato per adesso # self.plotEmbeddedElevationAndSpeed.update_figure_multiple_tracks(self.proc_measurements, self.proc_state_means, self.proc_new_gpx) self.plotEmbeddedElevationAndSpeed.clear_figure() self.plotEmbeddedDetails.clear_figure() # Generate html plot, if only one track is selected, proceed with the complete output, otherwise just plot the traces if len(self.gpxselectedlist) is 1: bombo.PlotOnMap( coords_array_list=self.proc_coords_to_plot, coords_array2_list=self.proc_coords_to_plot2, coords_palette=self.selectedpalette, tangentdata=None, balloondata_list=self.proc_balloondata, rdp_reduction=self.checkUseRDP.isChecked(), showmap=bool(self.check2DMapInExternalBrowser.isChecked())) else: bombo.PlotOnMap( coords_array_list=self.proc_coords_to_plot, coords_array2_list=None, coords_palette=self.selectedpalette, tangentdata=None, balloondata_list=self.proc_balloondata, rdp_reduction=self.checkUseRDP.isChecked(), showmap=bool(self.check2DMapInExternalBrowser.isChecked())) self.map2d.load(QtCore.QUrl(bombo.MAP_2D_FILENAME)) self.map2d.show() # Generate 3D plot, only with one track for the moment if len(self.gpxselectedlist) == 1: if self.check3DMapSelection.isChecked(): tile_selection = 'auto' else: tile_selection = self.text3DMapName.text() terrain, track, warnings = bombo.Generate3DMap( new_coords['lat'], new_coords['lon'], tile_selection=tile_selection, margin=self.spinbox3DMargin.value(), elevation_scale=self.spinbox3DElevationScale.value(), mapping='coords', use_osm_texture=True, texture_type='osm', texture_zoom=self.spinbox3DOSMZoom.value(), texture_invert=self.check3DOSMInvert.isChecked(), use_proxy=self.use_proxy, proxy_data=self.proxy_config, verbose=False) self.textWarningConsole.append(warnings) if terrain is not None: self.map3d.update_plot(terrain, track) else: self.textWarningConsole.setText( "You need to open a .gpx file before!") return def PlotSpecificAreaDialog(self): def PlotSpecificArea(): # Save coordinates for the next time if os.environ['QT_API'] == 'pyqt': self.settings.setValue("last_point_coord_lat", self.spinboxLatDec.value()) self.settings.setValue("last_point_coord_lon", self.spinboxLonDec.value()) elif os.environ['QT_API'] == 'pyqt5': self.settings.setValue( "last_point_coord_lat", QtCore.QVariant(self.spinboxLatDec.value())) self.settings.setValue( "last_point_coord_lon", QtCore.QVariant(self.spinboxLonDec.value())) # Select the 3D Map tab self.tab.setCurrentIndex(2) # Plot if self.check3DMapSelection.isChecked(): tile_selection = 'auto' else: tile_selection = self.text3DMapName.text() terrain, track, warnings = bombo.Generate3DMap( [self.spinboxLatDec.value()], [self.spinboxLonDec.value()], tile_selection=tile_selection, margin=self.spinbox3DMargin.value(), elevation_scale=self.spinbox3DElevationScale.value(), mapping='coords', use_osm_texture=True, texture_type='osm', texture_zoom=self.spinbox3DOSMZoom.value(), texture_invert=self.check3DOSMInvert.isChecked(), use_proxy=self.use_proxy, proxy_data=self.proxy_config, verbose=False) self.textWarningConsole.append(warnings) if terrain is not None: self.map3d.update_plot(terrain, track) d.done(0) def Convert(): try: dd = bombo.parse_dms(self.textLatLonGMS.text()) self.spinboxLatDec.setValue(dd[0]) self.spinboxLonDec.setValue(dd[1]) except: pass d = QDialog() grid = QGridLayout() hBox_coordsGMS = QHBoxLayout() hBox_coordsGMS.setSpacing(5) label = QLabel('Coordinates (gms)') grid.addWidget(label, 0, 0) self.textLatLonGMS = QLineEdit() self.textLatLonGMS.setText("") grid.addWidget(self.textLatLonGMS, 0, 1, 1, 2) button1 = QPushButton("Convert to decimal") button1.clicked.connect(Convert) grid.addWidget(button1, 0, 3) label = QLabel('Coordinates (decimal)') grid.addWidget(label, 1, 0) self.spinboxLatDec = QDoubleSpinBox() self.spinboxLatDec.setRange(-90, +90) self.spinboxLatDec.setSingleStep(0.0000001) self.spinboxLatDec.setDecimals(7) grid.addWidget(self.spinboxLatDec, 1, 1) self.spinboxLonDec = QDoubleSpinBox() self.spinboxLonDec.setRange(-180, +180) self.spinboxLonDec.setSingleStep(0.0000001) self.spinboxLonDec.setDecimals(7) grid.addWidget(self.spinboxLonDec, 1, 2) # Try to recover the last used points try: old_lat = self.settings.value("last_point_coord_lat", type=float) old_lon = self.settings.value("last_point_coord_lon", type=float) self.spinboxLatDec.setValue(old_lat) self.spinboxLonDec.setValue(old_lon) except: # Coordinates of Mt. Rinjani in Indonesia self.spinboxLatDec.setValue(-8.4166000) self.spinboxLonDec.setValue(116.4666000) button2 = QPushButton("Show 3D map") button2.clicked.connect(PlotSpecificArea) grid.addWidget(button2, 1, 3) d.setWindowTitle("Show point on 3D map") d.setLayout(grid) d.setWindowModality(QtCore.Qt.ApplicationModal) d.exec_() def ProxyDialog(self): def SetProxy(): self.use_proxy = bool(self.checkUseProxy.isChecked()) self.proxy_config = self.textProxyConfig.text() if os.environ['QT_API'] == 'pyqt': self.settings.setValue("use_proxy", self.use_proxy) self.settings.setValue("proxy_config", str(self.proxy_config)) elif os.environ['QT_API'] == 'pyqt5': self.settings.setValue("use_proxy", QtCore.QVariant(self.use_proxy)) self.settings.setValue("proxy_config", QtCore.QVariant(str(self.proxy_config))) d.done(0) d = QDialog() box = QVBoxLayout() hBox_proxy = QHBoxLayout() hBox_proxy.setSpacing(5) label = QLabel('Proxy') hBox_proxy.addWidget(label) self.textProxyConfig = QLineEdit() try: self.textProxyConfig.setText( self.settings.value('proxy_config', str)) except: self.textProxyConfig.setText(bombo.PROXY_DATA) self.textProxyConfig.setMinimumWidth(200) hBox_proxy.addWidget(self.textProxyConfig) box.addLayout(hBox_proxy) self.checkUseProxy = QCheckBox("Use proxy") try: self.checkUseProxy.setChecked( self.settings.value('use_proxy', bool)) except: self.checkUseProxy.setChecked(bool(bombo.USE_PROXY)) box.addWidget(self.checkUseProxy) button = QPushButton("Save configuration") button.clicked.connect(SetProxy) box.addWidget(button) d.setWindowTitle("Proxy configuration") d.setLayout(box) d.setWindowModality(QtCore.Qt.ApplicationModal) d.exec_() def __init__(self, parent=None): super(MainWindow, self).__init__() self.initVariables() self.initUI() def initVariables(self): self.gpxlist = list() self.gpxnamelist = list() self.gpxselectedlist = list() self.gpxselectednamelist = list() self.palette = bombo.GeneratePalette(N=10) * 5 # replicated 5 times #self.palette = ["#0000FF", "#00FF00", "#00FFFF", "#FF0000", "#FF00FF", "#FFFF00", "#FFFFFF"] # test palette self.selectedpalette = list() self.proc_coords = list() self.proc_measurements = list() self.proc_state_means = list() self.proc_state_vars = list() self.proc_new_coords = list() self.proc_new_gpx = list() self.proc_coords_to_plot = list() self.proc_coords_to_plot2 = list() self.proc_balloondata = list() def initUI(self): def selection_changed(): # Retrieve selected items # selecteditems = self.tracklist.selectedItems() selectedindexes = self.tracklist.selectedIndexes() # Adding the selected items to the processing list self.gpxselectedlist[:] = [] self.gpxselectednamelist[:] = [] self.selectedpalette[:] = [] for i in selectedindexes: # print str(i.text()) self.gpxselectedlist.append(self.gpxlist[i.row()]) self.gpxselectednamelist.append(self.gpxnamelist[i.row()]) self.selectedpalette.append(self.palette[i.row()]) def ClearStats(): """ # Some other code that could be used in the future index = self.treemodel.indexFromItem(parent1) self.tree.expand(index) selmod = self.tree.selectionModel() index2 = self.treemodel.indexFromItem(child2) selmod.select(index2, QtCore.QItemSelectionModel.Select|QtCore.QItemSelectionModel.Rows) root = self.treemodel.invisibleRootItem() (item.parent() or root).removeChild(item) """ # Returns a list of indexes. In our case, for each row there are 2 indexes, cos there are 2 columns. for index in self.tree.selectedIndexes(): # Consider only the first columns if index.column() == 0: # Need to check if it's a top item (i.e. track), otherwise if a subitem (i.e. distance or time) is selected, the result might be buggy parent = index.parent() parent_item = self.treemodel.itemFromIndex(parent) if parent_item is None: self.treemodel.removeRow(index.row()) # Application Settings QtCore.QCoreApplication.setOrganizationName("Ste") QtCore.QCoreApplication.setOrganizationDomain( "https://github.com/stesalati/sport/") QtCore.QCoreApplication.setApplicationName("TrackAnalyser") # Config settings self.settings = QtCore.QSettings(self) # Proxy settings try: self.use_proxy = self.settings.value('use_proxy', bool) self.proxy_config = self.settings.value('proxy_config', str) except: self.use_proxy = bombo.USE_PROXY self.proxy_config = bombo.PROXY_DATA # Actions openfile = QAction(QtGui.QIcon("icons/openfile.png"), "Open .gpx", self) openfile.setShortcut("Ctrl+O") openfile.setStatusTip("Open file") openfile.triggered.connect(self.selectFileToOpen) go = QAction(QtGui.QIcon("icons/go.png"), "Go!", self) go.setShortcut("Ctrl+R") go.setStatusTip("Run analysis") go.triggered.connect(self.Go) clearstats = QAction(QtGui.QIcon("icons/clear.png"), "Clear stats", self) clearstats.setShortcut("Ctrl+C") clearstats.setStatusTip("Clear stats") clearstats.triggered.connect(ClearStats) sep1 = QAction(self) sep1.setSeparator(True) showpoint = QAction(QtGui.QIcon("icons/point.png"), "Show point", self) showpoint.setShortcut("Ctrl+P") showpoint.setStatusTip("Show point") showpoint.triggered.connect(self.PlotSpecificAreaDialog) sep2 = QAction(self) sep2.setSeparator(True) quitapp = QAction(QtGui.QIcon("icons/quit.png"), "Quit", self) quitapp.setShortcut("Ctrl+Q") quitapp.setStatusTip("Quit application") quitapp.triggered.connect(qApp.quit) configs = QAction(QtGui.QIcon("icons/configs.png"), "Configs", self) configs.setStatusTip("Configs") configs.triggered.connect(self.ProxyDialog) # Menubar mainMenu = self.menuBar() configMenu = mainMenu.addMenu('&Config') configMenu.addAction(configs) # Toolbar toolbar = self.addToolBar('My tools') toolbar.addAction(openfile) toolbar.addAction(go) toolbar.addAction(clearstats) toolbar.addAction(sep1) toolbar.addAction(showpoint) toolbar.addAction(sep2) toolbar.addAction(quitapp) toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) toolbar.setIconSize(QtCore.QSize(30, 30)) # Status bar self.statusBar().show() # Main widget (everything that's not toolbar, statusbar or menubar must be in this widget) self.scatola = QWidget() # Main horizontal impagination hBox = QHBoxLayout() hBox.setSpacing(5) # Vertical left column vBox_left = QVBoxLayout() vBox_left.setSpacing(5) # 1st vertical box, a list self.tracklist = QListWidget() vBox_left.addWidget(self.tracklist) self.tracklist.setSelectionMode(QAbstractItemView.ExtendedSelection) self.tracklist.itemSelectionChanged.connect(selection_changed) self.tracklist.setMaximumHeight(120) # 2nd vertical box, containing several horizontal boxes, one for each setting vBox2 = QVBoxLayout() vBox2.setSpacing(5) # Just the group label labelSettings = QLabel('Settings') vBox2.addWidget(labelSettings) # Use/don't use corrected altitude self.checkUseSRTM = QCheckBox( "Use SRTM corrected elevation (needs Internet)") self.checkUseSRTM.setChecked(False) vBox2.addWidget(self.checkUseSRTM) # Choose processing method + use/don't use acceleration hBoxProcessingMethod = QHBoxLayout() labelProcessingMethod = QLabel('Processing method') hBoxProcessingMethod.addWidget(labelProcessingMethod) self.comboBoxProcessingMethod = QComboBox() self.comboBoxProcessingMethod.addItem("Just use available data") self.comboBoxProcessingMethod.addItem( "Fill all gaps at T=1s (resample)") self.comboBoxProcessingMethod.addItem("Fill only smaller gaps at T=1s") hBoxProcessingMethod.addWidget(self.comboBoxProcessingMethod) self.checkUseAcceleration = QCheckBox("Use acceleration") self.checkUseAcceleration.setChecked(False) hBoxProcessingMethod.addWidget(self.checkUseAcceleration) vBox2.addLayout(hBoxProcessingMethod) # Use/don't use variance smooth self.checkExtraSmooth = QCheckBox("Extra smooth") self.checkExtraSmooth.setChecked(False) vBox2.addWidget(self.checkExtraSmooth) # 2D interactive map settings hBox2DMap = QHBoxLayout() self.checkUseRDP = QCheckBox("Use RDP to reduce points") self.checkUseRDP.setChecked(False) hBox2DMap.addWidget(self.checkUseRDP) self.check2DMapInExternalBrowser = QCheckBox( "Show in external browser") self.check2DMapInExternalBrowser.setChecked(False) hBox2DMap.addWidget(self.check2DMapInExternalBrowser) vBox2.addLayout(hBox2DMap) # Settings for the 3D map line3DViewSettings = QFrame() #line3DViewSettings.setGeometry(QtCore.QRect(320, 150, 118, 3)) line3DViewSettings.setFrameShape(QFrame.HLine) line3DViewSettings.setFrameShadow(QFrame.Sunken) vBox2.addWidget(line3DViewSettings) label3DViewSettings = QLabel('3D view settings') vBox2.addWidget(label3DViewSettings) hBox3DMapSelection = QHBoxLayout() self.check3DMapSelection = QCheckBox( "Select elevation tiles automatically, otherwise") self.check3DMapSelection.setChecked(True) hBox3DMapSelection.addWidget(self.check3DMapSelection) self.text3DMapName = QLineEdit() self.text3DMapName.setText("Iceland.tif") hBox3DMapSelection.addWidget(self.text3DMapName) vBox2.addLayout(hBox3DMapSelection) hBox3D = QHBoxLayout() label3DMargin = QLabel('Margin') hBox3D.addWidget(label3DMargin) self.spinbox3DMargin = QSpinBox() self.spinbox3DMargin.setRange(50, 1000) self.spinbox3DMargin.setValue(100) self.spinbox3DMargin.setSingleStep(10) hBox3D.addWidget(self.spinbox3DMargin) labelSpace = QLabel(' ') hBox3D.addWidget(labelSpace) label3DElevationScale = QLabel('Elev. scale') hBox3D.addWidget(label3DElevationScale) self.spinbox3DElevationScale = QDoubleSpinBox() self.spinbox3DElevationScale.setRange(1, 50) self.spinbox3DElevationScale.setSingleStep(0.1) hBox3D.addWidget(self.spinbox3DElevationScale) hBox3D.addWidget(labelSpace) label3DOSMZoom = QLabel('Zoom') hBox3D.addWidget(label3DOSMZoom) self.spinbox3DOSMZoom = QSpinBox() self.spinbox3DOSMZoom.setRange(8, 15) self.spinbox3DOSMZoom.setValue(13) self.spinbox3DOSMZoom.setSingleStep(1) hBox3D.addWidget(self.spinbox3DOSMZoom) hBox3D.addWidget(labelSpace) self.check3DOSMInvert = QCheckBox("Invert") self.check3DOSMInvert.setChecked(False) hBox3D.addWidget(self.check3DOSMInvert) vBox2.addLayout(hBox3D) vBox_left.addLayout(vBox2) # 3rd stats tree lineTree = QFrame() lineTree.setFrameShape(QFrame.HLine) lineTree.setFrameShadow(QFrame.Sunken) vBox2.addWidget(lineTree) labelTree = QLabel('Track stats') vBox2.addWidget(labelTree) self.tree = QTreeView() self.tree.setSelectionBehavior(QAbstractItemView.SelectRows) self.treemodel = QtGui.QStandardItemModel() self.treemodel.setHorizontalHeaderLabels(['Name', 'Value']) self.tree.setModel(self.treemodel) self.tree.setUniformRowHeights(True) self.tree.setColumnWidth(0, 200) vBox_left.addWidget(self.tree) # 4th text, containing text messages/errors self.textWarningConsole = QTextEdit() self.textWarningConsole.setReadOnly(True) self.textWarningConsole.setFont(QtGui.QFont("Courier New", FONTSIZE)) self.textWarningConsole.clear() self.textWarningConsole.setMaximumHeight(50) vBox_left.addWidget(self.textWarningConsole) # I put "vBox_left" inside a widget and then the widget inside "hBox" # instead of just doing "hBox.addLayout(vBox_left) so I can set its # maximum width. vBox_left_widget = QWidget() vBox_left_widget.setLayout(vBox_left) vBox_left_widget.setMinimumWidth(400) vBox_left_widget.setMaximumWidth(500) hBox.addWidget(vBox_left_widget) # Vertical right column self.tab = QTabWidget() # Tab 1: Summary: elevation and speed tab1 = QWidget() # The tab layout vBox_tab = QVBoxLayout() vBox_tab.setSpacing(5) # Plot area self.plotEmbeddedElevationAndSpeed = EmbeddedPlot_ElevationSpeed( width=5, height=4, dpi=100) self.plotEmbeddedElevationAndSpeed.setMinimumWidth(800) # Add toolbar to the plot self.mpl_toolbar1 = NavigationToolbar( self.plotEmbeddedElevationAndSpeed, self.scatola) # Add widgets to the layout vBox_tab.addWidget(self.plotEmbeddedElevationAndSpeed) vBox_tab.addWidget(self.mpl_toolbar1) # Associate the layout to the tab tab1.setLayout(vBox_tab) # Tab 2: html 2D map tab2 = QWidget() # The tab layout vBox_tab = QVBoxLayout() vBox_tab.setSpacing(5) # Area self.map2d = QtWebEngineWidgets.QWebEngineView() # Add widgets to the layout vBox_tab.addWidget(self.map2d) # Associate the layout to the tab tab2.setLayout(vBox_tab) # Tab 3: 3D plot tab3 = QWidget() # The tab layout vBox_tab = QVBoxLayout() vBox_tab.setSpacing(5) # Area self.map3d = MayaviQWidget() # Add widgets to the layout vBox_tab.addWidget(self.map3d) # Associate the layout to the tab tab3.setLayout(vBox_tab) # Tab 4: Details tab4 = QWidget() # The tab layout vBox_tab = QVBoxLayout() vBox_tab.setSpacing(5) # Plot area self.plotEmbeddedDetails = EmbeddedPlot_Details(width=5, height=4, dpi=100) self.plotEmbeddedDetails.setMinimumWidth(800) # Add toolbar to the plot self.mpl_toolbar2 = NavigationToolbar(self.plotEmbeddedDetails, self.scatola) # Add widgets to the layout vBox_tab.addWidget(self.plotEmbeddedDetails) vBox_tab.addWidget(self.mpl_toolbar2) # Associate the layout to the tab tab4.setLayout(vBox_tab) # Associate tabs self.tab.addTab(tab1, "Summary") self.tab.addTab(tab2, "2D Map") self.tab.addTab(tab3, "3D Map") self.tab.addTab(tab4, "Details") hBox.addWidget(self.tab) # Setting hBox as main box self.scatola.setLayout(hBox) self.setCentralWidget(self.scatola) # Application settings self.setWindowTitle('TrackAnalyser') self.setWindowIcon((QtGui.QIcon('icons/app.png'))) self.setGeometry(100, 100, 1200, 700) self.show()
class BibleCollectionDialog(QDialog): def __init__(self, parent): super().__init__() self.setWindowTitle(config.thisTranslation["bibleCollections"]) self.setMinimumSize(680, 500) self.selectedCollection = None self.settingBibles = False self.bibles = self.getBibles() self.setupUI() self.parent = parent def setupUI(self): mainLayout = QVBoxLayout() title = QLabel(config.thisTranslation["bibleCollections"]) mainLayout.addWidget(title) self.collectionsLayout = QVBoxLayout() self.collectionsList = QListWidget() self.collectionsList.setMaximumHeight(90) self.collectionsLayout.addWidget(self.collectionsList) mainLayout.addLayout(self.collectionsLayout) self.showListOfCollections() buttonsLayout = QHBoxLayout() addButton = QPushButton(config.thisTranslation["add"]) addButton.clicked.connect(self.addNewCollection) buttonsLayout.addWidget(addButton) removeButton = QPushButton(config.thisTranslation["remove"]) removeButton.clicked.connect(self.removeCollection) buttonsLayout.addWidget(removeButton) renameButton = QPushButton(config.thisTranslation["rename"]) renameButton.clicked.connect(self.renameCollection) buttonsLayout.addWidget(renameButton) buttonsLayout.addStretch() mainLayout.addLayout(buttonsLayout) self.biblesTable = QTableView() self.biblesTable.setEnabled(False) self.biblesTable.setEditTriggers(QAbstractItemView.NoEditTriggers) self.biblesTable.setSortingEnabled(True) self.dataViewModel = QStandardItemModel(self.biblesTable) self.biblesTable.setModel(self.dataViewModel) self.loadBibleSelection() self.dataViewModel.itemChanged.connect(self.bibleSelectionChanged) mainLayout.addWidget(self.biblesTable) buttonLayout = QHBoxLayout() button = QPushButton(config.thisTranslation["close"]) button.clicked.connect(self.reloadControlPanel) button.clicked.connect(self.close) buttonLayout.addWidget(button) mainLayout.addLayout(buttonLayout) self.setLayout(mainLayout) def showListOfCollections(self): self.collectionsList.clear() if len(config.bibleCollections) > 0: for collection in sorted(config.bibleCollections.keys()): showBibleSelection = QRadioButton() showBibleSelection.setChecked(False) self.collectionsList.itemClicked.connect(self.selectCollection) self.collectionsList.addItem(collection) else: self.collectionsList.addItem("[No collection defined]") def addNewCollection(self): name, ok = QInputDialog.getText(self, 'Collection', 'Collection name:') if ok and len(name) > 0 and name != "All": config.bibleCollections[name] = {} self.showListOfCollections() self.biblesTable.setEnabled(False) def removeCollection(self): config.bibleCollections.pop(self.selectedCollection, None) self.showListOfCollections() self.biblesTable.setEnabled(False) def renameCollection(self): name, ok = QInputDialog.getText(self, 'Collection', 'Collection name:', text=self.selectedCollection) if ok and len(name) > 0 and name != "All": biblesInCollection = config.bibleCollections[ self.selectedCollection] config.bibleCollections.pop(self.selectedCollection, None) self.selectedCollection = name config.bibleCollections[name] = biblesInCollection self.showListOfCollections() self.biblesTable.setEnabled(False) def getBibles(self): from db.BiblesSqlite import BiblesSqlite from db.BiblesSqlite import Bible bibles = BiblesSqlite().getBibleList() bibleInfo = [] for bible in bibles: description = Bible(bible).bibleInfo() bibleInfo.append((bible, description)) return bibleInfo def selectCollection(self, item): self.selectedCollection = item.text() self.biblesTable.setEnabled(True) self.loadBibleSelection() def bibleSelectionChanged(self, item): if not self.settingBibles: if self.selectedCollection is not None: text = item.text() biblesInCollection = config.bibleCollections[ self.selectedCollection] if len(biblesInCollection) == 0: biblesInCollection = [] if text in biblesInCollection: biblesInCollection.remove(text) else: biblesInCollection.append(text) config.bibleCollections[ self.selectedCollection] = biblesInCollection def loadBibleSelection(self): self.settingBibles = True self.dataViewModel.clear() biblesInCollection = [] if self.selectedCollection is not None: biblesInCollection = config.bibleCollections[ self.selectedCollection] rowCount = 0 for bible, description in self.bibles: item = QStandardItem(bible) item.setToolTip(bible) item.setCheckable(True) if bible in biblesInCollection: item.setCheckState(Qt.Checked) self.dataViewModel.setItem(rowCount, 0, item) item = QStandardItem(description) self.dataViewModel.setItem(rowCount, 1, item) rowCount += 1 self.dataViewModel.setHorizontalHeaderLabels([ config.thisTranslation["bible"], config.thisTranslation["description"] ]) self.biblesTable.resizeColumnsToContents() self.settingBibles = False def reloadControlPanel(self): self.parent.reloadControlPanel(False)
class DownloadBibleMp3Dialog(QDialog): def __init__(self, parent): super().__init__() self.bibles = { "BBE (British accent)": ("BBE", "otseng/UniqueBible_MP3_BBE_british", "british"), "KJV (American accent)": ("KJV", "otseng/UniqueBible_MP3_KJV", "default"), "KJV (American soft music)": ("KJV", "otseng/UniqueBible_MP3_KJV_soft_music", "soft-music"), "NHEB (Indian accent)": ("NHEB", "otseng/UniqueBible_MP3_NHEB_indian", "indian"), "WEB (American accent)": ("WEB", "otseng/UniqueBible_MP3_WEB", "default"), "CUV (Chinese)": ("CUV", "otseng/UniqueBible_MP3_CUV", "default"), "HHBD (Hindi)": ("HHBD", "otseng/UniqueBible_MP3_HHBD", "default"), "RVA (Spanish)": ("RVA", "otseng/UniqueBible_MP3_RVA", "default"), "TR (Modern Greek)": ("TR", "otseng/UniqueBible_MP3_TR", "modern"), } self.parent = parent self.setWindowTitle(config.thisTranslation["gitHubBibleMp3Files"]) self.setMinimumSize(150, 450) self.selectedRendition = None self.selectedText = None self.selectedRepo = None self.selectedDirectory = None self.settingBibles = False self.thread = None self.setupUI() def setupUI(self): mainLayout = QVBoxLayout() title = QLabel(config.thisTranslation["gitHubBibleMp3Files"]) mainLayout.addWidget(title) self.versionsLayout = QVBoxLayout() self.renditionsList = QListWidget() self.renditionsList.itemClicked.connect(self.selectItem) for rendition in self.bibles.keys(): self.renditionsList.addItem(rendition) self.renditionsList.setMaximumHeight(100) self.versionsLayout.addWidget(self.renditionsList) mainLayout.addLayout(self.versionsLayout) self.downloadTable = QTableView() self.downloadTable.setEnabled(False) self.downloadTable.setFocusPolicy(Qt.StrongFocus) self.downloadTable.setEditTriggers(QAbstractItemView.NoEditTriggers) self.downloadTable.setSortingEnabled(True) self.dataViewModel = QStandardItemModel(self.downloadTable) self.downloadTable.setModel(self.dataViewModel) mainLayout.addWidget(self.downloadTable) buttonsLayout = QHBoxLayout() selectAllButton = QPushButton(config.thisTranslation["selectAll"]) selectAllButton.setFocusPolicy(Qt.StrongFocus) selectAllButton.clicked.connect(self.selectAll) buttonsLayout.addWidget(selectAllButton) selectNoneButton = QPushButton(config.thisTranslation["selectNone"]) selectNoneButton.setFocusPolicy(Qt.StrongFocus) selectNoneButton.clicked.connect(self.selectNone) buttonsLayout.addWidget(selectNoneButton) otButton = QPushButton("1-39") otButton.setFocusPolicy(Qt.StrongFocus) otButton.clicked.connect(self.selectOT) buttonsLayout.addWidget(otButton) ntButton = QPushButton("40-66") ntButton.setFocusPolicy(Qt.StrongFocus) ntButton.clicked.connect(self.selectNT) buttonsLayout.addWidget(ntButton) # buttonsLayout.addStretch() mainLayout.addLayout(buttonsLayout) self.downloadButton = QPushButton(config.thisTranslation["download"]) self.downloadButton.setFocusPolicy(Qt.StrongFocus) self.downloadButton.setAutoDefault(True) self.downloadButton.setFocus() self.downloadButton.clicked.connect(self.download) mainLayout.addWidget(self.downloadButton) self.status = QLabel("") mainLayout.addWidget(self.status) buttonLayout = QHBoxLayout() self.closeButton = QPushButton(config.thisTranslation["close"]) self.closeButton.setFocusPolicy(Qt.StrongFocus) self.closeButton.clicked.connect(self.closeDialog) buttonLayout.addWidget(self.closeButton) mainLayout.addLayout(buttonLayout) self.setLayout(mainLayout) self.renditionsList.item(0).setSelected(True) bible = self.renditionsList.item(0).text() self.selectRendition(bible) self.downloadButton.setDefault(True) QTimer.singleShot(0, self.downloadButton.setFocus) def selectItem(self, item): self.selectRendition(item.text()) def selectRendition(self, rendition): from util.GithubUtil import GithubUtil self.selectedRendition = rendition self.downloadTable.setEnabled(True) self.selectedText, self.selectedRepo, self.selectedDirectory = self.bibles[ self.selectedRendition] self.github = GithubUtil(self.selectedRepo) self.repoData = self.github.getRepoData() self.settingBibles = True self.dataViewModel.clear() rowCount = 0 for file in self.repoData.keys(): if len(str(file)) > 3: engFullBookName = file[3:] else: engFullBookName = BibleBooks().eng[str(int(file))][1] item = QStandardItem(file[:3].strip()) folder = os.path.join("audio", "bibles", self.selectedText, self.selectedDirectory, file) folderWithName = os.path.join("audio", "bibles", self.selectedText, self.selectedDirectory, file + " " + engFullBookName) if os.path.exists(folder) or os.path.exists(folderWithName): item.setCheckable(False) item.setCheckState(Qt.Unchecked) item.setEnabled(False) else: item.setCheckable(True) item.setCheckState(Qt.Checked) item.setEnabled(True) self.dataViewModel.setItem(rowCount, 0, item) item = QStandardItem(engFullBookName) self.dataViewModel.setItem(rowCount, 1, item) if os.path.exists(folder) or os.path.exists(folderWithName): item = QStandardItem("Installed") self.dataViewModel.setItem(rowCount, 2, item) else: item = QStandardItem("") self.dataViewModel.setItem(rowCount, 2, item) rowCount += 1 self.dataViewModel.setHorizontalHeaderLabels([ config.thisTranslation["menu_book"], config.thisTranslation["name"], "" ]) self.downloadTable.setColumnWidth(0, 90) self.downloadTable.setColumnWidth(1, 125) self.downloadTable.setColumnWidth(2, 125) # self.downloadTable.resizeColumnsToContents() self.settingBibles = False def selectAll(self): for index in range(self.dataViewModel.rowCount()): item = self.dataViewModel.item(index) if item.isEnabled(): item.setCheckState(Qt.Checked) def selectNone(self): for index in range(self.dataViewModel.rowCount()): item = self.dataViewModel.item(index) item.setCheckState(Qt.Unchecked) def selectOT(self): for index in range(self.dataViewModel.rowCount()): item = self.dataViewModel.item(index) bookNum = int(item.text()) if bookNum <= 39: if item.isEnabled(): item.setCheckState(Qt.Checked) else: item.setCheckState(Qt.Unchecked) else: item.setCheckState(Qt.Unchecked) def selectNT(self): for index in range(self.dataViewModel.rowCount()): item = self.dataViewModel.item(index) bookNum = int(item.text()) if bookNum >= 40: if item.isEnabled(): item.setCheckState(Qt.Checked) else: item.setCheckState(Qt.Unchecked) else: item.setCheckState(Qt.Unchecked) def download(self): self.downloadButton.setEnabled(False) self.setStatus(config.thisTranslation["message_installing"]) self.closeButton.setEnabled(False) folder = os.path.join("audio", "bibles") if not os.path.exists(folder): os.mkdir(folder) folder = os.path.join("audio", "bibles", self.selectedText) if not os.path.exists(folder): os.mkdir(folder) folder = os.path.join("audio", "bibles", self.selectedText, self.selectedDirectory) if not os.path.exists(folder): os.mkdir(folder) self.thread = QThread() self.worker = DownloadFromGitHub(self.github, self.repoData, self.dataViewModel, self.selectedText, self.selectedDirectory) self.worker.moveToThread(self.thread) self.thread.started.connect(self.worker.run) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.thread.finished.connect(self.worker.deleteLater) self.worker.finished.connect(self.finishedDownloading) self.worker.progress.connect(self.setStatus) self.thread.start() def finishedDownloading(self, count): self.selectRendition(self.selectedRendition) self.setStatus("") self.downloadButton.setEnabled(True) self.closeButton.setEnabled(True) if count > 0: self.parent.displayMessage( config.thisTranslation["message_installed"]) def setStatus(self, message): self.status.setText(message) QApplication.processEvents() def closeDialog(self): if self.thread: if self.thread.isRunning(): self.thread.quit() self.close()
class PlotLinesWidget(QWidget): """ Widget to set up spectral lines for plotting """ def __init__(self, parent=None, status=None, init_llist=None, init_z=None, edit_z=True, screen_scale=1.): """ Parameters ---------- parent : Widget parent status : Point to status bar init_llist : input LineList dictionary (from another widget) init_z : float, optional Initial redshift edit_z : bool, optional Allow z to be editable screen_scale : float, optional Scale GUI dimensions Returns ------- """ super(PlotLinesWidget, self).__init__(parent) # Initialize if not status is None: self.statusBar = status if init_z is None: init_z = 0. self.scale = screen_scale # Create a dialog window for redshift if edit_z: z_label = QLabel('z=') self.zbox = QLineEdit() self.zbox.z_frmt = '{:.7f}' self.zbox.setText(self.zbox.z_frmt.format(init_z)) self.zbox.setMinimumWidth(50 * self.scale) self.zbox.textChanged[str].connect(self.setz) #self.connect(self.zbox, QtCore.SIGNAL('editingFinished ()'), self.setz) else: z_label = QLabel('z={:.7f}'.format(init_z)) # Create the line list self.lists = [ 'None', 'ISM', 'Strong', 'HI', 'Galaxy', 'AGN', 'H2', 'EUV' ] #'grb.lst', 'dla.lst', 'lls.lst', 'subLLS.lst', # 'lyman.lst', 'Dlyman.lst', 'gal_vac.lst', 'ne8.lst', # 'lowz_ovi.lst', 'casbah.lst', 'H2.lst'] list_label = QLabel('Line Lists:') self.llist_widget = QListWidget(self) for ilist in self.lists: self.llist_widget.addItem(ilist) self.llist_widget.setCurrentRow(0) self.llist_widget.currentItemChanged.connect(self.on_list_change) self.llist_widget.setMaximumHeight(100 * self.scale) # Input line list? if init_llist is None: self.llist = {} # Dict for the line lists self.llist['Plot'] = False self.llist['z'] = 0. self.llist['List'] = 'None' # Name of the LineList being used self.llist['Lists'] = [] # Archived LineLists else: # Fill it all up and select self.llist = init_llist if not init_llist['List'] in self.lists: self.lists.append(init_llist['List']) self.llist_widget.addItem(init_llist['List']) self.llist_widget.setCurrentRow(len(self.lists) - 1) else: idx = self.lists.index(init_llist['List']) self.llist_widget.setCurrentRow(idx) try: self.zbox.setText(self.zbox.z_frmt.format(init_llist['z'])) except (AttributeError, KeyError): pass # Layout vbox = QVBoxLayout() vbox.addWidget(z_label) if edit_z: vbox.addWidget(self.zbox) vbox.addWidget(list_label) vbox.addWidget(self.llist_widget) self.setLayout(vbox) self.setMaximumHeight(200 * self.scale) def on_list_change(self, curr, prev): llist = str(curr.text()) # Print try: self.statusBar().showMessage('You chose: {:s}'.format(llist)) except AttributeError: print('You chose: {:s}'.format(curr.text())) #QtCore.pyqtRemoveInputHook() #xdb.set_trace() #QtCore.pyqtRestoreInputHook() self.llist = ltgu.set_llist(llist, in_dict=self.llist) # Try to draw if self.llist['Plot'] is True: try: self.spec_widg.on_draw() except AttributeError: return except TypeError: QtCore.pyqtRemoveInputHook() pdb.set_trace() QtCore.pyqtRestoreInputHook() def setz(self, text): # make sure z isnt too long for box self.zbox.setText(str(text)[:9]) # ensure the input z is a float sstr = ustr(self.zbox.text()) try: self.llist['z'] = float(sstr) except ValueError: try: self.statusBar().showMessage( 'ERROR: z Input must be a float! Try again..') except AttributeError: print('ERROR: z Input must be a float! Try again..') self.zbox.setText(self.zbox.z_frmt.format(self.llist['z'])) return # Report try: self.statusBar().showMessage('z = {:g}'.format(self.llist['z'])) except AttributeError: print('z = {:g}'.format(self.llist['z'])) # Try to draw try: self.spec_widg.on_draw() except AttributeError: return