def createListOption(self): def addItem(label, icon_pixmap, width, height): item = QListWidgetItem(list_option) item.setText(label) item.setTextAlignment(Qt.AlignHCenter) item.setIcon(QIcon(icon_pixmap)) item.setSizeHint(QSize(width, height)) list_option = QListWidget() list_option.setAutoFillBackground(True) list_option.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) list_option.setTextElideMode(Qt.ElideNone) list_option.setMovement(QListView.Static) list_option.setFlow(QListView.TopToBottom) list_option.setProperty("isWrapping", QVariant(False)) list_option.setSpacing(3) list_option.setViewMode(QListView.IconMode) items = [] items.append((QApplication.translate("option", "Connections"), "connections.png")) items.append((QApplication.translate("option", "Accounts"), "accounts.png")) items.append((QApplication.translate("option", "Aliases"), "aliases.png")) items.append((QApplication.translate("option", "Macros"), "macros.png")) items.append((QApplication.translate("option", "Keypad"), "keypad.png")) items.append((QApplication.translate("option", "Triggers"), "triggers.png")) items.append((QApplication.translate("option", "Preferences"), "preferences.png")) max_width = 0 for label, icon_name in items: w = list_option.fontMetrics().boundingRect(label).width() if w > max_width: max_width = w # An empiric method to align element in the center of the QListWidget max_width += 15 total_height = 0 for label, icon_name in items: icon_pixmap = QPixmap(":/images/" + icon_name) height = icon_pixmap.height() + list_option.fontMetrics().height() + 3 total_height += height + 5 addItem(label, icon_pixmap, max_width, height) list_option.setUniformItemSizes(True) list_option.setFixedWidth(max_width + 10) list_option.setMinimumHeight(total_height) return list_option
class HistoryWidget(QWidget): currentTrackChanged = pyqtSignal(dict) def __init__(self, bbclient, config, parent=None): super(HistoryWidget, self).__init__(parent) self.bbclient = bbclient self.config = config self.track_list = [] self.list = QListWidget(self) self.list.setUniformItemSizes(True) self.list.setSelectionMode(QListWidget.ExtendedSelection) self.list.currentRowChanged.connect(self._onRowChanged) self.delete_btn = QPushButton(QIcon(resource_path('img/delete.png')), '', self) self.save_btn = QPushButton(QIcon(resource_path('img/save.png')), '', self) self.upload_btn = QPushButton(QIcon(resource_path('img/upload.png')), '', self) for i, w in enumerate((self.delete_btn, self.save_btn, self.upload_btn)): w.setIconSize(QSize(22, 22)) if i < 1: w.setMinimumSize(32, 32) w.setMaximumSize(32, 32) else: w.setMinimumSize(58, 32) w.setMaximumSize(58, 32) save_menu = QMenu('Export tracks', self) act = save_menu.addAction('Save as TCX') act.triggered.connect(self._onSaveAsTCX) act = save_menu.addAction('Save as BDX (Bryton GPX extension)') act.triggered.connect(self._onSaveAsBDX) self.save_btn.setMenu(save_menu) upload_menu = QMenu('Upload tracks', self) act = upload_menu.addAction(QIcon(resource_path('img/strava-icon.png')), 'Upload to Strava.com') act.triggered.connect(self._onUploadStrava) act = upload_menu.addAction(QIcon(resource_path('img/bryton-icon.png')), 'Upload to Brytonsport.com') act.triggered.connect(self._onUploadBrytonSport) self.upload_btn.setMenu(upload_menu) self.delete_btn.clicked.connect(self._onDeleteTracks) self._createLayout() self.message_overlay = MessageWidget(self) self.message_overlay.setLoading('Loading tracklist') bbclient.refreshingTrackList.connect(self.message_overlay.show) def setTrackList(self, track_list, device_info): self.list.clear() self.device_info = device_info self.track_list = track_list for track in track_list: item = QListWidgetItem(track['name']) item.setData(TRACK_ITEM_ROLE, track['id']) self.list.addItem(item) self.message_overlay.hide() def resizeEvent(self, event): self.message_overlay.resize(event.size()) super(HistoryWidget, self).resizeEvent(event) def _onDeleteTracks(self): tracks = self._getSelectedTracks() if not tracks: tracks = self.track_list ids = map(lambda t: t['id'], tracks) names = map(lambda t: t['name'], tracks) msg = 'Are you sure you want to delete the following {} track(s):'.format(len(tracks)) msg += '\n' + '\n'.join(names) res = QMessageBox.question(self, 'Delete tracks?', msg, QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Cancel) print res if res == QMessageBox.Ok: print ids # self.bbclient._refreshTrackList() d = ProgressDialog('Finalizing', "Don't close this window\n(It may stall for a little while on 93%)", self) d.progress.setRange(0, 100) d.resize(250, 80) self.bbclient.finalizingProgress.connect(d.progress.setValue) self.bbclient.tracksDeleted.connect(d.accept) def _onFail(): QMessageBox.warning(self, 'Delete failed') d.accept() self.bbclient.deleteFailed.connect(_onFail) self.bbclient.deleteTracks(ids) d.exec_() def _onUploadStrava(self): tracks = self._getSelectedTracks() if not tracks: tracks = self.track_list strava.upload_to_strava(tracks, self.device_info, self, auth_token=self.config.get('strava_auth_token'), password=self.config.get('strava_password'), username=self.config.get('strava_email')) def _onUploadBrytonSport(self): brytonsport.upload_to_brytonsport(self.bbclient, self, username=self.config.get('bryton_email'), password=self.config.get('bryton_password'), session_id=self.config.get('bryton_session_id')) def _onSaveAsTCX(self): tracks = self._getSelectedTracks() if not tracks: tracks = self.track_list # QMessageBox.information(self, 'No tracks selected', 'You need to select the tracks you want to save.') if not tracks: return if len(tracks) == 1: name = QFileDialog.getSaveFileName(self, 'Save file %s' % tracks[0]['name'], self._trackFilename(tracks[0]['name'], 'tcx'), filter='TCX (*.tcx)') if name: self._saveContent(name, tcx.bryton_gpx_to_tcx(tracks[0]['gpx'], pretty=True, device=self.device_info)) else: dir = QFileDialog.getExistingDirectory(self, 'Open Directory', '', QFileDialog.ShowDirsOnly) if not dir: return for t in tracks: name = path.join(str(dir), self._trackFilename(t['name'], 'tcx')) self._saveContent(name, tcx.bryton_gpx_to_tcx(t['gpx'], pretty=True, device=self.device_info)) def _onSaveAsBDX(self): tracks = self._getSelectedTracks() if not tracks: tracks = self.track_list if not tracks: return if len(tracks) == 1: name = QFileDialog.getSaveFileName(self, 'Save file %s' % tracks[0]['name'], self._trackFilename(tracks[0]['name'], 'bdx'), filter='BDX (*.bdx)') if name: self._saveContent(name, tracks[0]['gpx'].toString(pretty=True)) else: dir = QFileDialog.getExistingDirectory(self, 'Open Directory', '', QFileDialog.ShowDirsOnly) if not dir: return for t in tracks: name = path.join(str(dir), self._trackFilename(t['name'], 'gpx')) self._saveContent(name, t['gpx'].toString(pretty=True)) def _saveContent(self, filename, content): with open(filename, 'w') as f: f.write(content) def _trackFilename(self, name, ext): return name.replace('/', '').replace(' ', '-').replace(':', '') + '.' + ext def _getSelectedTracks(self): items = self.list.selectedItems() tracks = [] for item in items: index = self.list.row(item) tracks.append(self.track_list[index]) return tracks def _onRowChanged(self, row): track = self.track_list[row] self.currentTrackChanged.emit(track) def _createLayout(self): l = QVBoxLayout() l.addWidget(self.list) h = QHBoxLayout() h.addWidget(self.delete_btn) h.addStretch() h.addWidget(self.save_btn) h.addWidget(self.upload_btn) l.addLayout(h) self.setLayout(l)