def initUI(self): QToolTip.setFont(QFont('SansSerif', 10)) self.setToolTip('This is a <b>QWidget</b> widget.') #quitBtn = QPushButton('Quit', self) #quitBtn.clicked.connect(self.quitBtnEvent()) #quitBtn.clicked.connect(QCoreApplication.instance().quit) #quitBtn.setToolTip('This is a <b>QPushButton</b> widget.') #quitBtn.resize(quitBtn.sizeHint()) exitAction = QAction(QIcon('application-exit-4.png'), '&Exit', self) exitAction.setShortcut('Alt+F4') exitAction.setStatusTip('Exit Application') exitAction.triggered.connect(qApp.quit) menuBar = QMenuBar() fileMenu = menuBar.addMenu('&File') fileMenu.addAction(exitAction) fileMenu.resize(fileMenu.sizeHint()) toolBar = QToolBar(self) toolBar.addAction(exitAction) #toolBar.resize(toolBar.sizeHint()) toolBar.setFixedHeight(60) hozLine = QFrame() hozLine.setFrameStyle(QFrame.HLine) #hozLine.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Expanding) statusBar = QStatusBar(self) statusBar.showMessage('Ready') grid = QGridLayout() lbl_1 = QLabel('1,1') lbl_2 = QLabel('1,2') lbl_3 = QLabel('2,1') lbl_4 = QLabel('2,2') grid.addWidget(lbl_1, 1, 1) grid.addWidget(lbl_2, 1, 2) grid.addWidget(lbl_3, 2, 1) grid.addWidget(lbl_4, 2, 2) vbox = QVBoxLayout() vbox.addWidget(menuBar) vbox.addWidget(hozLine) vbox.addWidget(toolBar) # vbox.addWidget(hozLine) vbox.addLayout(grid) vbox.addStretch(1) vbox.addWidget(statusBar) self.setLayout(vbox) self.setGeometry(300, 300, 500, 500) self.setWindowTitle('Photos') self.setWindowIcon(QIcon('camera-photo-5.png')) self.center() self.show()
class ControlPanelWindow(QDialog): def __init__(self, parent, cli_iface, iface_name): super(ControlPanelWindow, self).__init__(parent) self.setWindowTitle('SLCAN Adapter Control Panel') self.setAttribute(Qt.WA_DeleteOnClose) # This is required to stop background timers! self._cli_iface = cli_iface self._iface_name = iface_name self._state_widget = StateWidget(self, self._cli_iface) self._config_widget = ConfigWidget(self, self._cli_iface) self._cli_widget = CLIWidget(self, self._cli_iface) self._tab_widget = QTabWidget(self) self._tab_widget.addTab(self._state_widget, get_icon('dashboard'), 'Adapter State') self._tab_widget.addTab(self._config_widget, get_icon('wrench'), 'Configuration') self._tab_widget.addTab(self._cli_widget, get_icon('terminal'), 'Command Line') self._status_bar = QStatusBar(self) self._status_bar.setSizeGripEnabled(False) iface_name_label = QLabel(iface_name.split('/')[-1], self) iface_name_label.setFont(get_monospace_font()) layout = QVBoxLayout(self) layout.addWidget(iface_name_label) layout.addWidget(self._tab_widget) layout.addWidget(self._status_bar) left, top, right, bottom = layout.getContentsMargins() bottom = 0 layout.setContentsMargins(left, top, right, bottom) self.setLayout(layout) self.resize(400, 400) def closeEvent(self, close_event): if self._config_widget.have_unsaved_changes: if request_confirmation('Save changes?', 'You made changes to the adapter configuration that were not saved. ' 'Do you want to go back and save them?', parent=self): close_event.ignore() self._tab_widget.setCurrentWidget(self._config_widget) return super(ControlPanelWindow, self).closeEvent(close_event) def show_message(self, text, *fmt, duration=0): self._status_bar.showMessage(text % fmt, duration * 1000)
class Tab(QWidget): def __init__(self, parent, configuration): QWidget.__init__(self, parent) self._configuration = configuration layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) main_widget = QWidget(self) self._layout_main = QVBoxLayout() self._layout_main.setContentsMargins(0, 0, 0, 0) self._layout_main.setSpacing(6) main_widget.setLayout(self._layout_main) layout.addWidget(main_widget) self._status_bar = QStatusBar() layout.addWidget(self._status_bar) self.setLayout(layout) def _add_widget(self, widget): self._layout_main.addWidget(widget) def set_error_message(self, msg): self._status_bar.showMessage(msg)
class NodePropertiesWindow(QDialog): def __init__( self, parent, node, target_node_id, file_server_widget, node_monitor, dynamic_node_id_allocator_widget ): super(NodePropertiesWindow, self).__init__(parent) self.setAttribute(Qt.WA_DeleteOnClose) # This is required to stop background timers! self.setWindowTitle("Node Properties [%d]" % target_node_id) self.setMinimumWidth(640) self._target_node_id = target_node_id self._node = node self._file_server_widget = file_server_widget self._info_box = InfoBox(self, target_node_id, node_monitor) self._controls = Controls(self, node, target_node_id, file_server_widget, dynamic_node_id_allocator_widget) self._config_params = ConfigParams(self, node, target_node_id) self._status_bar = QStatusBar(self) self._status_bar.setSizeGripEnabled(False) layout = QVBoxLayout(self) layout.addWidget(self._info_box) layout.addWidget(self._controls) layout.addWidget(self._config_params) layout.addWidget(self._status_bar) left, top, right, bottom = layout.getContentsMargins() bottom = 0 layout.setContentsMargins(left, top, right, bottom) self.setLayout(layout) def show_message(self, text, *fmt, duration=0): self._status_bar.showMessage(text % fmt, duration * 1000) @property def target_node_id(self): return self._target_node_id
class EEGStudio(QMainWindow): """docstring for EEGStudio""" def __init__(self): super(EEGStudio, self).__init__() self.setWindowTitle('EEG Studio v1.0') self.setContentsMargins(10, 10, 10, 10) # Variables self.D = None self.X = None self.fs = 0 self.label = list() self.markPos = list() self.markItem = list() self.maxDuration = 0 # Main widgets self.fileDialog = FilePathDialog('EEG file:', 'Open file', 'EEG files (*.csv)') self.videoDialog = FilePathDialog('Video file:', 'Open video', 'Video files (*.mp4)') self.channelPanel = CheckBoxPanel(title='Channels') self.filteringForm = FilteringForm(title='Filtering') # Video player self.player = VideoPlayer() self.player.setSize(640, 480) self.player.error.connect(self.mediaError) self.player.stateChanged.connect(self.stateChanged) self.player.positionChanged.connect(self.positionChanged) self.player.durationChanged.connect(self.durationChanged) self.player.mediaStatusChanged.connect(self.mediaStatusChanged) self.player.videoAvailableChanged.connect(self.videoAvailableChanged) # Threads self.eegViewer = EEGViewer(mode='single') # EditLines self.timeEdit = QLineEdit('--:--:--') self.timeEdit.setAlignment(Qt.AlignCenter) self.indexEdit = QLineEdit('') self.indexEdit.setAlignment(Qt.AlignCenter) # Buttons self.icon = QWidget().style() self.loadButton = QPushButton('Load') self.loadButton.setIcon(self.icon.standardIcon(QStyle.SP_BrowserReload)) self.loadButton.clicked.connect(self.loadFiles) self.saveButton = QPushButton('Save') self.saveButton.setIcon(self.icon.standardIcon(QStyle.SP_DialogSaveButton)) self.saveButton.setEnabled(False) self.saveButton.clicked.connect(self.saveLabels) self.addButton = QPushButton('Add') self.addButton.setEnabled(False) self.addButton.clicked.connect(lambda: self.addLabel(None)) self.applyButton = QPushButton('Apply') self.applyButton.setIcon(self.icon.standardIcon(QStyle.SP_DialogApplyButton)) self.applyButton.setEnabled(False) self.applyButton.clicked.connect(self.applyParameters) self.playButton = QPushButton() self.playButton.setIcon(self.icon.standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.playButton.setEnabled(False) self.stopButton = QPushButton() self.stopButton.setIcon(self.icon.standardIcon(QStyle.SP_MediaStop)) self.stopButton.clicked.connect(self.stop) self.stopButton.setEnabled(False) self.syncButton = QPushButton('Sync') self.syncButton.setEnabled(False) self.syncButton.clicked.connect(self.syncTime) # Slider self.positionSlider = QSlider(Qt.Horizontal) self.positionSlider.setRange(0, 1) self.positionSlider.setTickPosition(2) self.positionSlider.setTickInterval(60000) self.positionSlider.sliderMoved.connect(self.setPosition) # GroupBoxes syncGBox = QGroupBox('Synchronization') syncGBox.setAlignment(Qt.AlignCenter) labelingGBox = QGroupBox('Labeling') labelingGBox.setAlignment(Qt.AlignCenter) # Layouts sourceLayout = QGridLayout() sourceLayout.setColumnStretch(0, 14) sourceLayout.setColumnStretch(1, 1) sourceLayout.setVerticalSpacing(0) sourceLayout.addWidget(self.fileDialog, 0, 0) sourceLayout.addWidget(self.videoDialog, 1, 0) sourceLayout.addWidget(self.loadButton, 0, 1, 2, 1) paramsLayout = QHBoxLayout() paramsLayout.addWidget(self.filteringForm, 7) paramsLayout.addWidget(self.applyButton,1) syncLayout = QGridLayout() syncLayout.addWidget(self.timeEdit) syncLayout.addWidget(self.syncButton) syncGBox.setLayout(syncLayout) labelingLayout = QGridLayout() labelingLayout.addWidget(QLabel('Index:'), 0, 0, alignment=Qt.AlignRight) labelingLayout.addWidget(self.indexEdit, 0, 1) labelingLayout.addWidget(self.addButton, 0, 2) labelingLayout.addWidget(self.saveButton, 1, 0, 1, 3) labelingGBox.setLayout(labelingLayout) controlLayout = QHBoxLayout() controlLayout.addWidget(self.playButton, 1) controlLayout.addWidget(self.stopButton, 1) controlLayout.addWidget(self.positionSlider, 15) controlLayout.addWidget(syncGBox, 1) mainLayout = QVBoxLayout() mainLayout.addLayout(sourceLayout, 1) mainLayout.addStretch(1) mainLayout.addWidget(self.channelPanel, 1) mainLayout.addStretch(1) mainLayout.addLayout(paramsLayout, 1) mainLayout.addStretch(1) mainLayout.addWidget(labelingGBox, 1, alignment=Qt.AlignCenter) mainLayout.addStretch(1) mainLayout.addLayout(controlLayout, 1) # Main widget mainWidget = QWidget() mainWidget.setLayout(mainLayout) self.setCentralWidget(mainWidget) # Status bar self.statusBar = QStatusBar() self.setStatusBar(self.statusBar) self.statusBar.showMessage('¡System ready!') def loadFiles(self): try: path = self.fileDialog.getFullPath() self.D = pd.read_csv(path) self.statusBar.showMessage('EEG file was successfully loaded!') self.positionSlider.setRange(0, self.D.index.size) self.createChannelWidgets() self.eegViewer.show() path = self.videoDialog.getFullPath() self.player.loadMedia(path) self.applyButton.setEnabled(True) except FileNotFoundError: self.statusBar.showMessage('EEG file not found!') def mediaError(self): self.statusBar.showMessage('Error: {}'.format(self.player.errorString())) def setPosition(self, position): if self.player.isVideoAvailable(): self.player.setPosition(position) self.syncTime() def durationChanged(self, duration): self.maxDuration = duration self.positionSlider.setRange(0, duration) self.timeEdit.setText('00:00:00') def positionChanged(self, position): self.positionSlider.setValue(position) seconds = round(position / 1000) time_str = str(timedelta(seconds=seconds)) self.timeEdit.setText(time_str) def stateChanged(self, state): if state == VideoPlayer.PlayingState: self.playButton.setIcon(self.icon.standardIcon(QStyle.SP_MediaPause)) self.statusBar.showMessage('Running...') else: self.playButton.setIcon(self.icon.standardIcon(QStyle.SP_MediaPlay)) self.statusBar.showMessage('Paused!') def mediaStatusChanged(self, status): if status == self.player.LoadingMedia: self.statusBar.showMessage('Loading video...') elif status == self.player.LoadedMedia: self.player.stop() self.syncButton.setEnabled(True) self.statusBar.showMessage('Video was successfully loaded!') def videoAvailableChanged(self, videoAvailable): if videoAvailable == True: self.player.show() else: self.player.hide() def createChannelWidgets(self): columns = self.D.columns self.channelPanel.setOptions(columns) def applyParameters(self): self.X = self.D.copy() param = self.filteringForm.getValues() channel = self.channelPanel.getChecked() if len(channel) == 0: self.statusBar.showMessage('You must select at least one channel') return color = self.channelPanel.getColors() numCh = param['n_channels'] self.fs = param['fs'] notch(self.X, self.fs, param['notch'], numCh) bandpass(self.X, self.fs, param['low'], param['high'], param['order'], numCh) self.X[self.X.columns[:numCh]] = MinMaxScaler().fit_transform(self.X[self.X.columns[:numCh]]) self.label = np.zeros((self.X.index.size,), dtype=int) if 'Label' in self.X.columns: self.label = self.X['Label'].to_numpy(copy=True) self.eegViewer.configure(channel, color, self.fs * 1.2, self.fs) self.eegViewer.plotData(self.X) self.eegViewer.setPosition(0) self.markPos.clear() self.markItem.clear() marks = np.where(self.label == 1)[0] for index in marks: self.addLabel(index) self.addButton.setEnabled(True) self.playButton.setEnabled(True) self.playButton.setFocus() self.stopButton.setEnabled(True) self.saveButton.setEnabled(True) self.applyButton.setEnabled(False) def play(self): if self.player.isVideoAvailable(): self.player.toggle() if self.eegViewer.getState() == EEGViewer.StoppedState: self.eegViewer.play() else: self.eegViewer.toggle() self.syncTime() self.playButton.setFocus() def stop(self): if self.player.isVideoAvailable(): self.player.stop() self.eegViewer.stop() self.playButton.setFocus() self.applyButton.setEnabled(True) def timeToSeconds(self): time_str = self.timeEdit.text() time_obj = pd.to_timedelta(time_str) seconds = int(time_obj.total_seconds()) return seconds def syncTime(self): seconds = self.timeToSeconds() position_vid = seconds * 1000 position_eeg = seconds * self.fs if position_vid <= self.maxDuration: self.player.setPosition(position_vid) self.eegViewer.setPosition(position_eeg) self.playButton.setFocus() def addLabel(self, index=None): position = int(self.indexEdit.text().strip()) if index is None else index if position < 0 or position > self.D.index.size: self.statusBar.showMessage('Index {} does not exist!'.format(position)) else: mark = self.eegViewer.addMark(position) mark.sigPositionChangeFinished.connect(self.markMoved) self.markPos.append(position) self.markItem.append(mark) self.label[position] = 1 self.indexEdit.setText('') self.playButton.setFocus() def markMoved(self): markPos = np.array(self.markPos, dtype=int) linePos = np.array([line.getXPos() for line in self.markItem], dtype=int) moved = np.where(markPos != linePos)[0] old_index = markPos[moved] self.label[old_index] = 0 new_index = linePos[moved] self.label[new_index] = 1 self.markPos = linePos.tolist() self.statusBar.showMessage(f'Label moved from {old_index} to {new_index}') def saveLabels(self): self.D['Label'] = self.label path = self.fileDialog.getFullPath() path = path.split('.')[0] path += '_Label.csv' self.D.to_csv(path, index=False) self.statusBar.showMessage('Labeled EEG file saved as {}'.format(path))
class AppWindow(QMainWindow): onRestart = pyqtSignal(name='onRestart') def __init__(self, dwarf_args, flags=None): super(AppWindow, self).__init__(flags) self.dwarf_args = dwarf_args self.session_manager = SessionManager(self) self.session_manager.sessionCreated.connect(self.session_created) self.session_manager.sessionStopped.connect(self.session_stopped) self.session_manager.sessionClosed.connect(self.session_closed) self._tab_order = [ 'memory', 'modules', 'ranges', 'jvm-inspector', 'jvm-debugger' ] self.menu = self.menuBar() self._is_newer_dwarf = False self.view_menu = None #dockwidgets self.watchers_dwidget = None self.hooks_dwiget = None self.bookmarks_dwiget = None self.registers_dock = None self.console_dock = None self.backtrace_dock = None self.threads_dock = None #panels self.asm_panel = None self.console_panel = None self.context_panel = None self.backtrace_panel = None self.contexts_list_panel = None self.data_panel = None self.emulator_panel = None self.ftrace_panel = None self.hooks_panel = None self.bookmarks_panel = None self.smali_panel = None self.java_inspector_panel = None self.java_explorer_panel = None self.java_trace_panel = None self.memory_panel = None self.modules_panel = None self.ranges_panel = None self.search_panel = None self.trace_panel = None self.watchers_panel = None self.welcome_window = None self._ui_elems = [] self.setWindowTitle( 'Dwarf - A debugger for reverse engineers, crackers and security analyst' ) # load external assets _app = QApplication.instance() self.remove_tmp_dir() # themes self.prefs = Prefs() self.set_theme(self.prefs.get('dwarf_ui_theme', 'black')) # load font if os.path.exists(utils.resource_path('assets/Anton.ttf')): QFontDatabase.addApplicationFont( utils.resource_path('assets/Anton.ttf')) if os.path.exists(utils.resource_path('assets/OpenSans-Regular.ttf')): QFontDatabase.addApplicationFont( utils.resource_path('assets/OpenSans-Regular.ttf')) font = QFont("OpenSans", 9, QFont.Normal) # TODO: add settingsdlg font_size = self.prefs.get('dwarf_ui_font_size', 12) font.setPixelSize(font_size) _app.setFont(font) if os.path.exists(utils.resource_path('assets/OpenSans-Bold.ttf')): QFontDatabase.addApplicationFont( utils.resource_path('assets/OpenSans-Bold.ttf')) # mainwindow statusbar self.progressbar = QProgressBar() self.progressbar.setRange(0, 0) self.progressbar.setVisible(False) self.progressbar.setFixedHeight(15) self.progressbar.setFixedWidth(100) self.progressbar.setTextVisible(False) self.progressbar.setValue(30) self.statusbar = QStatusBar(self) self.statusbar.setAutoFillBackground(False) self.statusbar.addPermanentWidget(self.progressbar) self.statusbar.setObjectName("statusbar") self.setStatusBar(self.statusbar) self.main_tabs = QTabWidget(self) self.main_tabs.setMovable(False) self.main_tabs.setTabsClosable(True) self.main_tabs.setAutoFillBackground(True) self.main_tabs.tabCloseRequested.connect(self._on_close_tab) self.setCentralWidget(self.main_tabs) if self.dwarf_args.package is None: self.welcome_window = WelcomeDialog(self) self.welcome_window.setModal(True) self.welcome_window.onIsNewerVersion.connect( self._enable_update_menu) self.welcome_window.onUpdateComplete.connect( self._on_dwarf_updated) self.welcome_window.setWindowTitle( 'Welcome to Dwarf - A debugger for reverse engineers, crackers and security analyst' ) self.welcome_window.onSessionSelected.connect(self._start_session) self.welcome_window.onSessionRestore.connect(self._restore_session) # wait for welcome screen self.hide() self.welcome_window.show() else: if dwarf_args.package is not None: if dwarf_args.type is None: # no device given check if package is local path if os.path.exists(dwarf_args.package): print('* Starting new LocalSession') self._start_session('local') else: print('use -t to set sessiontype') exit(0) else: print('* Starting new Session') self._start_session(dwarf_args.type) def _setup_main_menu(self): self.menu = self.menuBar() dwarf_menu = QMenu('Dwarf', self) theme = QMenu('Theme', dwarf_menu) theme.addAction('Black') theme.addAction('Dark') theme.addAction('Light') theme.triggered.connect(self._set_theme) dwarf_menu.addMenu(theme) dwarf_menu.addSeparator() if self._is_newer_dwarf: dwarf_menu.addAction('Update', self._update_dwarf) dwarf_menu.addAction('Close', self.session_manager.session.stop) self.menu.addMenu(dwarf_menu) session = self.session_manager.session if session is not None: session_menu = session.main_menu if isinstance(session_menu, list): for menu in session_menu: self.menu.addMenu(menu) else: self.menu.addMenu(session_menu) self.view_menu = QMenu('View', self) subview_menu = QMenu('Subview', self.view_menu) subview_menu.addAction('Search', lambda: self.show_main_tab('search'), shortcut=QKeySequence(Qt.CTRL + Qt.Key_F3)) subview_menu.addAction('Emulator', lambda: self.show_main_tab('emulator'), shortcut=QKeySequence(Qt.CTRL + Qt.Key_F2)) subview_menu.addAction('Disassembly', lambda: self.show_main_tab('disassembly'), shortcut=QKeySequence(Qt.CTRL + Qt.Key_F5)) self.view_menu.addMenu(subview_menu) self.view_menu.addSeparator() self.menu.addMenu(self.view_menu) if self.dwarf_args.debug_script: debug_menu = QMenu('Debug', self) debug_menu.addAction('Reload core', self._menu_reload_core) debug_menu.addAction('Debug dwarf js core', self._menu_debug_dwarf_js) self.menu.addMenu(debug_menu) about_menu = QMenu('About', self) about_menu.addAction('Dwarf on GitHub', self._menu_github) about_menu.addAction('Documention', self._menu_documentation) about_menu.addAction('Api', self._menu_api) about_menu.addAction('Slack', self._menu_slack) about_menu.addSeparator() about_menu.addAction('Info', self._show_about_dlg) self.menu.addMenu(about_menu) def _enable_update_menu(self): self._is_newer_dwarf = True def _update_dwarf(self): if self.welcome_window: self.welcome_window._update_dwarf() def _on_close_tab(self, index): tab_text = self.main_tabs.tabText(index) if tab_text: if tab_text.lower() in self.session_manager.session.non_closable: return try: self._ui_elems.remove(tab_text.lower()) except ValueError: # recheck ValueError: list.remove(x): x not in list pass self.main_tabs.removeTab(index) def _handle_tab_change(self): for index in range(self.main_tabs.count()): tab_name = self.main_tabs.tabText(index).lower().replace(' ', '-') if tab_name in self.session_manager.session.non_closable: self.main_tabs.tabBar().setTabButton(index, QTabBar.RightSide, None) if tab_name in self._tab_order: should_index = self._tab_order.index(tab_name) if index != should_index: self.main_tabs.tabBar().moveTab(index, should_index) def _on_dwarf_updated(self): self.onRestart.emit() def remove_tmp_dir(self): if os.path.exists('.tmp'): shutil.rmtree('.tmp', ignore_errors=True) def _set_theme(self, qaction): if qaction: self.set_theme(qaction.text()) def _menu_reload_core(self): self.dwarf.load_script() def _menu_debug_dwarf_js(self): you_know_what_to_do = json.loads( self.dwarf._script.exports.debugdwarfjs()) return you_know_what_to_do def show_main_tab(self, name): # elem doesnt exists? create it if name not in self._ui_elems: self._create_ui_elem(name) index = 0 name = name.join(name.split()).lower() if name == 'memory': index = self.main_tabs.indexOf(self.memory_panel) elif name == 'ranges': index = self.main_tabs.indexOf(self.ranges_panel) elif name == 'search': index = self.main_tabs.indexOf(self.search_panel) elif name == 'modules': index = self.main_tabs.indexOf(self.modules_panel) elif name == 'disassembly': index = self.main_tabs.indexOf(self.asm_panel) elif name == 'trace': index = self.main_tabs.indexOf(self.trace_panel) elif name == 'data': index = self.main_tabs.indexOf(self.data_panel) elif name == 'emulator': index = self.main_tabs.indexOf(self.emulator_panel) elif name == 'java-trace': index = self.main_tabs.indexOf(self.java_trace_panel) elif name == 'jvm-inspector': index = self.main_tabs.indexOf(self.java_inspector_panel) elif name == 'jvm-debugger': index = self.main_tabs.indexOf(self.java_explorer_panel) elif name == 'smali': index = self.main_tabs.indexOf(self.smali_panel) self.main_tabs.setCurrentIndex(index) def jump_to_address(self, ptr, show_panel=True): if self.memory_panel is not None: if show_panel: self.show_main_tab('memory') self.memory_panel.read_memory(ptr) @pyqtSlot(name='mainMenuGitHub') def _menu_github(self): QDesktopServices.openUrl(QUrl('https://github.com/iGio90/Dwarf')) @pyqtSlot(name='mainMenuDocumentation') def _menu_api(self): QDesktopServices.openUrl(QUrl('https://igio90.github.io/Dwarf/')) @pyqtSlot(name='mainMenuApi') def _menu_documentation(self): QDesktopServices.openUrl(QUrl('https://igio90.github.io/Dwarf/api')) @pyqtSlot(name='mainMenuSlack') def _menu_slack(self): QDesktopServices.openUrl( QUrl('https://join.slack.com/t/resecret/shared_invite' '/enQtMzc1NTg4MzE3NjA1LTlkNzYxNTIwYTc2ZTYyOWY1MT' 'Q1NzBiN2ZhYjQwYmY0ZmRhODQ0NDE3NmRmZjFiMmE1MDYwN' 'WJlNDVjZDcwNGE')) def _show_about_dlg(self): about_dlg = AboutDialog(self) about_dlg.show() def _create_ui_elem(self, elem): if not isinstance(elem, str): return if elem not in self._ui_elems: self._ui_elems.append(elem) if elem == 'watchers': from ui.panel_watchers import WatchersPanel self.watchers_dwidget = QDockWidget('Watchers', self) self.watchers_panel = WatchersPanel(self) # dont respond to dblclick mem cant be shown # self.watchers_panel.onItemDoubleClicked.connect( # self._on_watcher_clicked) self.watchers_panel.onItemRemoved.connect( self._on_watcher_removeditem) self.watchers_panel.onItemAdded.connect(self._on_watcher_added) self.watchers_dwidget.setWidget(self.watchers_panel) self.watchers_dwidget.setObjectName('WatchersPanel') self.addDockWidget(Qt.LeftDockWidgetArea, self.watchers_dwidget) self.view_menu.addAction(self.watchers_dwidget.toggleViewAction()) elif elem == 'hooks': from ui.panel_hooks import HooksPanel self.hooks_dwiget = QDockWidget('Breakpoints', self) self.hooks_panel = HooksPanel(self) self.hooks_panel.onShowMemoryRequest.connect( self._on_watcher_clicked) self.hooks_panel.onHookRemoved.connect(self._on_hook_removed) self.hooks_dwiget.setWidget(self.hooks_panel) self.hooks_dwiget.setObjectName('HooksPanel') self.addDockWidget(Qt.LeftDockWidgetArea, self.hooks_dwiget) self.view_menu.addAction(self.hooks_dwiget.toggleViewAction()) elif elem == 'bookmarks': from ui.panel_bookmarks import BookmarksPanel self.bookmarks_dwiget = QDockWidget('Boomarks', self) self.bookmarks_panel = BookmarksPanel(self) self.bookmarks_panel.onShowMemoryRequest.connect( self._on_watcher_clicked) self.bookmarks_dwiget.setWidget(self.bookmarks_panel) self.bookmarks_dwiget.setObjectName('BookmarksPanel') self.addDockWidget(Qt.LeftDockWidgetArea, self.bookmarks_dwiget) self.view_menu.addAction(self.bookmarks_dwiget.toggleViewAction()) elif elem == 'registers': from ui.panel_context import ContextPanel self.registers_dock = QDockWidget('Context', self) self.context_panel = ContextPanel(self) self.registers_dock.setWidget(self.context_panel) self.registers_dock.setObjectName('ContextsPanel') self.addDockWidget(Qt.RightDockWidgetArea, self.registers_dock) self.view_menu.addAction(self.registers_dock.toggleViewAction()) elif elem == 'memory': from ui.panel_memory import MemoryPanel self.memory_panel = MemoryPanel(self) self.memory_panel.onShowDisassembly.connect( self._disassemble_range) self.memory_panel.dataChanged.connect(self._on_memory_modified) self.memory_panel.statusChanged.connect(self.set_status_text) self.main_tabs.addTab(self.memory_panel, 'Memory') elif elem == 'jvm-debugger': from ui.panel_java_explorer import JavaExplorerPanel self.java_explorer_panel = JavaExplorerPanel(self) self.main_tabs.addTab(self.java_explorer_panel, 'JVM debugger') self.main_tabs.tabBar().moveTab( self.main_tabs.indexOf(self.java_explorer_panel), 1) elif elem == 'jvm-inspector': from ui.panel_java_inspector import JavaInspector self.java_inspector_panel = JavaInspector(self) self.main_tabs.addTab(self.java_inspector_panel, 'JVM inspector') elif elem == 'console': from ui.panel_console import ConsolePanel self.console_dock = QDockWidget('Console', self) self.console_panel = ConsolePanel(self) self.dwarf.onLogToConsole.connect(self._log_js_output) self.console_dock.setWidget(self.console_panel) self.console_dock.setObjectName('ConsolePanel') self.addDockWidget(Qt.BottomDockWidgetArea, self.console_dock) self.view_menu.addAction(self.console_dock.toggleViewAction()) elif elem == 'backtrace': from ui.panel_backtrace import BacktracePanel self.backtrace_dock = QDockWidget('Backtrace', self) self.backtrace_panel = BacktracePanel(self) self.backtrace_dock.setWidget(self.backtrace_panel) self.backtrace_dock.setObjectName('BacktracePanel') self.backtrace_panel.onShowMemoryRequest.connect( self._on_watcher_clicked) self.addDockWidget(Qt.RightDockWidgetArea, self.backtrace_dock) self.view_menu.addAction(self.backtrace_dock.toggleViewAction()) elif elem == 'threads': from ui.panel_contexts_list import ContextsListPanel self.threads_dock = QDockWidget('Threads', self) self.contexts_list_panel = ContextsListPanel(self) self.dwarf.onThreadResumed.connect( self.contexts_list_panel.resume_tid) self.contexts_list_panel.onItemDoubleClicked.connect( self._manually_apply_context) self.threads_dock.setWidget(self.contexts_list_panel) self.threads_dock.setObjectName('ThreadPanel') self.addDockWidget(Qt.RightDockWidgetArea, self.threads_dock) self.view_menu.addAction(self.threads_dock.toggleViewAction()) elif elem == 'modules': from ui.panel_modules import ModulesPanel self.modules_panel = ModulesPanel(self) self.modules_panel.onModuleSelected.connect( self._on_module_dblclicked) self.modules_panel.onModuleFuncSelected.connect( self._on_modulefunc_dblclicked) self.modules_panel.onAddHook.connect(self._on_addmodule_hook) self.modules_panel.onDumpBinary.connect(self._on_dumpmodule) self.main_tabs.addTab(self.modules_panel, 'Modules') elif elem == 'ranges': from ui.panel_ranges import RangesPanel self.ranges_panel = RangesPanel(self) self.ranges_panel.onItemDoubleClicked.connect( self._range_dblclicked) self.ranges_panel.onDumpBinary.connect(self._on_dumpmodule) # connect to watcherpanel func self.ranges_panel.onAddWatcher.connect( self.watchers_panel.do_addwatcher_dlg) self.main_tabs.addTab(self.ranges_panel, 'Ranges') elif elem == 'search': from ui.panel_search import SearchPanel self.search_panel = SearchPanel(self) self.search_panel.onShowMemoryRequest.connect( self._on_watcher_clicked) self.main_tabs.addTab(self.search_panel, 'Search') elif elem == 'data': from ui.panel_data import DataPanel self.data_panel = DataPanel(self) self.main_tabs.addTab(self.data_panel, 'Data') elif elem == 'trace': from ui.panel_trace import TracePanel self.trace_panel = TracePanel(self) self.main_tabs.addTab(self.trace_panel, 'Trace') elif elem == 'disassembly': from ui.widgets.disasm_view import DisassemblyView self.asm_panel = DisassemblyView(self) self.asm_panel.onShowMemoryRequest.connect(self._on_disasm_showmem) self.main_tabs.addTab(self.asm_panel, 'Disassembly') elif elem == 'emulator': from ui.panel_emulator import EmulatorPanel self.emulator_panel = EmulatorPanel(self) self.main_tabs.addTab(self.emulator_panel, 'Emulator') elif elem == 'java-trace': from ui.panel_java_trace import JavaTracePanel self.java_trace_panel = JavaTracePanel(self) self.main_tabs.addTab(self.java_trace_panel, 'JVM tracer') elif elem == 'smali': from ui.panel_smali import SmaliPanel self.smali_panel = SmaliPanel() self.main_tabs.addTab(self.smali_panel, 'Smali') else: print('no handler for elem: ' + elem) # make tabs unclosable and sort self._handle_tab_change() # TODO: remove add @2x for item in self.findChildren(QDockWidget): if item: if 'darwin' in sys.platform: item.setStyleSheet( 'QDockWidget::title { padding-left:-30px; }') def set_theme(self, theme): if theme: theme = theme.replace(os.pardir, '').replace('.', '') theme = theme.join(theme.split()).lower() theme_style = 'assets/' + theme + '_style.qss' if not os.path.exists(utils.resource_path(theme_style)): return self.prefs.put('dwarf_ui_theme', theme) try: _app = QApplication.instance() with open(theme_style) as stylesheet: _app.setStyleSheet(_app.styleSheet() + '\n' + stylesheet.read()) except Exception as e: pass # err = self.dwarf.spawn(dwarf_args.package, dwarf_args.script) def set_status_text(self, txt): self.statusbar.showMessage(txt) # ************************************************************************ # **************************** Properties ******************************** # ************************************************************************ @property def disassembly(self): return self.asm_panel @property def backtrace(self): return self.backtrace_panel @property def console(self): return self.console_panel @property def context(self): return self.context_panel @property def threads(self): return self.contexts_list_panel @property def emulator(self): return self.emulator_panel @property def ftrace(self): return self.ftrace_panel @property def hooks(self): return self.hooks_panel @property def java_inspector(self): return self.java_inspector_panel @property def java_explorer(self): return self.java_explorer_panel @property def memory(self): return self.memory_panel @property def modules(self): return self.memory_panel @property def ranges(self): return self.ranges_panel @property def trace(self): return self.trace_panel @property def watchers(self): return self.watchers_panel @property def dwarf(self): if self.session_manager.session is not None: return self.session_manager.session.dwarf else: return None # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ # session handlers def _start_session(self, session_type, session_data=None): if self.welcome_window is not None: self.welcome_window.close() self.session_manager.create_session(session_type, session_data=session_data) def _restore_session(self, session_data): if 'session' in session_data: session_type = session_data['session'] self._start_session(session_type, session_data=session_data) def session_created(self): # session init done create ui for it session = self.session_manager.session self._setup_main_menu() for ui_elem in session.session_ui_sections: ui_elem = ui_elem.join(ui_elem.split()).lower() self._create_ui_elem(ui_elem) self.dwarf.onAttached.connect(self._on_attached) self.dwarf.onScriptLoaded.connect(self._on_script_loaded) # hookup self.dwarf.onSetRanges.connect(self._on_setranges) self.dwarf.onSetModules.connect(self._on_setmodules) self.dwarf.onAddNativeHook.connect(self._on_add_hook) self.dwarf.onApplyContext.connect(self._apply_context) self.dwarf.onThreadResumed.connect(self.on_tid_resumed) self.dwarf.onTraceData.connect(self._on_tracer_data) self.dwarf.onSetData.connect(self._on_set_data) self.session_manager.start_session(self.dwarf_args) q_settings = QSettings("dwarf_window_pos.ini", QSettings.IniFormat) ui_state = q_settings.value('dwarf_ui_state') if ui_state: self.restoreGeometry(ui_state) window_state = q_settings.value('dwarf_ui_window', self.saveState()) if window_state: self.restoreState(window_state) self.showMaximized() def session_stopped(self): self.remove_tmp_dir() self.menu.clear() self.main_tabs.clear() # actually we need to kill this. needs a refactor if self.java_trace_panel is not None: self.java_trace_panel = None for elem in self._ui_elems: if elem == 'watchers': self.watchers_panel.clear_list() self.watchers_panel.close() self.watchers_panel = None self.removeDockWidget(self.watchers_dwidget) self.watchers_dwidget = None elif elem == 'hooks': self.hooks_panel.close() self.hooks_panel = None self.removeDockWidget(self.hooks_dwiget) self.hooks_dwiget = None elif elem == 'registers': self.context_panel.close() self.context_panel = None self.removeDockWidget(self.registers_dock) self.registers_dock = None elif elem == 'memory': self.memory_panel.close() self.memory_panel = None self.main_tabs.removeTab(0) # self.main_tabs elif elem == 'jvm-debugger': self.java_explorer_panel.close() self.java_explorer_panel = None self.removeDockWidget(self.watchers_dwidget) elif elem == 'console': self.console_panel.close() self.console_panel = None self.removeDockWidget(self.console_dock) self.console_dock = None elif elem == 'backtrace': self.backtrace_panel.close() self.backtrace_panel = None self.removeDockWidget(self.backtrace_dock) elif elem == 'threads': self.contexts_list_panel.close() self.contexts_list_panel = None self.removeDockWidget(self.threads_dock) self.threads_dock = None elif elem == 'bookmarks': self.bookmarks_panel.close() self.bookmarks_panel = None self.removeDockWidget(self.bookmarks_dwiget) self.bookmarks_dwiget = None def session_closed(self): self._ui_elems = [] self.hide() if self.welcome_window is not None: self.welcome_window.exec() # close if it was a commandline session if self.welcome_window is None: if self.dwarf_args.package: self.close() # ui handler def closeEvent(self, event): """ Window closed save stuff or whatever at exit detaches dwarf """ # save windowstuff q_settings = QSettings("dwarf_window_pos.ini", QSettings.IniFormat) q_settings.setValue('dwarf_ui_state', self.saveGeometry()) q_settings.setValue('dwarf_ui_window', self.saveState()) if self.dwarf: self.dwarf.detach() super().closeEvent(event) def _on_watcher_clicked(self, ptr): """ Address in Watcher/Hookpanel was clicked show Memory """ if '.' in ptr: # java_hook file_path = ptr.replace('.', os.path.sep) if os.path.exists('.tmp/smali/' + file_path + '.smali'): if self.smali_panel is None: self._create_ui_elem('smali') self.smali_panel.set_file('.tmp/smali/' + file_path + '.smali') self.show_main_tab('smali') else: self.memory_panel.read_memory(ptr=ptr) self.show_main_tab('memory') def _on_disasm_showmem(self, ptr, length): """ Address in Disasm was clicked adds temphighlight for bytes from current instruction """ self.memory_panel.read_memory(ptr) self.memory_panel.add_highlight( HighLight('attention', utils.parse_ptr(ptr), length)) self.show_main_tab('memory') def _on_watcher_added(self, ptr): """ Watcher Entry was added """ try: # set highlight self.memory_panel.add_highlight( HighLight('watcher', ptr, self.dwarf.pointer_size)) except HighlightExistsError: pass def _on_watcher_removeditem(self, ptr): """ Watcher Entry was removed remove highlight too """ self.memory_panel.remove_highlight(ptr) def _on_module_dblclicked(self, data): """ Module in ModulePanel was doubleclicked """ addr, size = data addr = utils.parse_ptr(addr) size = int(size, 10) self.memory_panel.read_memory(ptr=addr, length=size) self.show_main_tab('Memory') def _on_modulefunc_dblclicked(self, ptr): """ Function in ModulePanel was doubleclicked """ ptr = utils.parse_ptr(ptr) self.memory_panel.read_memory(ptr=ptr) self.show_main_tab('Memory') def _on_dumpmodule(self, data): """ DumpBinary MenuItem in ModulePanel was selected """ ptr, size = data ptr = utils.parse_ptr(ptr) size = int(size, 10) self.dwarf.dump_memory(ptr=ptr, length=size) def _disassemble_range(self, mem_range): """ Disassemble MenuItem in Hexview was selected """ if mem_range: if self.asm_panel is None: self._create_ui_elem('disassembly') if mem_range: self.asm_panel.disassemble(mem_range) self.show_main_tab('disassembly') def _range_dblclicked(self, ptr): """ Range in RangesPanel was doubleclicked """ ptr = utils.parse_ptr(ptr) self.memory_panel.read_memory(ptr=ptr) self.show_main_tab('Memory') # dwarf handlers def _log_js_output(self, output): if self.console_panel is not None: self.console_panel.get_js_console().log(output) def _on_setranges(self, ranges): """ Dwarf wants to set Ranges only hooked up to switch tab or create ui its connected in panel after creation """ if self.ranges_panel is None: self.show_main_tab('ranges') # forward only now to panel it connects after creation self.ranges_panel.set_ranges(ranges) def _on_setmodules(self, modules): """ Dwarf wants to set Modules only hooked up to switch tab or create ui its connected in panel after creation """ if self.modules_panel is None: self._create_ui_elem('modules') self.modules_panel.set_modules(modules) if self.modules_panel is not None: self.show_main_tab('modules') def _manually_apply_context(self, context): """ perform additional operation if the context has been manually applied from the context list """ self._apply_context(context, manual=True) def _apply_context(self, context, manual=False): # update current context tid # this should be on top as any further api from js needs to be executed on that thread is_initial_hook = context['reason'] >= 0 if manual or (self.dwarf.context_tid and not is_initial_hook): self.dwarf.context_tid = context['tid'] if 'context' in context: if not manual: self.threads.add_context(context) is_java = context['is_java'] if is_java: if self.java_explorer_panel is None: self._create_ui_elem('jvm-debugger') self.context_panel.set_context(context['ptr'], 1, context['context']) self.java_explorer_panel._set_handle_arg(-1) self.show_main_tab('jvm-debugger') else: self.context_panel.set_context(context['ptr'], 0, context['context']) if 'pc' in context['context']: if not 'disassembly' in self._ui_elems: from lib.range import Range _range = Range(Range.SOURCE_TARGET, self.dwarf) _range.init_with_address( int(context['context']['pc']['value'], 16)) self._disassemble_range(_range) if 'backtrace' in context: self.backtrace_panel.set_backtrace(context['backtrace']) def _on_add_hook(self, hook): try: # set highlight ptr = hook.get_ptr() ptr = utils.parse_ptr(ptr) self.memory_panel.add_highlight( HighLight('hook', ptr, self.dwarf.pointer_size)) except HighlightExistsError: pass def _on_hook_removed(self, ptr): ptr = utils.parse_ptr(ptr) self.memory_panel.remove_highlight(ptr) def _on_addmodule_hook(self, data): ptr, name = data self.dwarf.hook_native(ptr, own_input=name) def on_tid_resumed(self, tid): if self.dwarf: if self.dwarf.context_tid == tid: # clear backtrace if 'backtrace' in self._ui_elems: if self.backtrace_panel is not None: self.backtrace_panel.clear() # remove thread if 'threads' in self._ui_elems: if self.contexts_list_panel is not None: self.contexts_list_panel.resume_tid(tid) # clear registers if 'registers' in self._ui_elems: if self.context_panel is not None: self.context_panel.clear() # clear jvm explorer if 'jvm-debugger' in self._ui_elems: if self.java_explorer_panel is not None: self.java_explorer_panel.clear_panel() # invalidate dwarf context tid self.dwarf.context_tid = 0 def _on_tracer_data(self, data): if not data: return if self.trace_panel is None: self._create_ui_elem('trace') if self.trace_panel is not None: self.show_main_tab('Trace') self.trace_panel.start() trace_events_parts = data[1].split(',') while trace_events_parts: trace_event = TraceEvent(trace_events_parts.pop(0), trace_events_parts.pop(0), trace_events_parts.pop(0), trace_events_parts.pop(0)) self.trace_panel.event_queue.append(trace_event) def _on_set_data(self, data): if not isinstance(data, list): return if self.data_panel is None: self._create_ui_elem('data') if self.data_panel is not None: self.show_main_tab('Data') self.data_panel.append_data(data[0], data[1], data[2]) def show_progress(self, text): self.progressbar.setVisible(True) self.set_status_text(text) def hide_progress(self): self.progressbar.setVisible(False) self.set_status_text('') def _on_attached(self, data): self.setWindowTitle('Dwarf - Attached to %s (%s)' % (data[1], data[0])) def _on_script_loaded(self): # restore the loaded session if any self.session_manager.restore_session() def _on_memory_modified(self, pos, length): data_pos = self.memory_panel.base + pos data = self.memory_panel.data[pos:pos + length] data = [data[0]] # todo: strange js part if self.dwarf.dwarf_api('writeBytes', [data_pos, data]): pass else: utils.show_message_box('Failed to write Memory') def on_add_bookmark(self, ptr): """ provide ptr as int """ if self.bookmarks_panel is not None: self.bookmarks_panel._create_bookmark(ptr=hex(ptr))
class NoteMain(QMainWindow): def __init__(self, parent=None): super(NoteMain, self).__init__(parent) self.setWindowTitle("CSDN 同步笔记(author:rechard)") #os.path.dirname(os.path.realpath(__file__) 获取到当前文件的路径 #self.setWindowIcon(QtGui.QIcon(os.path.join(os.path.dirname(os.path.realpath(__file__)), "icon.png" ))) self.setWindowIcon(QIcon("./images/icon.png")) self.blogCache = BlogCache() self.browser = BrowserWidget() self.browser.cookieAdd.connect(self.on_browser_cookieAdd) self.split = QSplitter() self.articleList = ArticleList() self.articleList.itemClicked.connect(self.articleItemClick) self.initCategory() self.split.addWidget(self.articleList) self.split.addWidget(self.browser) self.toolbar = MDToolBarWidget(self.browser) self.split.addWidget(self.toolbar) self.split.setSizes([0, 0, 900, 0]) self.setCentralWidget(self.split) self.showMaximized() #self.setGeometry(200, 200, 800, 500) self.cookies = {} # 存放domain的key-value self.loginDone = False #self.loginSuccessInit() #点击article list里的选项 def articleItemClick(self, clickItem: ArticleItem): self.showArticleInLeftFrame(clickItem.getBlog()) def on_browser_cookieAdd(self, cookie): # 处理cookie添加的事件 name = cookie.name().data().decode('utf-8') # 先获取cookie的名字,再把编码处理一下 value = cookie.value().data().decode('utf-8') # 先获取cookie值,再把编码处理一下 self.cookies[name] = value if self.cookies.get('UserToken') and not self.loginDone: self.loginSuccessInit() def onLoadFinished(self, finished): if finished and self.cookies.get('UserToken') and not self.loginDone: self.loginSuccessInit() def loginSuccessInit(self): self.initMenu() self.loadAllBlogsCategories() self.loadAllDraftBlogCategories() self.statusBar = QStatusBar() self.setStatusBar(self.statusBar) self.loginDone = True self.browser.setHtml('welcome!') self.split.setSizes([250, 250, 900, 50]) # 显示文章到左边的显示框里 def showArticleInLeftFrame(self, blog: Blog = None): if blog != None: self.browser.setBlog(blog) self.browser.setTitle(blog.title) if blog.url == 'draft': self.showHtml(blog) else: self.backend = LoadArticleThread(blog, CSDNService(self.cookies)) self.backend.trigger.connect(self.showHtml) self.backend.start() def showHtml(self, data: Blog): searchTxt = self.searchTxt.text() html = data.content if len(searchTxt.strip()) > 0: html = html.replace( searchTxt, '<font style=\'background-color:yellow\'>' + searchTxt + '</font>') self.browser.setHtml(html) self.browser.setMD(data.mdText) # 加载loading 条 def startloading(self): self.imageLabel = QLabel() self.movie = QMovie("./images/loading.gif") self.imageLabel.setMovie(self.movie) self.movie.start() self.setCentralWidget(self.imageLabel) def stopLoading(self): self.setCentralWidget(self.browser) def initMenu(self): tb: QToolBar = self.addToolBar("toolbar") add = QAction(QIcon('./images/add.png'), '&新建草稿', self) add.setStatusTip('新建文章') tb.addAction(add) refreshAct = QAction(QIcon('./images/refresh.png'), '&同步文章', self) refreshAct.setShortcut('Ctrl+R') refreshAct.setStatusTip('从csdn同步文章...') tb.addAction(refreshAct) personal = QAction(QIcon('./images/personal.png'), '&个人信息', self) personal.setStatusTip('个人信息') tb.addAction(personal) help = QAction(QIcon('./images/help.png'), '&帮助', self) help.setStatusTip('帮助说明') tb.addAction(help) tb.actionTriggered[QAction].connect(self.windowaction) tb.setFloatable(False) logging.info("menu ini success") def windowaction(self, q): if q.text() == "&新建草稿": self.createDraft() elif q.text() == "&同步文章": self.reloadArticles() elif q.text() == "&个人信息": QMessageBox.about(self, "个人信息", "用户名:%s" % self.cookies['UN']) elif q.text() == "&帮助": QMessageBox.about( self, "帮助说明", ''' 同步csdn文章的一个笔记工具,模仿有道笔记的界面,使用到了python,pyqt5, sqllite等 ''') def createDraft(self): blog = Blog() blog.title = '无标题笔记' blog.category = 'draft' blog.categoryUrl = 'none' blog.content = '' blog.mdText = '' blog.url = 'draft' c = TreeWidgetItem(blog=blog) c.setText(0, blog.title) c.setIcon(0, QIcon("./images/draft.png")) self.draftArticles.addChild(c) # todo: how to focus on new created item BlogCache().saveArticlies([blog]) item = ListWidgetItem(blog=blog) item.setSizeHint(QSize(100, 80)) item.setIcon(QIcon("./images/draft.png")) item.setText(blog.title) self.articleList.addItem(item) def reloadArticles(self): service = CSDNService(self.cookies) #self.reloadPublish=ReloadBlogThread(url='https://blog.csdn.net/guo_xl',service=service,parent=self) self.reloadPublish = ReloadBlogThread(url='https://blog.csdn.net/' + self.cookies['UN'], service=service, parent=self) self.reloadPublish.start() self.reloadPublish.trigger.connect(self.handleReloadMessage) self.reloadDraft = ReloadDraftBlogThread(service=service) self.reloadDraft.start() self.reloadDraft.trigger.connect(self.handleDraftReloadMessage) self.statusBar.showMessage("博客加载中...") MessageTip("开始同步").show() #返回的data是个[],里面装了Blog对象 def handleDraftReloadMessage(self, data): if isinstance(data, str): self.statusBar.showMessage(data) if data == "加载完毕": self.loadAllDraftBlogCategories() elif isinstance(data, List): self.draftArticles.takeChildren() for blog in data: c = TreeWidgetItem(blog=blog) c.setText(0, blog.title) c.setIcon(0, QIcon("./images/draft.png")) self.draftArticles.addChild(c) elif isinstance(data, Blog): self.blogCache.saveArticlies([data]) def handleReloadMessage(self, data): if isinstance(data, str): self.statusBar.showMessage(data) if data == "加载完毕": self.loadAllBlogsCategories() elif isinstance(data, dict): list = data["data"] type = data["type"] if type == BlogLoadType.categories: self.handleDisplayCategories(list) elif type == BlogLoadType.subCategories: categoryName = data["categoryName"] logging.info("处理%s" % categoryName) #找到categoryName对应的menu item #坑爹,不要用publishArticlesCategory.takeChildren()移除所有的item count = self.publishArticlesCategory.childCount() i = 0 while i < count: c = self.publishArticlesCategory.child(i) i += 1 if categoryName == c.text(0): self.handleDisplaySubCategories(list, c) logging.info("处理完%s" % categoryName) return elif isinstance(data, Blog): self.blogCache.saveArticlies([data]) #记载草稿 def loadAllDraftBlogCategories(self): data = self.blogCache.searchAllDraft() self.draftArticles.takeChildren() for blog in data: c = TreeWidgetItem(blog=blog) c.setText(0, blog.title) c.setIcon(0, QIcon("./images/draft.png")) self.draftArticles.addChild(c) item = ListWidgetItem(blog=blog) item.setSizeHint(QSize(100, 80)) item.setIcon(QIcon("./images/draft.png")) item.setText(blog.title) self.articleList.addItem(item) #加载blog's all categories def loadAllBlogsCategories(self): # 注意这里写法 # 这样是错误的,为什么? # backend=BackendThread() # backend.start() # backend.articleCategory.connect(self.handleDisplay) data = self.blogCache.searchAllPublished() publicCategory = self.publishArticlesCategory publicCategory.takeChildren() for k, v in data.items(): child = QTreeWidgetItem() child.setText(0, v.get("category")) # title child.setText(1, v.get("categoryUrl")) # url child.setText(2, 'category') child.setIcon(0, QIcon("./images/folder_close.png")) publicCategory.addChild(child) for blog in v.get("blogs"): c = TreeWidgetItem(blog=blog) c.setText(0, blog.title) c.setIcon(0, QIcon("./images/blog_normal.png")) child.addChild(c) item = ListWidgetItem(blog=blog) item.setSizeHint(QSize(100, 80)) item.setIcon(QIcon("./images/blog_normal.png")) item.setText(blog.title) self.articleList.addItem(item) self.publishArticlesCategory.setDisabled(False) def handleDisplayCategories(self, data): publicCategory = self.publishArticlesCategory for item in data: if self.findCategoryByUrl(item["url"], publicCategory) == None: child = QTreeWidgetItem() child.setText(0, item["title"]) # title child.setText(1, item["url"]) # url child.setText(2, 'category') child.setIcon(0, QIcon("./images/folder_close.png")) publicCategory.addChild(child) def findCategoryByUrl(self, url, widget): total = widget.childCount() i = 0 while i < total: if widget.child(i).text(1) == url: return widget.child(i) i = i + 1 return None def initCategory(self): self.container = QWidget(self) layout = QVBoxLayout(self.container) self.tree = QTreeWidget() # 设置列数 self.tree.setColumnCount(3) self.tree.setColumnHidden(1, True) self.tree.setColumnHidden(2, True) # 设置头的标题 self.tree.setHeaderLabels(['title', 'url', 'category']) self.tree.setHeaderHidden(True) # 设置列宽 self.tree.setColumnWidth(0, 320) self.searchTxt = QLineEdit() self.searchTxt.setPlaceholderText("关键字查询") self.searchTxt.textChanged.connect(self.search) layout.addWidget(self.searchTxt) layout.addWidget(self.tree) self.initPublishArticle() self.initDraftArticle() self.tree.itemClicked.connect(self.onClicked) self.tree.itemCollapsed.connect(self.onCollapsed) self.tree.itemExpanded.connect(self.onExpended) self.split.addWidget(self.container) self.tree.setContextMenuPolicy(Qt.CustomContextMenu) self.tree.customContextMenuRequested.connect(self.onCustomContextMenu) def onCustomContextMenu(self, point): i = self.tree.indexAt(point) menu = QMenu() upload = QAction("上传到CSDN", self) menu.addAction(upload) t = time.time() k = menu.exec_(self.tree.mapToGlobal(point)) #If the menu hasn't been open for more than 0.6s, #assume user did not have time to properly react to it opening if time.time() - t < 0.6: return if k == upload: msg = QMessageBox() msg.setText("同步到csdn") msg.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel) r = msg.exec_() if r == QMessageBox.Yes: MessageTip("开始同步到csdn").show() item = self.tree.currentItem() ut = UpdateThread(item.getBlog(), CSDNService(self.cookies)) ut.update_proess_signal.connect(self.onUploaded) ut.start() def onUploaded(self, code: int): if (code == 200): win = MessageTip("发布到csdn成功") win.show() def onCollapsed(self, index: QModelIndex): index.setIcon(0, QIcon("./images/folder_open.png") ) if index.isExpanded() else index.setIcon( 0, QIcon("./images/folder_close.png")) def onExpended(self, index: QModelIndex): index.setIcon(0, QIcon("./images/folder_open.png") ) if index.isExpanded() else index.setIcon( 0, QIcon("./images/folder_close.png")) def search(self, data): result = self.blogCache.fuzzySearch(data) #public:QTreeWidgetItem=self.publishArticlesCategory # public # total=public.childCount() # i=0 # while i<total: # c=public.child(i) # ctotal=c.childCount() # j=0 # while j<ctotal: # if len(data)>0 and (not result or c.child(j).text(0) not in result): # c.child(j).setHidden(True) # else: # c.child(j).setHidden(False) # j=j+1 # i=i+1 i = 0 articleList: QListWidget = self.articleList total = articleList.count() while i < total: if len(data) > 0 and (not result or articleList.item(i).text() not in result): articleList.item(i).setHidden(True) else: articleList.item(i).setHidden(False) i = i + 1 def onClicked(self): try: item = self.tree.currentItem() if item != None: #None是root节点 if isinstance(item, TreeWidgetItem): self.showArticleInLeftFrame(item.getBlog()) except Exception as ex: logging.exception(ex) #加载category下的子category # def loadSubCategories(self, item:QTreeWidgetItem): # list=item.takeChildren() # list.clear() # #改成异步加载 # logging.info("loading sub category start") # self.backend=BackendThread(url=item.text(1),type=BlogLoadType.subCategories) # self.backend.trigger.connect(lambda data:self.handleDisplaySubCategories(data, item)) # self.backend.start() def handleDisplaySubCategories(self, articles, item): logging.info("loading %s subcategory" % item.text(0)) for i in articles: if self.findCategoryByUrl(i["url"], item) == None: c = QTreeWidgetItem() c.setText(0, i['title']) # title c.setText(1, i['url']) # url c.setText(2, 'article') c.setText(3, i['updateTime']) item.addChild(c) def initDraftArticle(self): self.draftArticles = QTreeWidgetItem(self.tree) self.draftArticles.setText(0, '草稿箱') self.draftArticles.setIcon(0, QIcon("./images/folder_close.png")) self.tree.addTopLevelItem(self.draftArticles) def initPublishArticle(self): self.publishArticlesCategory = QTreeWidgetItem(self.tree) self.publishArticlesCategory.setText(0, '公开文章') self.publishArticlesCategory.setIcon( 0, QIcon("./images/folder_close.png")) self.publishArticlesCategory.setDisabled(True) # self.label = QLabel('', self) # self.movie = QMovie("./images/loading.gif") # self.label.setMovie(self.movie) # self.movie.start() ### 设置节点的背景颜色 #brush_red = QBrush(Qt.red) #self.publishArticles.setBackground(0, brush_red) #brush_green = QBrush(Qt.green) #self.publishArticlesCategories.setBackground(1, brush_green) self.tree.addTopLevelItem(self.publishArticlesCategory) #异步加载文章 #self.statusBar.showMessage("博客加载中...") def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft())
class EEGRecorder(QMainWindow): """docstring for EEGRecorder""" def __init__(self): super(EEGRecorder, self).__init__() self.setWindowTitle('EEG Recorder v2.0') self.setWindowIcon(QIcon('./icons/record.png')) self.resize(480, 640) self.setContentsMargins(10, 10, 10, 10) # Main widgets self.videoDialog = FilePathDialog('Video file:', 'Open video', 'Video files (*.mp4)') self.connectionForm = LSLForm('Lab Streaming Layer') self.personalForm = PersonalInformationForm('Personal Information') # Video player self.player = VideoPlayer() self.player.setSize(640, 480) self.player.error.connect(self.mediaError) self.player.mediaStatusChanged.connect(self.mediaStatusChanged) # Threads self.lsl = LSLClient() self.camera = OCVWebcam() # Buttons self.loadButton = QPushButton('Load') self.loadButton.clicked.connect(self.loadVideo) self.startButton = QPushButton('Start') self.startButton.setEnabled(False) self.startButton.clicked.connect(self.startRecording) self.pauseResumeButton = QPushButton('Pause') self.pauseResumeButton.setEnabled(False) self.pauseResumeButton.clicked.connect(self.pauseAndResume) self.stopSaveButton = QPushButton('Stop && Save') self.stopSaveButton.setEnabled(False) self.stopSaveButton.clicked.connect(self.stopAndSave) # Layouts buttonLayout = QHBoxLayout() buttonLayout.addWidget(self.startButton) buttonLayout.addWidget(self.pauseResumeButton) buttonLayout.addWidget(self.stopSaveButton) mainLayout = QVBoxLayout() mainLayout.addWidget(self.videoDialog, 1) mainLayout.addStretch(1) mainLayout.addWidget(self.loadButton) mainLayout.addStretch(1) mainLayout.addWidget(self.connectionForm, 1) mainLayout.addStretch(1) mainLayout.addWidget(self.personalForm, 1) mainLayout.addStretch(1) mainLayout.addLayout(buttonLayout, 1) # Main widget mainWidget = QWidget() mainWidget.setLayout(mainLayout) self.setCentralWidget(mainWidget) # Status bar self.statusBar = QStatusBar() self.setStatusBar(self.statusBar) self.statusBar.showMessage('¡System ready!') def loadVideo(self): path = self.videoDialog.getFullPath() self.player.loadMedia(path) self.camera.setSource(0, width=640, height=480) self.startButton.setEnabled(True) def mediaError(self): self.statusBar.showMessage('Error: {}'.format( self.player.errorString())) def mediaStatusChanged(self, status): if status == self.player.LoadingMedia: self.statusBar.showMessage('Loading video...') elif status == self.player.LoadedMedia: self.player.show() self.statusBar.showMessage('Video was successfully loaded!') elif status == self.player.EndOfMedia: self.stopAndSave() def startRecording(self): server = self.connectionForm.getValues()['server'] if server == '': self.statusBar.showMessage('¡LSL server not specified!') return self.lsl.setStream('name', server) self.camera.record('video.hdf5') self.lsl.record() if self.player.isVideoAvailable(): self.player.play() self.statusBar.showMessage('Recording...') self.pauseResumeButton.setEnabled(True) self.stopSaveButton.setEnabled(True) self.startButton.setEnabled(False) self.loadButton.setEnabled(False) def pauseAndResume(self): self.lsl.toggle() self.camera.toggle() if self.player.isVideoAvailable(): self.player.toggle() if self.lsl.getState() == LSLClient.PausedState: self.pauseResumeButton.setText('Resume') self.statusBar.showMessage('Paused!') else: self.pauseResumeButton.setText('Pause') self.statusBar.showMessage('Recording...') def stopAndSave(self): self.lsl.stop() self.camera.stop() self.statusBar.showMessage('Stopping LSL thread...') while not self.lsl.isFinished(): pass self.statusBar.showMessage('LSL thread finished!') if self.player.isVideoAvailable(): self.player.stop() self.player.hide() path = QFileDialog.getExistingDirectory(self, 'Select folder', QDir.homePath(), QFileDialog.ShowDirsOnly) if path != '': path += '/' self.saveDataAndVideo(path) else: self.statusBar.showMessage('Files were not saved... data is lost!') self.pauseResumeButton.setEnabled(False) self.stopSaveButton.setEnabled(False) self.startButton.setEnabled(False) self.loadButton.setEnabled(True) def getFilenames(self, path): # File counter i = 1 # Get personal information subject = self.personalForm.getValues() # Create the file base name basename = '{}-{}-{}-{}'.format(subject['name'], subject['last'], subject['age'], subject['sex']) # Get current date date = datetime.today().strftime('%Y-%m-%d') # Add elapsed time and date basename += '_{}'.format(date) # Add file extension filename = basename + '_{}.csv'.format(i) # Complete the full path dataFullPath = path + filename # Evaluate if the file name is already used while QFile(dataFullPath).exists(): i += 1 filename = basename + '_{}.csv'.format(i) dataFullPath = path + filename # Create a new full path to store the video file filename = basename + '_{}.hdf5'.format(i) videoFullPath = path + filename # Return data and video full paths return (dataFullPath, videoFullPath) def saveDataAndVideo(self, path): # Get valid file names dataFullPath, videoFullPath = self.getFilenames(path) # Get the EEG data D = self.lsl.getData() # Get the EEG channels channels = self.connectionForm.getValues()['channels'].strip() channels = channels.split(',') if channels != '' else range( 1, len(D[0]) + 1) # Create a new DataFrame file = pd.DataFrame(D, columns=channels) # Export DataFrame to CSV file.to_csv(dataFullPath, index=False) self.statusBar.showMessage('EEG file saved as {}'.format(dataFullPath)) # Rename video file file = QFile('video.hdf5') file.rename(videoFullPath) self.statusBar.showMessage( 'Video file saved as {}'.format(videoFullPath))
class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName(_fromUtf8("MainWindow")) MainWindow.resize(533, 388) self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName(_fromUtf8("centralwidget")) self.gridLayout = QGridLayout(self.centralwidget) self.gridLayout.setObjectName(_fromUtf8("gridLayout")) self.mainGridLayout = QGridLayout() self.mainGridLayout.setObjectName(_fromUtf8("mainGridLayout")) self.z_Spin = QSpinBox(self.centralwidget) self.z_Spin.setMinimum(1) self.z_Spin.setObjectName(_fromUtf8("z_Spin")) self.mainGridLayout.addWidget(self.z_Spin, 2, 0, 1, 2) self.time_Spin = QSpinBox(self.centralwidget) self.time_Spin.setMinimum(1) self.time_Spin.setObjectName(_fromUtf8("time_Spin")) self.mainGridLayout.addWidget(self.time_Spin, 2, 2, 1, 1) self.openFile_Button = QPushButton(self.centralwidget) self.openFile_Button.setObjectName(_fromUtf8("openFile_Button")) self.mainGridLayout.addWidget(self.openFile_Button, 0, 0, 1, 1) self.DIC_Spin = QSpinBox(self.centralwidget) self.DIC_Spin.setMinimum(1) self.DIC_Spin.setObjectName(_fromUtf8("DIC_Spin")) self.mainGridLayout.addWidget(self.DIC_Spin, 2, 4, 1, 1) self.Z_Label = QLabel(self.centralwidget) self.Z_Label.setObjectName(_fromUtf8("Z_Label")) self.mainGridLayout.addWidget(self.Z_Label, 1, 0, 1, 2) self.correctAtt_Check = QCheckBox(self.centralwidget) self.correctAtt_Check.setObjectName(_fromUtf8("correctAtt_Check")) self.mainGridLayout.addWidget(self.correctAtt_Check, 3, 4, 1, 1) self.Ch_label = QLabel(self.centralwidget) self.Ch_label.setObjectName(_fromUtf8("Ch_label")) self.mainGridLayout.addWidget(self.Ch_label, 1, 3, 1, 1) self.Bkgd_horizontalLayout = QHBoxLayout() self.Bkgd_horizontalLayout.setObjectName( _fromUtf8("Bkgd_horizontalLayout")) self.removeBG_Check = QCheckBox(self.centralwidget) self.removeBG_Check.setObjectName(_fromUtf8("removeBG_Check")) self.Bkgd_horizontalLayout.addWidget(self.removeBG_Check) self.customize_Check = QCheckBox(self.centralwidget) self.customize_Check.setObjectName(_fromUtf8("customize_Check")) self.Bkgd_horizontalLayout.addWidget(self.customize_Check) self.mainGridLayout.addLayout(self.Bkgd_horizontalLayout, 3, 2, 1, 2) self.comboBox = QComboBox(self.centralwidget) self.comboBox.setObjectName(_fromUtf8("comboBox")) self.comboBox.addItem(_fromUtf8("")) self.comboBox.addItem(_fromUtf8("")) self.mainGridLayout.addWidget(self.comboBox, 4, 0, 3, 2) self.fileName_Line = QLineEdit(self.centralwidget) self.fileName_Line.setObjectName(_fromUtf8("fileName_Line")) self.mainGridLayout.addWidget(self.fileName_Line, 0, 1, 1, 4) self.correctDrift_Check = QCheckBox(self.centralwidget) self.correctDrift_Check.setObjectName(_fromUtf8("correctDrift_Check")) self.mainGridLayout.addWidget(self.correctDrift_Check, 3, 0, 1, 2) self.T_Label = QLabel(self.centralwidget) self.T_Label.setObjectName(_fromUtf8("T_Label")) self.mainGridLayout.addWidget(self.T_Label, 1, 2, 1, 1) self.DIC_label = QLabel(self.centralwidget) self.DIC_label.setObjectName(_fromUtf8("DIC_label")) self.mainGridLayout.addWidget(self.DIC_label, 1, 4, 1, 1) self.channel_Spin = QSpinBox(self.centralwidget) self.channel_Spin.setMinimum(1) self.channel_Spin.setMaximum(5) self.channel_Spin.setObjectName(_fromUtf8("channel_Spin")) self.mainGridLayout.addWidget(self.channel_Spin, 2, 3, 1, 1) self.run_Button = QPushButton(self.centralwidget) self.run_Button.setObjectName(_fromUtf8("run_Button")) self.mainGridLayout.addWidget(self.run_Button, 9, 0, 1, 1) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) self.resolution_Spin = QDoubleSpinBox(self.centralwidget) self.resolution_Spin.setSingleStep(0.01) self.resolution_Spin.setProperty("value", 0.21) self.resolution_Spin.setObjectName(_fromUtf8("resolution_Spin")) self.horizontalLayout.addWidget(self.resolution_Spin) self.resolution_Label = QLabel(self.centralwidget) self.resolution_Label.setObjectName(_fromUtf8("resolution_Label")) self.horizontalLayout.addWidget(self.resolution_Label) self.mainGridLayout.addLayout(self.horizontalLayout, 7, 0, 2, 2) self.verticalLayout = QVBoxLayout() self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) self.correctAtt_Spin = QDoubleSpinBox(self.centralwidget) self.correctAtt_Spin.setMaximum(1.0) self.correctAtt_Spin.setMinimum(0.01) self.correctAtt_Spin.setValue(0.1) self.correctAtt_Spin.setSingleStep(0.01) self.correctAtt_Spin.setObjectName(_fromUtf8("correctAtt_Spin")) self.verticalLayout.addWidget(self.correctAtt_Spin) spacerItem = QSpacerItem(88, 37, QSizePolicy.Minimum, QSizePolicy.Expanding) self.verticalLayout.addItem(spacerItem) self.mainGridLayout.addLayout(self.verticalLayout, 4, 4, 5, 1) self.featureSize_verticalLayout = QVBoxLayout() self.featureSize_verticalLayout.setObjectName( _fromUtf8("featureSize_verticalLayout")) self.horizontalLayout_1 = QHBoxLayout() self.horizontalLayout_1.setObjectName(_fromUtf8("horizontalLayout_1")) self.featureSize1_Label = QLabel(self.centralwidget) self.featureSize1_Label.setEnabled(True) self.featureSize1_Label.setObjectName(_fromUtf8("featureSize1_Label")) self.horizontalLayout_1.addWidget(self.featureSize1_Label) self.featureSize1_Spin = oddSpinBox(self.centralwidget) self.featureSize1_Spin.setEnabled(True) self.featureSize1_Spin.setMaximum(999) self.featureSize1_Spin.setSingleStep(2) self.featureSize1_Spin.setObjectName(_fromUtf8("featureSize1_Spin")) self.horizontalLayout_1.addWidget(self.featureSize1_Spin) self.featureSize_verticalLayout.addLayout(self.horizontalLayout_1) self.horizontalLayout_2 = QHBoxLayout() self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) self.featureSize2_Label = QLabel(self.centralwidget) self.featureSize2_Label.setEnabled(True) self.featureSize2_Label.setObjectName(_fromUtf8("featureSize2_Label")) self.horizontalLayout_2.addWidget(self.featureSize2_Label) self.featureSize2_Spin = oddSpinBox(self.centralwidget) self.featureSize2_Spin.setEnabled(True) self.featureSize2_Spin.setMaximum(999) self.featureSize2_Spin.setSingleStep(2) self.featureSize2_Spin.setObjectName(_fromUtf8("featureSize2_Spin")) self.horizontalLayout_2.addWidget(self.featureSize2_Spin) self.featureSize_verticalLayout.addLayout(self.horizontalLayout_2) self.horizontalLayout_3 = QHBoxLayout() self.horizontalLayout_3.setObjectName(_fromUtf8("horizontalLayout_3")) self.featureSize3_Label = QLabel(self.centralwidget) self.featureSize3_Label.setEnabled(True) self.featureSize3_Label.setObjectName(_fromUtf8("featureSize3_Label")) self.horizontalLayout_3.addWidget(self.featureSize3_Label) self.featureSize3_Spin = oddSpinBox(self.centralwidget) self.featureSize3_Spin.setEnabled(True) self.featureSize3_Spin.setMaximum(999) self.featureSize3_Spin.setSingleStep(2) self.featureSize3_Spin.setObjectName(_fromUtf8("featureSize3_Spin")) self.horizontalLayout_3.addWidget(self.featureSize3_Spin) self.featureSize_verticalLayout.addLayout(self.horizontalLayout_3) self.horizontalLayout_5 = QHBoxLayout() self.horizontalLayout_5.setObjectName(_fromUtf8("horizontalLayout_5")) self.featureSize4_Label = QLabel(self.centralwidget) self.featureSize4_Label.setEnabled(True) self.featureSize4_Label.setObjectName(_fromUtf8("featureSize4_Label")) self.horizontalLayout_5.addWidget(self.featureSize4_Label) self.featureSize4_Spin = oddSpinBox(self.centralwidget) self.featureSize4_Spin.setEnabled(True) self.featureSize4_Spin.setMaximum(999) self.featureSize4_Spin.setSingleStep(2) self.featureSize4_Spin.setObjectName(_fromUtf8("featureSize4_Spin")) self.horizontalLayout_5.addWidget(self.featureSize4_Spin) self.featureSize_verticalLayout.addLayout(self.horizontalLayout_5) self.horizontalLayout_8 = QHBoxLayout() self.horizontalLayout_8.setObjectName(_fromUtf8("horizontalLayout_8")) self.featureSize5_Label = QLabel(self.centralwidget) self.featureSize5_Label.setEnabled(True) self.featureSize5_Label.setObjectName(_fromUtf8("featureSize5_Label")) self.horizontalLayout_8.addWidget(self.featureSize5_Label) self.featureSize5_Spin = oddSpinBox(self.centralwidget) self.featureSize5_Spin.setEnabled(True) self.featureSize5_Spin.setMaximum(999) self.featureSize5_Spin.setSingleStep(2) self.featureSize5_Spin.setObjectName(_fromUtf8("featureSize5_Spin")) self.horizontalLayout_8.addWidget(self.featureSize5_Spin) self.featureSize_verticalLayout.addLayout(self.horizontalLayout_8) spacerItem1 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) self.featureSize_verticalLayout.addItem(spacerItem1) self.mainGridLayout.addLayout(self.featureSize_verticalLayout, 4, 2, 5, 2) self.gridLayout.addLayout(self.mainGridLayout, 0, 0, 1, 1) self.resolution_Label.raise_() MainWindow.setCentralWidget(self.centralwidget) self.statusBar = QStatusBar(MainWindow) self.statusBar.setObjectName(_fromUtf8("statusBar")) MainWindow.setStatusBar(self.statusBar) self.featureSpins = [ self.featureSize1_Spin, self.featureSize2_Spin, self.featureSize3_Spin, self.featureSize4_Spin, self.featureSize5_Spin ] self.featureLabels = [ self.featureSize1_Label, self.featureSize2_Label, self.featureSize3_Label, self.featureSize4_Label, self.featureSize5_Label ] self.defaultFeatureValue = 301 self.initialSetup() self.retranslateUi(MainWindow) self.connectUI() QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None)) self.openFile_Button.setText(_translate("MainWindow", "Open", None)) self.Z_Label.setText(_translate("MainWindow", "Z", None)) self.correctAtt_Check.setText( _translate("MainWindow", "Correct Attenuation", None)) self.Ch_label.setText(_translate("MainWindow", "C", None)) self.removeBG_Check.setText( _translate("MainWindow", "Remove Bkgd", None)) self.customize_Check.setText( _translate("MainWindow", "Customize", None)) self.comboBox.setItemText(0, _translate("MainWindow", "czt", None)) self.comboBox.setItemText(1, _translate("MainWindow", "zct", None)) self.correctDrift_Check.setText( _translate("MainWindow", "Correct Drift", None)) self.T_Label.setText(_translate("MainWindow", "T", None)) self.DIC_label.setText(_translate("MainWindow", "DIC", None)) self.run_Button.setText(_translate("MainWindow", "Run", None)) self.resolution_Label.setText(_translate("MainWindow", "um/pix", None)) self.featureSize1_Label.setText( _translate("MainWindow", "Feature Size Ch X", None)) self.featureSize2_Label.setText( _translate("MainWindow", "Feature Size Ch 2", None)) self.featureSize3_Label.setText( _translate("MainWindow", "Feature Size Ch 3", None)) self.featureSize4_Label.setText( _translate("MainWindow", "Feature Size Ch 4", None)) self.featureSize5_Label.setText( _translate("MainWindow", "Feature Size Ch 5", None)) def initialSetup(self): for feature in self.featureSpins: feature.setValue(self.defaultFeatureValue) self.noBckgdChecked() self.correctAttClicked(False) self.run_Button.setEnabled(False) self.z_Spin.setValue(18) self.time_Spin.setValue(4) self.channel_Spin.setValue(3) self.DIC_Spin.setValue(3) self.fileName_Line.setText( '/home/renat/Documents/work/development/example/W9F004T0001Z01C1.tif' ) # # self.z_Spin.setValue(1) # # self.time_Spin.setValue(17) # # self.channel_Spin.setValue(3) # # self.DIC_Spin.setValue(1) # # self.fileName_Line.setText('/home/renat/Documents/work/development/test/TESTME_BGLI141_1B_t2.tif') # # # self.z_Spin.setValue(5) # # self.time_Spin.setValue(7) # # self.channel_Spin.setValue(3) # # self.DIC_Spin.setValue(3) # # self.fileName_Line.setText('/home/renat/Documents/work/development/test/OD3465-0002.tif_Files/OD3465-0002_z0t0c0.tif') self.run_Button.setEnabled(True) # # # self.z_Spin.setValue(5) # # self.time_Spin.setValue(7) # # self.channel_Spin.setValue(3) # # self.DIC_Spin.setValue(3) # # self.fileName_Line.setText('/home/renat/Documents/work/development/test/OD3465-0003_2x2.tif_Files/OD3465-0003_2x2_z0t0c0.tif') # # self.resolution_Spin.setValue(0.42) # # self.run_Button.setEnabled(True)0 def connectUI(self): self.openFile_Button.clicked.connect(self.openFile) self.run_Button.clicked.connect(self.run) self.correctAtt_Check.toggled.connect(self.correctAttClicked) self.channel_Spin.valueChanged.connect(self.channelNumChanged) self.DIC_Spin.valueChanged.connect(self.DIC_changed) self.removeBG_Check.toggled.connect(self.removeBGClicked) self.customize_Check.toggled.connect(self.customBGClicked) # for i in range(len(self.featureSpins)): # self.featureSpins[i].valueChanged.connect(self.checkOdd) def openFile(self): fileFilter = "TIF (*.tif)" fileName = QFileDialog.getOpenFileName( self.centralwidget, 'Open File', '/home/renat/Documents/work/development/Well005/', fileFilter) self.fileName_Line.setText(_translate("MainWindow", fileName[0], None)) self.run_Button.setEnabled(True) def correctAttClicked(self, state): self.correctAtt_Spin.setEnabled(state) self.correctAtt_Spin.setVisible(state) if state: self.removeBG_Check.setChecked(True) def removeBGClicked(self, state): if state: self.customize_Check.setVisible(True) self.customize_Check.setEnabled(True) if self.channel_Spin.value() > 1: self.showFeatureSize(0, True) else: self.noBckgdChecked() def customBGClicked(self, state): nCh = self.channel_Spin.value() if state: self.showFeatureSize(0, False) self.featureSize1_Label.setText("Feature Size Ch 1") for i in range(nCh): if i != self.DIC_Spin.value() - 1: self.showFeatureSize(i, True) else: self.hideAllFeatures() self.featureSize1_Label.setText("Feature Size Ch X") if self.channel_Spin.value() > 1: self.showFeatureSize(0, True) def channelNumChanged(self, nCh): self.DIC_Spin.setMaximum(nCh) if self.customize_Check.isChecked(): self.customBGClicked(False) self.customBGClicked(True) def DIC_changed(self): if self.customize_Check.isChecked(): self.customBGClicked(False) self.customBGClicked(True) def hideAllFeatures(self): for i in range(len(self.featureLabels)): self.showFeatureSize(i, False) def noBckgdChecked(self): self.correctAtt_Check.setChecked(False) self.hideAllFeatures() self.customize_Check.setChecked(False) self.customize_Check.setEnabled(False) self.customize_Check.setVisible(False) def showFeatureSize(self, ch, bool): self.featureSpins[ch].setEnabled(bool) self.featureSpins[ch].setVisible(bool) self.featureLabels[ch].setVisible(bool) def checkOdd(self, val): if val % 2 == 0: self.centralwidget.sender().setValue(val + 1) def run(self): self.statusBar.showMessage('Running...') QApplication.processEvents() if self.customize_Check.isChecked(): featureList = [] for f in self.featureSpins: featureList.append(f.value()) else: featureList = [ self.featureSize1_Spin.value() for i in range(self.channel_Spin.value()) ] featureList[self.DIC_Spin.value() - 1] = None self.statusBar.showMessage('Loading images...') imgs = self.openImage() self.statusBar.showMessage('Cropping...') try: allEmbs = cropAPI.cropEmbs(imgs, self.DIC_Spin.value() - 1, self.correctDrift_Check.isChecked(), \ self.correctAtt_Check.isChecked(), self.correctAtt_Spin.value(), self.removeBG_Check.isChecked(), featureList, self.resolution_Spin.value()) self.save(allEmbs) except Exception as err: QMessageBox.warning(self.centralwidget, 'Error', traceback.format_exc()) self.statusBar.showMessage('Error: ' + str(err)) def openImage(self): path, nZ, nT, nCh, order = str(self.fileName_Line.text()), self.z_Spin.value(), self.time_Spin.value(), \ self.channel_Spin.value(), str(self.comboBox.currentText()) if os.path.isfile(path): ims = myFunc.loadImTif(path) if len(ims.shape) == 2: path = '/'.join(path.split('/')[:-1]) + '/' ims = myFunc.loadImFolder(path) elif os.path.isdir(path): ims = myFunc.loadImFolder(path) else: raise ('Error: wrong path {0}'.format(path)) if len(ims.shape) > 3: ims = np.reshape(ims, (-1, ims.shape[-2], ims.shape[-1])) if np.array(ims).size == nZ * nT * nCh * ims[0].size: if order == 'czt': ims = np.reshape(ims, (nT, nZ, nCh, ims[0].shape[0], ims[0].shape[1])).astype(np.float) else: ims = np.reshape(ims, (nT, nCh, nZ, ims[0].shape[0], ims[0].shape[1])).astype(np.float) ims = np.swapaxes(ims, 1, 2) else: self.statusBar.showMessage( 'Error: number of images (or sizes) does not correspond to z={0}, t={1}, ch={2}' .format(nZ, nT, nCh)) raise Exception( 'Error: number of images (or sizes) does not correspond to z={0}, t={1}, ch={2}' .format(nZ, nT, nCh)) return ims def save(self, allEmbs): path = '/'.join(str(self.fileName_Line.text()).split('/')[:-1]) + '/' if not os.path.exists(path + 'crop/'): myFunc.mkdir_p(path + 'crop/') for i in range(len(allEmbs)): self.statusBar.showMessage('saving Embryo {}'.format(i + 1)) myFunc.saveImagesMulti(allEmbs[i].astype(np.uint16), path + 'crop/Emb{0:02}.tif'.format(i)) self.statusBar.showMessage('embryos saved')
class GPSWindow(QDialog): satellites = 0 # Satellites in view hdop = 40 # Horizontal dilution of position def __init__(self, parent=None): super(GPSWindow, self).__init__(parent) self.setupUi() def setupUi(self): self.setObjectName("GPSWindow") self.setModal(True) top = QHBoxLayout(self) ll = QVBoxLayout() self.web = QWebView() ll.addWidget(self.web) self.statusBar = QStatusBar(self) ll.addWidget(self.statusBar) top.addLayout(ll) self.resize(640, 480) self.statusBar.showMessage("No fix") self.web.setHtml('''<!DOCTYPE html> <html> <head> <meta name="viewport" content="initial-scale=1.0, user-scalable=no"> <meta charset="utf-8"> <title>Circles</title> <style> html, body, #map-canvas { height: 100%; margin: 0; padding: 0; } </style> <script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true"></script> <script> var map; var quadcircle; function updatePosition(lat, lng, err){ quadCircle.setMap(map); quadCircle.setCenter(new google.maps.LatLng(lat, lng)); quadCircle.setRadius(err); } function hidePosition(){ quadCircle.setMap(null); } function moveToLocation(lat, lng){ var center = new google.maps.LatLng(lat, lng); map.panTo(center); } function initialize() { // Create the map. map = new google.maps.Map(document.getElementById('map-canvas'), { zoom: 4, center: new google.maps.LatLng(0, 0), mapTypeId: google.maps.MapTypeId.TERRAIN }); // Representation of the quadricopter on map quadCircle = new google.maps.Circle({ strokeColor: '#FF0000', strokeOpacity: 0.8, strokeWeight: 2, fillColor: '#FF0000', fillOpacity: 0.35, map: null }); hidePosition(); } google.maps.event.addDomListener(window, 'load', initialize); </script> </head> <body> <div id="map-canvas"></div> </body> </html>''') def parseNMEA(self, nmeaMessage): fields = nmeaMessage.split(',') # Recommended Minimum if fields[0] == '$GPRMC': if fields[3] != '' and fields[5] != '': lat = float(fields[3]) * (1.0 if fields[4] == 'N' else -1.0) lon = float(fields[5]) * (1.0 if fields[4] == 'E' else -1.0) lat = int(lat/100) + (lat - (int(lat/100) * 100)) / 60 lon = int(lon/100) + (lon - (int(lon/100) * 100)) / 60 self.web.page().mainFrame().evaluateJavaScript('moveToLocation(%f, %f)' % (lat, lon)) self.web.page().mainFrame().evaluateJavaScript('updatePosition(%f, %f, %d)' % (lat, lon, self.hdop * 2.5)) self.statusBar.showMessage("Fix, %d satellites in view" % (self.satellites)) else: self.statusBar.showMessage("No fix, %d satellites in view" % (self.satellites)) self.web.page().mainFrame().evaluateJavaScript('hidePosition()') elif fields[0] == '$GPGSV': self.satellites = int(fields[3]) elif fields[0] == '$GPGSA': self.hdop = float(fields[16]) def newData(self, string): data = string.rstrip('\r\n').split() if data[0] != 'GPS': return self.parseNMEA(' '.join(data[1:])) def newMessage(self, message, data): if message == 'GPS': self.parseNMEA(data)
class MainWindow_Ui(QMainWindow): def __init__(self, persepolis_setting): super().__init__() # MainWindow self.persepolis_setting = persepolis_setting # add support for other languages locale = str(self.persepolis_setting.value('settings/locale')) QLocale.setDefault(QLocale(locale)) self.translator = QTranslator() if self.translator.load(':/translations/locales/ui_' + locale, 'ts'): QCoreApplication.installTranslator(self.translator) # set ui direction ui_direction = self.persepolis_setting.value('ui_direction') if ui_direction == 'rtl': self.setLayoutDirection(Qt.RightToLeft) elif ui_direction in 'ltr': self.setLayoutDirection(Qt.LeftToRight) icons = ':/' + \ str(self.persepolis_setting.value('settings/icons')) + '/' self.setWindowTitle(QCoreApplication.translate("mainwindow_ui_tr", "Persepolis Download Manager")) self.setWindowIcon(QIcon.fromTheme('persepolis', QIcon(':/persepolis.svg'))) self.centralwidget = QWidget(self) self.verticalLayout = QVBoxLayout(self.centralwidget) # enable drag and drop self.setAcceptDrops(True) # frame self.frame = QFrame(self.centralwidget) # download_table_horizontalLayout download_table_horizontalLayout = QHBoxLayout() tabels_splitter = QSplitter(Qt.Horizontal) # category_tree self.category_tree_qwidget = QWidget(self) category_tree_verticalLayout = QVBoxLayout() self.category_tree = CategoryTreeView(self) category_tree_verticalLayout.addWidget(self.category_tree) self.category_tree_model = QStandardItemModel() self.category_tree.setModel(self.category_tree_model) category_table_header = [QCoreApplication.translate("mainwindow_ui_tr", 'Category')] self.category_tree_model.setHorizontalHeaderLabels( category_table_header) self.category_tree.header().setStretchLastSection(True) self.category_tree.header().setDefaultAlignment(Qt.AlignCenter) # queue_panel self.queue_panel_widget = QWidget(self) queue_panel_verticalLayout_main = QVBoxLayout(self.queue_panel_widget) # queue_panel_show_button self.queue_panel_show_button = QPushButton(self) queue_panel_verticalLayout_main.addWidget(self.queue_panel_show_button) # queue_panel_widget_frame self.queue_panel_widget_frame = QFrame(self) self.queue_panel_widget_frame.setFrameShape(QFrame.StyledPanel) self.queue_panel_widget_frame.setFrameShadow(QFrame.Raised) queue_panel_verticalLayout_main.addWidget( self.queue_panel_widget_frame) queue_panel_verticalLayout = QVBoxLayout(self.queue_panel_widget_frame) queue_panel_verticalLayout_main.setContentsMargins(50, -1, 50, -1) # start_end_frame self.start_end_frame = QFrame(self) # start time start_verticalLayout = QVBoxLayout(self.start_end_frame) self.start_checkBox = QCheckBox(self) start_verticalLayout.addWidget(self.start_checkBox) self.start_frame = QFrame(self) self.start_frame.setFrameShape(QFrame.StyledPanel) self.start_frame.setFrameShadow(QFrame.Raised) start_frame_verticalLayout = QVBoxLayout(self.start_frame) self.start_time_qDataTimeEdit = QDateTimeEdit(self.start_frame) self.start_time_qDataTimeEdit.setDisplayFormat('H:mm') start_frame_verticalLayout.addWidget(self.start_time_qDataTimeEdit) start_verticalLayout.addWidget(self.start_frame) # end time self.end_checkBox = QCheckBox(self) start_verticalLayout.addWidget(self.end_checkBox) self.end_frame = QFrame(self) self.end_frame.setFrameShape(QFrame.StyledPanel) self.end_frame.setFrameShadow(QFrame.Raised) end_frame_verticalLayout = QVBoxLayout(self.end_frame) self.end_time_qDateTimeEdit = QDateTimeEdit(self.end_frame) self.end_time_qDateTimeEdit.setDisplayFormat('H:mm') end_frame_verticalLayout.addWidget(self.end_time_qDateTimeEdit) start_verticalLayout.addWidget(self.end_frame) self.reverse_checkBox = QCheckBox(self) start_verticalLayout.addWidget(self.reverse_checkBox) queue_panel_verticalLayout.addWidget(self.start_end_frame) # limit_after_frame self.limit_after_frame = QFrame(self) # limit_checkBox limit_verticalLayout = QVBoxLayout(self.limit_after_frame) self.limit_checkBox = QCheckBox(self) limit_verticalLayout.addWidget(self.limit_checkBox) # limit_frame self.limit_frame = QFrame(self) self.limit_frame.setFrameShape(QFrame.StyledPanel) self.limit_frame.setFrameShadow(QFrame.Raised) limit_verticalLayout.addWidget(self.limit_frame) limit_frame_verticalLayout = QVBoxLayout(self.limit_frame) # limit_spinBox limit_frame_horizontalLayout = QHBoxLayout() self.limit_spinBox = QDoubleSpinBox(self) self.limit_spinBox.setMinimum(1) self.limit_spinBox.setMaximum(1023) limit_frame_horizontalLayout.addWidget(self.limit_spinBox) # limit_comboBox self.limit_comboBox = QComboBox(self) self.limit_comboBox.addItem("") self.limit_comboBox.addItem("") limit_frame_horizontalLayout.addWidget(self.limit_comboBox) limit_frame_verticalLayout.addLayout(limit_frame_horizontalLayout) # limit_pushButton self.limit_pushButton = QPushButton(self) limit_frame_verticalLayout.addWidget(self.limit_pushButton) # after_checkBox self.after_checkBox = QtWidgets.QCheckBox(self) limit_verticalLayout.addWidget(self.after_checkBox) # after_frame self.after_frame = QtWidgets.QFrame(self) self.after_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.after_frame.setFrameShadow(QtWidgets.QFrame.Raised) limit_verticalLayout.addWidget(self.after_frame) after_frame_verticalLayout = QVBoxLayout(self.after_frame) # after_comboBox self.after_comboBox = QComboBox(self) self.after_comboBox.addItem("") after_frame_verticalLayout.addWidget(self.after_comboBox) # after_pushButton self.after_pushButton = QPushButton(self) after_frame_verticalLayout.addWidget(self.after_pushButton) queue_panel_verticalLayout.addWidget(self.limit_after_frame) category_tree_verticalLayout.addWidget(self.queue_panel_widget) # keep_awake_checkBox self.keep_awake_checkBox = QCheckBox(self) queue_panel_verticalLayout.addWidget(self.keep_awake_checkBox) self.category_tree_qwidget.setLayout(category_tree_verticalLayout) tabels_splitter.addWidget(self.category_tree_qwidget) # download table widget self.download_table_content_widget = QWidget(self) download_table_content_widget_verticalLayout = QVBoxLayout( self.download_table_content_widget) self.download_table = DownloadTableWidget(self) download_table_content_widget_verticalLayout.addWidget( self.download_table) tabels_splitter.addWidget(self.download_table_content_widget) self.download_table.setColumnCount(13) self.download_table.setSelectionBehavior(QAbstractItemView.SelectRows) self.download_table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.download_table.verticalHeader().hide() # hide gid and download dictioanry section self.download_table.setColumnHidden(8, True) self.download_table.setColumnHidden(9, True) download_table_header = [QCoreApplication.translate("mainwindow_ui_tr", 'File Name'), QCoreApplication.translate("mainwindow_ui_tr",'Status'), QCoreApplication.translate("mainwindow_ui_tr", 'Size'), QCoreApplication.translate("mainwindow_ui_tr", 'Downloaded'), QCoreApplication.translate("mainwindow_ui_tr", 'Percentage'), QCoreApplication.translate("mainwindow_ui_tr", 'Connections'), QCoreApplication.translate("mainwindow_ui_tr", 'Transfer rate'), QCoreApplication.translate("mainwindow_ui_tr",'Estimated time left'), 'Gid', QCoreApplication.translate("mainwindow_ui_tr",'Link'), QCoreApplication.translate("mainwindow_ui_tr", 'First try date'), QCoreApplication.translate("mainwindow_ui_tr", 'Last try date'), QCoreApplication.translate("mainwindow_ui_tr",'Category')] self.download_table.setHorizontalHeaderLabels(download_table_header) # fixing the size of download_table when window is Maximized! self.download_table.horizontalHeader().setSectionResizeMode(0) self.download_table.horizontalHeader().setStretchLastSection(True) tabels_splitter.setStretchFactor(0, 3) # category_tree width tabels_splitter.setStretchFactor(1, 10) # ratio of tables's width download_table_horizontalLayout.addWidget(tabels_splitter) self.frame.setLayout(download_table_horizontalLayout) self.verticalLayout.addWidget(self.frame) self.setCentralWidget(self.centralwidget) # menubar self.menubar = QMenuBar(self) self.menubar.setGeometry(QRect(0, 0, 600, 24)) self.setMenuBar(self.menubar) fileMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", '&File')) editMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", '&Edit')) viewMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", '&View')) downloadMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", '&Download')) queueMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", '&Queue')) videoFinderMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", 'V&ideo Finder')) helpMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", '&Help')) # viewMenu submenus sortMenu = viewMenu.addMenu(QCoreApplication.translate("mainwindow_ui_tr", 'Sort by')) # statusbar self.statusbar = QStatusBar(self) self.setStatusBar(self.statusbar) self.statusbar.showMessage(QCoreApplication.translate("mainwindow_ui_tr", "Persepolis Download Manager")) # toolBar self.toolBar2 = QToolBar(self) self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar2) self.toolBar2.setWindowTitle(QCoreApplication.translate("mainwindow_ui_tr", 'Menu')) self.toolBar2.setFloatable(False) self.toolBar2.setMovable(False) self.toolBar = QToolBar(self) self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) self.toolBar.setWindowTitle(QCoreApplication.translate("mainwindow_ui_tr", 'Toolbar')) self.toolBar.setFloatable(False) self.toolBar.setMovable(False) #toolBar and menubar and actions self.videoFinderAddLinkAction = QAction(QIcon(icons + 'video_finder'), QCoreApplication.translate("mainwindow_ui_tr", 'Find Video Links'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Download video or audio from Youtube, Vimeo, etc...'), triggered=self.showVideoFinderAddLinkWindow) QShortcut(QKeySequence('Ctrl+I'), self, self.showVideoFinderAddLinkWindow) videoFinderMenu.addAction(self.videoFinderAddLinkAction) self.stopAllAction = QAction(QIcon(icons + 'stop_all'), QCoreApplication.translate("mainwindow_ui_tr", 'Stop all active downloads'), self, statusTip='Stop all active downloads', triggered=self.stopAllDownloads) downloadMenu.addAction(self.stopAllAction) self.sort_file_name_Action = QAction( QCoreApplication.translate("mainwindow_ui_tr", 'File name'), self, triggered=self.sortByName) sortMenu.addAction(self.sort_file_name_Action) self.sort_file_size_Action = QAction( QCoreApplication.translate("mainwindow_ui_tr", 'File size'), self, triggered=self.sortBySize) sortMenu.addAction(self.sort_file_size_Action) self.sort_first_try_date_Action = QAction( QCoreApplication.translate("mainwindow_ui_tr", 'First try date'), self, triggered=self.sortByFirstTry) sortMenu.addAction(self.sort_first_try_date_Action) self.sort_last_try_date_Action = QAction( QCoreApplication.translate("mainwindow_ui_tr", 'Last try date'), self, triggered=self.sortByLastTry) sortMenu.addAction(self.sort_last_try_date_Action) self.sort_download_status_Action = QAction( QCoreApplication.translate("mainwindow_ui_tr", 'Download status'), self, triggered=self.sortByStatus) sortMenu.addAction(self.sort_download_status_Action) self.trayAction = QAction(QCoreApplication.translate("mainwindow_ui_tr", 'Show system tray icon'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Show/Hide system tray icon"), triggered=self.showTray) self.trayAction.setCheckable(True) viewMenu.addAction(self.trayAction) self.showMenuBarAction = QAction( QCoreApplication.translate("mainwindow_ui_tr", 'Show menubar'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Show menubar'), triggered=self.showMenuBar) self.showMenuBarAction.setCheckable(True) viewMenu.addAction(self.showMenuBarAction) self.showSidePanelAction = QAction( QCoreApplication.translate("mainwindow_ui_tr", 'Show side panel'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Show side panel'), triggered=self.showSidePanel) self.showSidePanelAction.setCheckable(True) viewMenu.addAction(self.showSidePanelAction) self.minimizeAction = QAction(QIcon(icons + 'minimize'), QCoreApplication.translate("mainwindow_ui_tr", 'Minimize to system tray'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Minimize to system tray"), triggered=self.minMaxTray) QShortcut(QKeySequence('Ctrl+W'), self, self.minMaxTray) viewMenu.addAction(self.minimizeAction) self.addlinkAction = QAction(QIcon(icons + 'add'), QCoreApplication.translate("mainwindow_ui_tr", 'Add New Download Link'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Add New Download Link"), triggered=self.addLinkButtonPressed) QShortcut(QKeySequence('Ctrl+N'), self, self.addLinkButtonPressed) fileMenu.addAction(self.addlinkAction) self.addtextfileAction = QAction(QIcon(icons + 'file'), QCoreApplication.translate("mainwindow_ui_tr", 'Import links from text file'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Create a Text file and put links in it.line by line!'), triggered=self.importText) fileMenu.addAction(self.addtextfileAction) self.resumeAction = QAction(QIcon(icons + 'play'), QCoreApplication.translate("mainwindow_ui_tr", 'Resume Download'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Resume Download"), triggered=self.resumeButtonPressed) QShortcut(QKeySequence('Ctrl+R'), self, self.resumeButtonPressed) downloadMenu.addAction(self.resumeAction) self.pauseAction = QAction(QIcon(icons + 'pause'), QCoreApplication.translate("mainwindow_ui_tr", 'Pause Download'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Pause Download"), triggered=self.pauseButtonPressed) QShortcut(QKeySequence('Ctrl+C'), self, self.pauseButtonPressed) downloadMenu.addAction(self.pauseAction) self.stopAction = QAction(QIcon(icons + 'stop'), QCoreApplication.translate("mainwindow_ui_tr", 'Stop Download'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Stop/Cancel Download"), triggered=self.stopButtonPressed) QShortcut(QKeySequence('Ctrl+S'), self, self.stopButtonPressed) downloadMenu.addAction(self.stopAction) self.propertiesAction = QAction(QIcon(icons + 'setting'), QCoreApplication.translate("mainwindow_ui_tr", 'Properties'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Properties"), triggered=self.propertiesButtonPressed) QShortcut(QKeySequence('Ctrl+P'), self, self.propertiesButtonPressed) downloadMenu.addAction(self.propertiesAction) self.progressAction = QAction(QIcon(icons + 'window'), QCoreApplication.translate("mainwindow_ui_tr", 'Progress'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Progress"), triggered=self.progressButtonPressed) QShortcut(QKeySequence('Ctrl+Z'), self, self.progressButtonPressed) downloadMenu.addAction(self.progressAction) self.openFileAction = QAction(QIcon( icons + 'file'), QCoreApplication.translate("mainwindow_ui_tr", 'Open file'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Open file'), triggered=self.openFile) fileMenu.addAction(self.openFileAction) self.openDownloadFolderAction = QAction(QIcon( icons + 'folder'), QCoreApplication.translate("mainwindow_ui_tr", 'Open download folder'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Open download folder'), triggered=self.openDownloadFolder) fileMenu.addAction(self.openDownloadFolderAction) self.openDefaultDownloadFolderAction = QAction(QIcon( icons + 'folder'), QCoreApplication.translate("mainwindow_ui_tr", 'Open default download folder'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Open default download folder'), triggered=self.openDefaultDownloadFolder) fileMenu.addAction(self.openDefaultDownloadFolderAction) self.exitAction = QAction(QIcon(icons + 'exit'), QCoreApplication.translate("mainwindow_ui_tr", 'Exit'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Exit"), triggered=self.closeEvent) QShortcut(QKeySequence('Ctrl+Q'), self, self.closeEvent) fileMenu.addAction(self.exitAction) self.clearAction = QAction(QIcon(icons + 'multi_remove'), QCoreApplication.translate("mainwindow_ui_tr", 'Clear download list'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Clear all items in download list'), triggered=self.clearDownloadList) editMenu.addAction(self.clearAction) self.removeSelectedAction = QAction(QIcon(icons + 'remove'), QCoreApplication.translate("mainwindow_ui_tr", 'Remove selected downloads from list'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Remove selected downloads form list'), triggered=self.removeSelected) editMenu.addAction(self.removeSelectedAction) self.removeSelectedAction.setEnabled(False) self.deleteSelectedAction = QAction(QIcon(icons + 'trash'), QCoreApplication.translate("mainwindow_ui_tr", 'Delete selected download files'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Delete selected download files'), triggered=self.deleteSelected) editMenu.addAction(self.deleteSelectedAction) self.deleteSelectedAction.setEnabled(False) self.createQueueAction = QAction(QIcon(icons + 'add_queue'), QCoreApplication.translate("mainwindow_ui_tr", 'Create new queue'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Create new download queue'), triggered=self.createQueue) queueMenu.addAction(self.createQueueAction) self.removeQueueAction = QAction(QIcon(icons + 'remove_queue'), QCoreApplication.translate("mainwindow_ui_tr", 'Remove this queue'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Remove this queue'), triggered=self.removeQueue) queueMenu.addAction(self.removeQueueAction) self.startQueueAction = QAction(QIcon( icons + 'start_queue'), QCoreApplication.translate("mainwindow_ui_tr", 'Start this queue'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Start this queue'), triggered=self.startQueue) queueMenu.addAction(self.startQueueAction) self.stopQueueAction = QAction(QIcon( icons + 'stop_queue'), QCoreApplication.translate("mainwindow_ui_tr", 'Stop this queue'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Stop this queue'), triggered=self.stopQueue) queueMenu.addAction(self.stopQueueAction) self.moveUpSelectedAction = QAction(QIcon(icons + 'multi_up'), QCoreApplication.translate("mainwindow_ui_tr", 'Move up selected items'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Move currently selected items up by one row'), triggered=self.moveUpSelected) queueMenu.addAction(self.moveUpSelectedAction) self.moveDownSelectedAction = QAction(QIcon(icons + 'multi_down'), QCoreApplication.translate("mainwindow_ui_tr", 'Move down selected items'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Move currently selected items down by one row'), triggered=self.moveDownSelected) queueMenu.addAction(self.moveDownSelectedAction) self.preferencesAction = QAction(QIcon(icons + 'preferences'), QCoreApplication.translate("mainwindow_ui_tr", 'Preferences'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Preferences'), triggered=self.openPreferences, menuRole=5) editMenu.addAction(self.preferencesAction) self.aboutAction = QAction(QIcon( icons + 'about'), QCoreApplication.translate("mainwindow_ui_tr", 'About'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'About'), triggered=self.openAbout, menuRole=4) helpMenu.addAction(self.aboutAction) self.issueAction = QAction(QIcon(icons + 'about'), QCoreApplication.translate("mainwindow_ui_tr", 'Report an issue'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Report an issue'), triggered=self.reportIssue) helpMenu.addAction(self.issueAction) self.updateAction = QAction(QIcon(icons + 'about'), QCoreApplication.translate("mainwindow_ui_tr", 'Check for newer version'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Check for newer release'), triggered=self.newUpdate) helpMenu.addAction(self.updateAction) self.logAction = QAction(QIcon(icons + 'about'), QCoreApplication.translate("mainwindow_ui_tr", 'Show log file'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Help'), triggered=self.showLog) helpMenu.addAction(self.logAction) self.helpAction = QAction(QIcon(icons + 'about'), QCoreApplication.translate("mainwindow_ui_tr", 'Help'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Help'), triggered=self.persepolisHelp) helpMenu.addAction(self.helpAction) self.qmenu = MenuWidget(self) self.toolBar2.addWidget(self.qmenu) # labels self.queue_panel_show_button.setText(QCoreApplication.translate("mainwindow_ui_tr", "Hide options")) self.start_checkBox.setText(QCoreApplication.translate("mainwindow_ui_tr", "Start Time")) self.end_checkBox.setText(QCoreApplication.translate("mainwindow_ui_tr", "End Time")) self.reverse_checkBox.setText(QCoreApplication.translate("mainwindow_ui_tr", "Download bottom of\n the list first")) self.limit_checkBox.setText(QCoreApplication.translate("mainwindow_ui_tr", "Limit Speed")) self.limit_comboBox.setItemText(0, "KiB/s") self.limit_comboBox.setItemText(1, "MiB/s") self.limit_pushButton.setText(QCoreApplication.translate("mainwindow_ui_tr", "Apply")) self.after_checkBox.setText(QCoreApplication.translate("mainwindow_ui_tr", "After download")) self.after_comboBox.setItemText(0, QCoreApplication.translate("mainwindow_ui_tr", "Shut Down")) self.keep_awake_checkBox.setText(QCoreApplication.translate("mainwindow_ui_tr", "Keep system awake!")) self.keep_awake_checkBox.setToolTip( QCoreApplication.translate("mainwindow_ui_tr", "<html><head/><body><p>This option is preventing system from going to sleep.\ This is necessary if your power manager is suspending system automatically. </p></body></html>")) self.after_pushButton.setText(QCoreApplication.translate("mainwindow_ui_tr", "Apply")) def changeIcon(self, icons): icons = ':/' + str(icons) + '/' action_icon_dict = {self.stopAllAction: 'stop_all', self.minimizeAction: 'minimize', self.addlinkAction: 'add', self.addtextfileAction: 'file', self.resumeAction: 'play', self.pauseAction: 'pause', self.stopAction: 'stop', self.propertiesAction: 'setting', self.progressAction: 'window', self.openFileAction: 'file', self.openDownloadFolderAction: 'folder', self.openDefaultDownloadFolderAction: 'folder', self.exitAction: 'exit', self.removeSelectedAction: 'multi_remove', self.deleteSelectedAction: 'multi_trash', self.createQueueAction: 'add_queue', self.removeQueueAction: 'remove_queue', self.startQueueAction: 'start_queue', self.stopQueueAction: 'stop_queue', self.preferencesAction: 'preferences', self.aboutAction: 'about', self.issueAction: 'about', self.updateAction: 'about', self.videoFinderAddLinkAction: 'video_finder', self.qmenu: 'menu'} for key in action_icon_dict.keys(): key.setIcon(QIcon(icons + str(action_icon_dict[key])))
class MainWindowUi(QMainWindow): """This class manages the system tray icon of the main program, post-login. """ vpn_connect_section = QVBoxLayout() def __init__(self): super(QMainWindow, self).__init__() # Using a StackedWidget to be able to replace login window # https://stackoverflow.com/questions/13550076 self.cw = QStackedWidget() self.setCentralWidget(self.cw) # Set minimum width of Main Window to 500 pixels self.cw.setMinimumWidth(500) self.setWindowTitle('MerLink - VPN Client for Meraki firewalls') self.link_style = "font-family: verdana, sans-serif; font-style:" \ " normal; font-size: 13px; color: #1795E6;" # Required for Login. Elements should be object variables if they # Could be called by other modules self.username_textfield = QLineEdit() self.password_textfield = QLineEdit() self.guest_user_chkbox = QCheckBox("Use guest account instead") self.password_textfield.setEchoMode(QLineEdit.Password) self.org_dropdown = QComboBox() self.create_vpn_btn = QPushButton("Create VPN Interface") self.create_vpn_tabs = QTabWidget() self.tab_dashboard = QWidget() self.tab_manual = QWidget() self.vpn_opts_layout = QVBoxLayout() def setup_pyqt_slots(self): """Initiate all of the triggers and connects.""" def setup_window(self): """Setup various sections that will be combined.""" self.create_vpn_tabs.addTab(self.tab_dashboard, "Dashboard Setup") self.create_vpn_tabs.addTab(self.tab_manual, "Manual Setup") self.vpn_opts_setup() self.setup_manual_tab() self.setup_dashboard_tab() self.vpn_connect_setup() self.decorate_sections() self.combine_sections_dashboard() # Set the layout once we are done adding elements self.main_window_set_admin_layout() def setup_dashboard_tab(self): """Provide input fields for dashboard-gathered data.""" self.tab_dashboard.layout = QVBoxLayout(self) # Guest users should manually enter their information # Only difference between Guest and Dashboard for UI should be that # Email/pass is prepopulated for dashboard admins (inactivated) email_pass_layout = QVBoxLayout() username_label = QLabel("Email") password_label = QLabel("Password") self.disable_email_pass(True) self.add_all_to_layout( email_pass_layout, [ username_label, self.username_textfield, password_label, self.password_textfield ] ) self.tab_dashboard.layout.addWidget(self.guest_user_chkbox) self.tab_dashboard.layout.addLayout(email_pass_layout) self.tab_dashboard.layout.addLayout(self.vpn_opts_layout) self.tab_dashboard.setLayout(self.tab_dashboard.layout) def disable_email_pass(self, change_to_disabled): """Disable username/password if user should not edit them.""" disable_lineedit(self.username_textfield, change_to_disabled) disable_lineedit(self.password_textfield, change_to_disabled) def vpn_opts_setup(self): """Set up the vpn vars UI region.""" # Create org and network dropdowns so the user can select the firewall # they would like to connect to. org_dropdown = QComboBox() org_dropdown.addItem('-- Select an Organization --') network_dropdown = QComboBox() network_dropdown.setEnabled(False) # Allow the user to change the VPN name vpn_name_layout = QHBoxLayout() vpn_name_label = QLabel("VPN Name:") vpn_name_textfield = QLineEdit() vpn_name_layout.addWidget(vpn_name_label) vpn_name_layout.addWidget(vpn_name_textfield) # Ask the user for int/str values if they want to enter them idle_disconnect_layout = QHBoxLayout() idle_disconnect_chkbox = QCheckBox("Idle disconnect seconds?") idle_disconnect_spinbox = QSpinBox() idle_disconnect_spinbox.setValue(0) # Negative seconds aren't useful here idle_disconnect_spinbox.setMinimum(0) idle_disconnect_layout.addWidget( idle_disconnect_chkbox) idle_disconnect_layout.addWidget( idle_disconnect_spinbox) dns_suffix_layout = QHBoxLayout() dns_suffix_chkbox = QCheckBox("DNS Suffix?") dns_suffix_txtbox = QLineEdit('-') dns_suffix_layout.addWidget(dns_suffix_chkbox) dns_suffix_layout.addWidget(dns_suffix_txtbox) # Boolean asks of the user split_tunneled_chkbox = QCheckBox("Split-Tunnel?") remember_credential_chkbox = QCheckBox("Remember Credentials?") use_winlogon_chkbox = QCheckBox("Use Windows Logon Credentials?") self.add_all_to_layout( self.vpn_opts_layout, [ org_dropdown, network_dropdown, vpn_name_layout, # Add layouts for specialized params idle_disconnect_layout, dns_suffix_layout, # Add checkboxes split_tunneled_chkbox, remember_credential_chkbox, use_winlogon_chkbox, # Ensure that button is at bottom of pane by adding space QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding) ] ) def setup_manual_tab(self): """Gray out options and provide input fields to manually enter data.""" self.tab_manual.layout = QVBoxLayout(self) # User should be able to change email/pass as it's required self.disable_email_pass(False) username_textfield = QLineEdit() password_textfield = QLineEdit() password_textfield.setEchoMode(QLineEdit.Password) username_label = QLabel("Email") password_label = QLabel("Password") vpn_name_label = QLabel("VPN Name") vpn_name_textfield = QLineEdit() server_name_label = QLabel("Server name/IP") server_name_textfield = QLineEdit() shared_secret_label = QLabel("Shared Secret") shared_secret_textfield = QLineEdit() shared_secret_textfield.setEchoMode(QLineEdit.Password) self.add_all_to_layout( self.tab_manual.layout, [ username_label, username_textfield, password_label, password_textfield, vpn_name_label, vpn_name_textfield, server_name_label, server_name_textfield, shared_secret_label, shared_secret_textfield, QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding) ] ) self.tab_manual.setLayout(self.tab_manual.layout) def vpn_connect_setup(self): """Setup the GUI componentst of the right pane.""" vpn_list = QListWidget() ipsum_vpn_interfaces = ['eth', 'wifi'] vpn_list.addItems(ipsum_vpn_interfaces) check_for_probs_cb = QCheckBox( "Check for issues before connecting (recommended)") check_for_probs_cb.setChecked(True) probs_list = QListWidget() problems = ["Forget the milk", "My hovercraft is full of eels"] probs_list.addItems(problems) connect_vpn_btn = QPushButton("Connect") self.add_all_to_layout( self.vpn_connect_section, [ vpn_list, check_for_probs_cb, probs_list, connect_vpn_btn ] ) def decorate_sections(self): """Add a box around each section for readability.""" # Set GroupBox CSS manually because otherwise margins are huge self.setStyleSheet(".QGroupBox { border: 1px solid #ccc;}") def combine_sections_dashboard(self): """Combine left and right panes into a final layout.""" # Create a horizontal line above the status bar to highlight it self.hline = QFrame() self.hline.setFrameShape(QFrame.HLine) self.hline.setFrameShadow(QFrame.Sunken) self.vline = QFrame() self.vline.setFrameShape(QFrame.VLine) self.vline.setFrameShadow(QFrame.Sunken) # Status bar be at bottom and inform user of what the program is doing. self.status = QStatusBar() self.status.showMessage("Status: -") self.status.setStyleSheet("Background:#fff") main_widget = QWidget() main_layout = QVBoxLayout(main_widget) left_pane = QVBoxLayout() left_pane.addWidget(self.create_vpn_tabs) left_pane.addWidget(self.create_vpn_btn) two_pane_layout = QHBoxLayout() two_pane_layout.addLayout(left_pane) two_pane_layout.addWidget(self.vline) two_pane_layout.addLayout(self.vpn_connect_section) main_layout.addLayout(two_pane_layout) main_layout.addWidget(self.hline) main_layout.addWidget(self.status) self.cw.addWidget(main_widget) def main_window_set_admin_layout(self): """Set the dashboard user layout. Hides guest user layout as we will only be connecting with one user. The user will see the username/obfuscated password they entered. """ self.username_textfield.setText( self.login_dict['username']) self.username_textfield.setReadOnly(True) self.password_textfield.setText( self.login_dict['password']) self.password_textfield.setReadOnly(True) def main_window_set_guest_layout(self): """Set the guest user layout. Hides dashboard user layout as we will only be connecting with one user. The user will see blank user/pass text fields where they can enter information for a guest user. """ self.radio_username_textfield.clear() self.radio_username_textfield.setReadOnly(False) self.radio_password_textfield.clear() self.radio_password_textfield.setReadOnly(False) @staticmethod def add_all_to_layout(layout, element_list): """Add all of the elements to the layout.""" for elem in element_list: if isinstance(elem, QWidget): layout.addWidget(elem) elif is_layout(elem): layout.addLayout(elem) elif isinstance(elem, QSpacerItem): layout.addItem(elem) else: print("ERROR: Trying to add illegal element to UI!") exit(1)
class App(QMainWindow): def __init__(self): super().__init__() self.title = 'IT567 Port Scanner' self.left = 10 self.top = 10 self.width = 400 self.height = 400 self.initUI() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.statusBar = QStatusBar() self.setStatusBar(self.statusBar) self.host_label = QLabel("IPs:", self) self.host_label.move(20, 14) self.host_text = QLineEdit(self) self.host_text.move(80, 20) self.host_text.resize(140, 20) self.port_label = QLabel("Ports:", self) self.port_label.move(20, 44) self.port_text = QLineEdit(self) self.port_text.move(80, 50) self.port_text.resize(140, 20) self.tcp_button = QRadioButton("TCP", self) self.tcp_button.move(20, 80) self.tcp_button.setChecked(True) self.udp_button = QRadioButton("UDP", self) self.udp_button.move(80, 80) # Create a button in the window self.button = QPushButton('Scan', self) self.button.move(20, 120) self.button.setAutoDefault(True) self.output = QTextEdit(self) self.output.setReadOnly(True) self.output.move(20, 160) self.output.resize(360, 210) # connect button to function on_click self.button.clicked.connect(self.on_click) self.button.pressed.connect(self.on_pressed) self.show() @pyqtSlot() def on_pressed(self): self.button.setEnabled(False) self.output.clear() @pyqtSlot() def on_click(self): if not self.host_text.text(): self.statusBar.showMessage("No hosts specified") self.button.setEnabled(True) return if not self.port_text.text(): self.statusBar.showMessage("No ports specified") self.button.setEnabled(True) return try: hosts = host_list(self.host_text.text()) ports = port_list(self.port_text.text()) except ValueError as e: self.statusBar.showMessage(str(e)) self.button.setEnabled(True) return self.statusBar.showMessage("Scanning...") for host in hosts: udp = self.udp_button.isChecked() protocol = "UDP" if udp else "TCP" self.output.append("Host {} ({}):".format(host, protocol)) try: for port in scan_host(host, ports, udp=udp): self.output.append(str(port)) except socket.error as e: self.output.append(str(e)) self.output.append("") self.statusBar.clearMessage() self.output.append("Done") self.button.setEnabled(True)
class VideoPlayer(QWidget): def __init__(self, name, file_path, parent=None): super(VideoPlayer, self).__init__(parent) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) # Contains full path self.fileName = file_path self.res = 'answer not yet' btnSize = QSize(16, 16) videoWidget = QVideoWidget() #nameLabel = QLabel("") #nameLabel.setText("Name of the person") openButton = QPushButton("Open Video") openButton.setToolTip("Open Video File") openButton.setStatusTip("Open Video File") openButton.setFixedHeight(24) openButton.setIconSize(btnSize) openButton.setFont(QFont("Noto Sans", 8)) openButton.setIcon( QIcon.fromTheme("document-open", QIcon("D:/_Qt/img/open.png"))) # openButton.clicked.connect(self.abrir) self.result = QPushButton("Result") self.result.setGeometry(QtCore.QRect(500, 400, 141, 51)) self.result.setObjectName("result") self.result.setEnabled(False) self.result.clicked.connect(self.result_window) """ result window event """ self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setFixedHeight(24) self.playButton.setIconSize(btnSize) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.positionSlider = QSlider(Qt.Horizontal) self.positionSlider.setRange(0, 0) self.positionSlider.sliderMoved.connect(self.setPosition) self.statusBar = QStatusBar() self.statusBar.setFont(QFont("Noto Sans", 7)) self.statusBar.setFixedHeight(50) controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) #controlLayout.addWidget(openButton) controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.positionSlider) controlLayout.addWidget(self.result) layout = QVBoxLayout() layout.addWidget(videoWidget) layout.addLayout(controlLayout) layout.addWidget(self.statusBar) self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(self.fileName))) self.playButton.setEnabled(True) #self.statusBar.showMessage(fileName) self.play() self.setLayout(layout) f = "Hello, " + name self.mediaPlayer.setVideoOutput(videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.error.connect(self.handleError) self.statusBar.showMessage(f) def enable_result(self, res): self.res = res self.result.setEnabled(True) print('VideoPlayer, result is enabled') pass def abrir(self): # fileName, _ = QFileDialog.getOpenFileName(self, "Selecciona los mediose", # ".", "Video Files (*.mp4 *.flv *.ts *.mts *.avi)") # if fileName != '': self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(self.fileName))) self.playButton.setEnabled(True) #self.statusBar.showMessage(fileName) self.play() def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def positionChanged(self, position): self.positionSlider.setValue(position) def durationChanged(self, duration): self.positionSlider.setRange(0, duration) def setPosition(self, position): self.mediaPlayer.setPosition(position) def handleError(self): self.playButton.setEnabled(False) self.statusBar.showMessage("Error: " + self.mediaPlayer.errorString()) def result_window(self): print("answer: ", self.res)
class VideoPlayer(QWidget): def __init__(self, parent=None): super(VideoPlayer, self).__init__(parent) self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface) btnSize = QSize(16, 16) videoWidget = QVideoWidget() openButton = QPushButton("Open Video") openButton.setToolTip("Open Video File") openButton.setStatusTip("Open Video File") openButton.setFixedHeight(24) openButton.setIconSize(btnSize) openButton.setFont(QFont("Noto Sans", 8)) openButton.setIcon( QIcon.fromTheme("document-open", QIcon("D:/_Qt/img/open.png"))) openButton.clicked.connect(self.abrir) self.playButton = QPushButton() self.playButton.setEnabled(False) self.playButton.setFixedHeight(24) self.playButton.setIconSize(btnSize) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.playButton.clicked.connect(self.play) self.positionSlider = QSlider(Qt.Horizontal) self.positionSlider.setRange(0, 0) self.positionSlider.sliderMoved.connect(self.setPosition) self.statusBar = QStatusBar() self.statusBar.setFont(QFont("Noto Sans", 7)) self.statusBar.setFixedHeight(14) controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(openButton) controlLayout.addWidget(self.playButton) controlLayout.addWidget(self.positionSlider) layout = QVBoxLayout() layout.addWidget(videoWidget) layout.addLayout(controlLayout) layout.addWidget(self.statusBar) self.setLayout(layout) self.mediaPlayer.setVideoOutput(videoWidget) self.mediaPlayer.stateChanged.connect(self.mediaStateChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.error.connect(self.handleError) self.statusBar.showMessage("Ready") def abrir(self): fileName, _ = QFileDialog.getOpenFileName( self, "Selecciona los mediose", ".", "Video Files (*.mp4 *.flv *.ts *.mts *.avi)") if fileName != '': self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(fileName))) self.playButton.setEnabled(True) self.statusBar.showMessage(fileName) self.play() def play(self): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.mediaPlayer.pause() else: self.mediaPlayer.play() def mediaStateChanged(self, state): if self.mediaPlayer.state() == QMediaPlayer.PlayingState: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) else: self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) def positionChanged(self, position): self.positionSlider.setValue(position) def durationChanged(self, duration): self.positionSlider.setRange(0, duration) def setPosition(self, position): self.mediaPlayer.setPosition(position) def handleError(self): self.playButton.setEnabled(False) self.statusBar.showMessage("Error: " + self.mediaPlayer.errorString())
class Config(QWidget): def __init__(self): super(Config, self).__init__() config_group = QtWidgets.QGroupBox(u"参数配置") lineconfig_group = QtWidgets.QGroupBox(u"线条风格配置") axisconfig_group = QtWidgets.QGroupBox(u"坐标轴风格配置") lineshow_group = QtWidgets.QGroupBox(u"线条风格预览") result_group = QtWidgets.QGroupBox(u"结果展示") # 当前绘图结果 self.fig = None # 当前绘图总数据保存 # 坐标轴信息 self.min_x = 0. self.max_x = 1. self.min_y = 0. self.max_y = 1. self.x_text = u'The number of retrived samples' self.y_text = u'precision @ 256 bins' self.x_tick_list = [0., 0.5, 1.] self.x_label_list = ['0', '0.5', '1.0'] self.y_tick_list = [0., 0.5, 1.] self.y_label_list = ['0', '0.5', '1.0'] # 已有曲线信息 self.formula_list = [] self.ls_list = [] self.lc_list = [] self.lt_list = [] self.mark_list = [] self.mark_density_list = [] # 当前绘图曲线元数据保存 self.ls = '-' self.mark = 'o' self.formula = 'y=x**2' self.lc = '#00ff00' self.lt = 'Our Method' self.md = 5 # 状态栏 self.statusBar = QStatusBar() self.statusBar.setFont(QFont(u'华文楷体', 10)) self.statusBar.showMessage(u"准备就绪") # 编辑公式 self.math = QLineEdit() self.math.setPlaceholderText(u'y=x**2') self.math.setClearButtonEnabled(True) # 线条风格 self.linestyle = QComboBox() self.line_list = ["-", "--", "-.", ":"] for each in self.line_list: self.linestyle.addItem(each) # 标记风格 self.markerstyle = QComboBox() self.marker_list = [ ".", ",", "o", "v", "^", "<", ">", "1", "2", "3", "4" "s", "p", "*", "h", "H", "+", "x", "D", "d", "|", "_" ] for each in self.marker_list: self.markerstyle.addItem(each) # 设置线条标签名称 self.label = QLineEdit() self.label.setPlaceholderText(u'Our Method') self.label.setClearButtonEnabled(True) # 设置线条颜色 self.lineColor = QPushButton('更改线条颜色') self.lineColor.setToolTip("点击此按钮将更改线条颜色!") self.lineColor.setStatusTip("点击此按钮将更改线条颜色!") self.lineColor.clicked.connect(self.changeColor) self.lineColor.resize(self.lineColor.sizeHint()) self.lineColor.installEventFilter(self) # 设置标记密集程度 self.markDensity = QSlider(Qt.Horizontal) self.markDensity.setMinimum(1) self.markDensity.setMaximum(50) self.markDensity.setValue(5) self.markDensity.installEventFilter(self) # 横坐标轴范围 self.x_scale = QLineEdit() self.x_scale.setPlaceholderText(u'0,1') self.x_scale.setClearButtonEnabled(True) # 纵坐标轴范围 self.y_scale = QLineEdit() self.y_scale.setPlaceholderText(u'0,1') self.y_scale.setClearButtonEnabled(True) # 横坐标轴标签名称 self.x_label = QLineEdit() self.x_label.setPlaceholderText(u'The number of retrived samples') self.x_label.setClearButtonEnabled(True) # 纵坐标轴标签名称 self.y_label = QLineEdit() self.y_label.setPlaceholderText(u'precision @ 256 bins') self.y_label.setClearButtonEnabled(True) # 横坐标刻度数量 self.x_ticks = QLineEdit() self.x_ticks.setPlaceholderText(u'100') self.x_ticks.setClearButtonEnabled(True) # 纵坐标刻度数量 self.y_ticks = QLineEdit() self.y_ticks.setPlaceholderText(u'100') self.y_ticks.setClearButtonEnabled(True) # 线条风格预览按钮 self.lineview = QPushButton(u'预览') self.lineview.setToolTip("线条预览!") self.lineview.setStatusTip("线条预览!") self.lineview.clicked.connect(self.showLine) self.lineview.installEventFilter(self) # 布局设置 main_layout = QVBoxLayout() # 参数外层布局 config_outer_layout = QVBoxLayout() # 参数内层布局配置 config_inner_layout = QHBoxLayout() config_inner_layout.addWidget(lineconfig_group) config_inner_layout.setStretchFactor(lineconfig_group, 1) config_inner_layout.addWidget(axisconfig_group) config_inner_layout.setStretchFactor(axisconfig_group, 1) config_inner_layout.addWidget(lineshow_group) config_inner_layout.setStretchFactor(lineshow_group, 1) # 线条布局 line_layout = QFormLayout() line_layout.addRow(u'编辑公式', self.math) line_layout.addRow(u'线条风格', self.linestyle) line_layout.addRow(u'标记风格', self.markerstyle) line_layout.addRow(u'标签名称', self.label) line_layout.addRow(u'颜色配置', self.lineColor) line_layout.addRow(u'标记密度', self.markDensity) lineconfig_group.setLayout(line_layout) # 坐标轴布局 tick_layout = QFormLayout() tick_layout.addRow(u'横坐标轴范围', self.x_scale) tick_layout.addRow(u'纵坐标轴范围', self.y_scale) tick_layout.addRow(u'横坐标轴标签名称', self.x_label) tick_layout.addRow(u'纵坐标轴标签名称', self.y_label) tick_layout.addRow(u'横坐标刻度数量', self.x_ticks) tick_layout.addRow(u'纵坐标刻度数量', self.y_ticks) axisconfig_group.setLayout(tick_layout) # 预览布局 view = QVBoxLayout() # 预览显示 self.view_face = QMainWindow() view.addWidget(self.view_face) # 预览按钮 view.addWidget(self.lineview) lineshow_group.setLayout(view) # 中层按钮定义 # 按钮一:显示最终结果 # 按钮二:添加新的线条 # 按钮三:删除最近一条线条 # 按钮四:保存图像 self.showresult = QPushButton(u'刷新视图') self.showresult.setToolTip(u'刷新视图!') self.showresult.clicked.connect(self.resultShow) self.showresult.installEventFilter(self) self.addline = QPushButton(u'新增线条') self.addline.setToolTip(u'新增一条曲线!') self.addline.clicked.connect(self.addLine) self.addline.installEventFilter(self) self.removeline = QPushButton(u'删除线条') self.removeline.setToolTip(u'删除最近一条曲线!') self.removeline.clicked.connect(self.removeLine) self.removeline.installEventFilter(self) self.savefig = QPushButton(u'保存结果') self.savefig.setToolTip(u'将当前结果保存为高清图片!') self.savefig.clicked.connect(self.saveFig) self.savefig.installEventFilter(self) # 中层按钮布局 center_layout = QHBoxLayout() center_layout.addWidget(self.showresult) center_layout.addWidget(self.addline) center_layout.addWidget(self.removeline) center_layout.addWidget(self.savefig) # 第三层按钮定义 file_layout = QHBoxLayout() left_layout = QHBoxLayout() leftl_layout = QFormLayout() self.x_file_path = QLineEdit() self.x_file_path.setFixedHeight(20) leftl_layout.addRow(u"X轴:", self.x_file_path) leftr_layout = QVBoxLayout() x_file_option = QPushButton("选择") x_file_option.setFixedWidth(35) x_file_option.setFixedHeight(20) x_file_option.clicked.connect(self.xFile) leftr_layout.addWidget(x_file_option) left_layout.addLayout(leftl_layout) left_layout.addLayout(leftr_layout) right_layout = QHBoxLayout() rightl_layout = QFormLayout() self.y_file_path = QLineEdit() self.y_file_path.setFixedHeight(20) rightl_layout.addRow(u"Y轴:", self.y_file_path) rightr_layout = QVBoxLayout() y_file_option = QPushButton("选择") y_file_option.setFixedWidth(35) y_file_option.setFixedHeight(20) y_file_option.clicked.connect(self.yFile) rightr_layout.addWidget(y_file_option) right_layout.addLayout(rightl_layout) right_layout.addLayout(rightr_layout) self.selection = QCheckBox(u"自适应") okbt = QPushButton(u"确定") okbt.clicked.connect(self.xyPlot) file_layout.addLayout(left_layout) file_layout.addLayout(right_layout) file_layout.addWidget(self.selection) file_layout.addWidget(okbt) # 设置布局中控件的间距 left_layout.setSpacing(3) right_layout.setSpacing(3) file_layout.setSpacing(20) # 下层状态栏 bottom_layout = QVBoxLayout() bottom_layout.addWidget(self.statusBar) config_outer_layout.addItem(config_inner_layout) config_outer_layout.addItem(center_layout) config_outer_layout.addItem(file_layout) config_outer_layout.addItem(bottom_layout) config_group.setLayout(config_outer_layout) # 结果展示栏,设置为mainWindow result = QVBoxLayout() self.result = QMainWindow() result.addWidget(self.result) result_group.setLayout(result) main_layout.addWidget(config_group) main_layout.setStretchFactor(config_group, 1) main_layout.addWidget(result_group) main_layout.setStretchFactor(result_group, 2) self.setLayout(main_layout) cp = QDesktopWidget().availableGeometry().center() window_width = int(cp.x() * 2 * 0.7) window_height = int(cp.y() * 2 * 0.7) self.setGeometry(cp.x() - window_width // 2, cp.y() - window_height // 2, window_width, window_height) def changeColor(self): col = QColorDialog.getColor() if col.isValid(): self.lc = col.name() self.showLine() def showLine(self): # self.view_face.setFixedWidth(230) # self.view_face.setSizePolicy(self.view_face.sizeHint()) # 获取参数 try: x_scale_text = self.x_scale.text() if x_scale_text == "": x_scale_text = self.x_scale.placeholderText() self.min_x, self.max_x = [ float(k.strip()) for k in x_scale_text.strip().split(',') ] except Exception as ex: pass self.formula = self.math.text() if self.formula == "": self.formula = self.math.placeholderText() self.ls = self.linestyle.currentText() self.mark = self.markerstyle.currentText() self.lt = self.label.text() if self.lt == "": self.lt = self.label.placeholderText() self.md = self.markDensity.value() x0 = np.linspace(self.min_x, self.max_x, 100) try: formula_str = self.formula.split('=')[1] y0 = [eval(formula_str) for x in x0] except Exception as ex: return plt.cla() fig = plt.figure() ax = fig.add_subplot(1, 1, 1) ax.set_xlim(self.min_x, self.max_x) ax.plot(x0, y0, color=self.lc, ls=self.ls, marker=self.mark, label=self.lt, markevery=self.md) plt.subplots_adjust(left=0.17, bottom=0.17, right=0.9, top=0.9, hspace=0.1, wspace=0.3) ax.legend(loc='best') self.fig = fig canvas = FigureCanvas(fig) self.view_face.setCentralWidget(canvas) def resultShow(self): try: x_scale_text = self.x_scale.text() if x_scale_text == "": x_scale_text = self.x_scale.placeholderText() self.min_x, self.max_x = [ float(k.strip()) for k in x_scale_text.strip().split(',') ] except Exception as ex: pass try: y_scale_text = self.y_scale.text() if y_scale_text == "": y_scale_text = self.y_scale.placeholderText() self.min_y, self.max_y = [ float(k.strip()) for k in y_scale_text.strip().split(',') ] except Exception as ex: pass self.x_text = self.x_label.text() if self.x_text == "": self.x_text = self.x_label.placeholderText() self.y_text = self.y_label.text() if self.y_text == "": self.y_text = self.y_label.placeholderText() try: x_tick_str = self.x_ticks.text() if x_tick_str == "": x_tick_str = self.x_ticks.placeholderText() self.x_tick_list = np.linspace(self.min_x, self.max_x, int(x_tick_str.strip())) self.x_label_list = self.x_tick_list except Exception as ex: pass try: y_tick_str = self.y_ticks.text() if y_tick_str == "": y_tick_str = self.y_ticks.placeholderText() self.y_tick_list = np.linspace(self.min_y, self.max_y, int(y_tick_str.strip())) self.y_label_list = self.y_tick_list except Exception as ex: pass fig = plt.figure() ax = fig.add_subplot(1, 1, 1) for index in range(len(self.formula_list)): x0 = np.linspace(self.min_x, self.max_x, 100) y0 = [eval(self.formula_list[index].split('=')[1]) for x in x0] ax.plot(x0, y0, color=self.lc_list[index], ls=self.ls_list[index], marker=self.mark_list[index], markevery=self.mark_density_list[index], label=self.lt_list[index]) ax.legend(loc='best') ax.set_xticks(self.x_tick_list) ax.set_xticklabels(self.x_label_list) ax.set_yticks(self.y_tick_list) ax.set_yticklabels(self.y_label_list) ax.set_xlabel(self.x_text) ax.set_ylabel(self.y_text) ax.set_xlim(self.min_x, self.max_x) ax.set_ylim(self.min_y, self.max_y) self.fig = fig canvas = FigureCanvas(fig) self.result.setCentralWidget(canvas) def addLine(self): try: x = 1 math_txt = self.math.text() if math_txt == "": math_txt = self.math.placeholderText() temp = eval(math_txt.split('=')[1]) self.formula_list.append(math_txt) self.ls_list.append(self.linestyle.currentText()) self.mark_list.append(self.markerstyle.currentText()) label_txt = self.label.text() if label_txt == "": label_txt = self.label.placeholderText() self.lt_list.append(label_txt) self.lc_list.append(self.lc) self.mark_density_list.append(self.md) self.resultShow() except Exception as ex: pass def removeLine(self): try: assert (len(self.formula_list) != 0) self.formula_list.pop() self.ls_list.pop() self.mark_list.pop() self.lt_list.pop() self.lc_list.pop() self.mark_density_list.pop() self.resultShow() except Exception as ex: pass def xFile(self): filename, filetype = QFileDialog.getOpenFileName(self, "选取文件", "./",\ "Text Files (*.txt);;Python Files (*.npy)") if filename != "": self.x_file_path.setText(filename) def yFile(self): filename, filetype = QFileDialog.getOpenFileName(self, "选取文件", "./",\ "Text Files (*.txt);;Python Files (*.npy)") if filename != "": self.y_file_path.setText(filename) def xyPlot(self): fig = plt.figure() ax = fig.add_subplot(1, 1, 1) xfile = self.x_file_path.text() yfile = self.y_file_path.text() x_arr = None y_arr = None if xfile and yfile: if not os.path.exists(xfile) or not os.path.exists(yfile): return xtype = os.path.splitext(xfile)[1] ytype = os.path.splitext(yfile)[1] if xtype != ytype: return if xtype.lower() == '.txt': try: with open(xfile) as fp: xdata = [[each.strip() for each in line.split(',')] for line in fp.readlines()] with open(yfile) as fp: ydata = [[each.strip() for each in line.split(',')] for line in fp.readlines()] x_arr = np.array(xdata, dtype=np.float) y_arr = np.array(ydata, dtype=np.float) if x_arr.shape != y_arr.shape: return except Exception as ex: pass elif xtype.lower() == '.npy': try: x_arr = np.load(xfile) y_arr = np.load(yfile) if x_arr.shape != y_arr.shape: return except Exception as ex: pass if self.selection.checkState(): rd = np.random.RandomState(1234) color_list = rd.rand(x_arr.shape[0], 3) for index in range(x_arr.shape[0]): ax.plot(x_arr[index], y_arr[index], color=color_list[index],\ ls=rd.choice(self.line_list), marker=rd.choice(self.marker_list)) self.fig = fig canvas = FigureCanvas(fig) self.result.setCentralWidget(canvas) else: pass def saveFig(self): dialog = QFileDialog() filename, filetype = dialog.getSaveFileName(self, "图像保存", "./result.png"\ ,"All Files (*);;JPEG Files (*.jpg);;PNG Files (*.png);;SVG Files (*.svg)") self.fig.set_size_inches(8, 6) if filename != "" and self.fig: plt.savefig(filename, dpi=80) self.resultShow() def eventFilter(self, obj, event): if event.type() == QEvent.HoverEnter: if obj == self.lineColor: self.statusBar.showMessage(u"点击此按钮将更改线条颜色!") return False elif obj == self.markDensity: value = self.markDensity.value() self.statusBar.showMessage(str(value)) return False elif obj == self.lineview: self.statusBar.showMessage(u"线条预览!") return False elif obj == self.showresult: self.statusBar.showMessage(u"刷新当前视图,重新显示图片!") return False elif obj == self.addline: self.statusBar.showMessage(u'新增一条曲线!') return False elif obj == self.removeline: self.statusBar.showMessage(u'删去最近的一条曲线!') return False elif obj == self.savefig: self.statusBar.showMessage(u'将当前结果保存为高清图片!') return False elif event.type() == 2 or event.type() == 129: if obj == self.markDensity: value = self.markDensity.value() self.statusBar.showMessage(str(value)) self.showLine() return False else: return False else: return False
class MainWindow(QMainWindow): # pylint: disable=too-many-instance-attributes # pylint: disable=too-many-statements def __init__(self, app, mapLayers, mapLayersCategory): QMainWindow.__init__(self) self.app = app self.mapLayers = mapLayers self.mapLayersCategory = mapLayersCategory self.resize(shared.windowWidth, shared.windowHeight) self.setWindowTitle(shared.progName + ": " + shared.progVer) # Set up the map canvas self.canvas = QgsMapCanvas() self.setCentralWidget(self.canvas) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setCachingEnabled(True) #self.canvas.setMapUpdateInterval(1000) self.canvas.setParallelRenderingEnabled(True) self.canvas.enableMapTileRendering(True) self.canvas.setLayers(self.mapLayers) self.canvas.setExtent(shared.extentRect) self.canvas.setMagnificationFactor(shared.windowMagnification) #mapSet = self.canvas.mapSettings() #print(mapSet.flags()) # Create some actions #self.actionExit = QAction(QIcon('exit.png'), '&Exit', self) self.actionExit = QAction("&Exit", self) self.actionExit.setShortcut("Ctrl+Q") self.actionExit.setStatusTip("Exit " + shared.progName) self.actionZoomIn = QAction("Zoom in", self) self.actionZoomIn.setCheckable(True) #self.actionExit.setShortcut("Ctrl++") self.actionZoomIn.setStatusTip("Show more detail") self.actionZoomOut = QAction("Zoom out", self) self.actionZoomOut.setCheckable(True) #self.actionExit.setShortcut("Ctrl+-") self.actionZoomOut.setStatusTip("Show less detail") self.actionPan = QAction("Pan", self) self.actionPan.setCheckable(True) self.actionPan.setStatusTip("Move the map laterally") self.actionChangeBackground = QAction("Change background", self) self.actionChangeBackground.setStatusTip( "Change the raster background") if not shared.haveRasterBackground: self.actionChangeBackground.setEnabled(False) self.actionCoords = QAction("Show coordinates", self) self.actionCoords.setCheckable(True) self.actionCoords.setStatusTip("Click to show coordinates") self.actionRun = QAction("Simulate", self) self.actionRun.setStatusTip("Route flow") # Connect the actions self.actionExit.triggered.connect(app.quit) self.actionZoomIn.triggered.connect(self.zoomIn) self.actionZoomOut.triggered.connect(self.zoomOut) self.actionPan.triggered.connect(self.pan) self.actionChangeBackground.triggered.connect(self.changeBackground) self.actionCoords.triggered.connect(self.showCoords) self.actionRun.triggered.connect(self.doRun) # Create a menu bar and add menus self.menubar = self.menuBar() self.fileMenu = self.menubar.addMenu("&File") self.fileMenu.addAction(self.actionExit) self.editMenu = self.menubar.addMenu("&Edit") #self.editMenu.addAction(self.actionExit) self.viewMenu = self.menubar.addMenu("&View") self.viewMenu.addAction(self.actionZoomIn) self.viewMenu.addAction(self.actionZoomOut) self.viewMenu.addAction(self.actionPan) self.viewMenu.addAction(self.actionChangeBackground) self.viewMenu.addAction(self.actionCoords) self.runMenu = self.menubar.addMenu("&Run") self.runMenu.addAction(self.actionRun) # Create a tool bar and add some actions self.toolbar = self.addToolBar("Default") self.toolbar.setFloatable(True) self.toolbar.addAction(self.actionRun) self.toolbar.addAction(self.actionZoomIn) self.toolbar.addAction(self.actionZoomOut) self.toolbar.addAction(self.actionPan) self.toolbar.addAction(self.actionCoords) # Create some map tools self.toolPan = QgsMapToolPan(self.canvas) self.toolPan.setAction(self.actionPan) self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # False = in self.toolZoomIn.setAction(self.actionZoomIn) self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # True = out self.toolZoomOut.setAction(self.actionZoomOut) self.toolCoords = PointTool(self.canvas) self.toolCoords.setAction(self.actionCoords) # Put into panning mode self.pan() # Add a status bar self.statusBar = QStatusBar(self.canvas) self.setStatusBar(self.statusBar) # And put a progress indicator on the status bar self.statusBar.progress = QProgressBar(self) self.statusBar.progress.setRange(0, 100) self.statusBar.progress.setMaximumWidth(500) self.statusBar.progress.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.statusBar.addPermanentWidget(self.statusBar.progress) self.myThread = None return #====================================================================================================================== #====================================================================================================================== def doRun(self): # Delete all output features (in case we have some from a previous run) listIDs = [ feat.id() for feat in shared.outFlowMarkerPointLayer.getFeatures() ] prov = shared.outFlowMarkerPointLayer.dataProvider() prov.deleteFeatures([featID for featID in listIDs]) shared.outFlowMarkerPointLayer.updateExtents() shared.outFlowMarkerPointLayer.triggerRepaint() listIDs = [feat.id() for feat in shared.outFlowLineLayer.getFeatures()] prov = shared.outFlowLineLayer.dataProvider() prov.deleteFeatures([featID for featID in listIDs]) shared.outFlowLineLayer.updateExtents() shared.outFlowLineLayer.triggerRepaint() self.canvas.repaint() self.statusBar.progress.setValue(0) self.actionRun.setEnabled(False) # All is now ready, so run the simulation as a separate thread self.myThread = SimulationThread(self.app, self) self.myThread.refresh.connect(self.doRefresh) self.myThread.runDone.connect(self.runDone) self.canvas.freeze(True) #self.canvas.refreshAllLayers() #self.app.processEvents() self.myThread.start() print("\nThread started") return #====================================================================================================================== #====================================================================================================================== def doRefresh(self): self.canvas.freeze(False) if not self.canvas.isDrawing(): shared.outFlowMarkerPointLayer.triggerRepaint() shared.outFlowLineLayer.triggerRepaint() self.canvas.repaint() self.canvas.freeze(True) if not isinstance(shared.flowStartPoints, int): doneSoFar = (float(shared.thisStartPoint) / float(len(shared.flowStartPoints) + 1)) * 100.0 #shared.fpOut.write(doneSoFar) self.statusBar.progress.setValue(doneSoFar) return #====================================================================================================================== #====================================================================================================================== def zoomIn(self): self.canvas.freeze(False) self.canvas.setMapTool(self.toolZoomIn) return #====================================================================================================================== #====================================================================================================================== def zoomOut(self): self.canvas.freeze(False) self.canvas.setMapTool(self.toolZoomOut) return #====================================================================================================================== #====================================================================================================================== def pan(self): self.canvas.freeze(False) self.canvas.setMapTool(self.toolPan) return #====================================================================================================================== #====================================================================================================================== def showCoords(self): self.canvas.setMapTool(self.toolCoords) return #====================================================================================================================== #====================================================================================================================== def close(self): if self.myThread: self.myThread.quit() self.myThread = None return #====================================================================================================================== #====================================================================================================================== def runDone(self): self.canvas.freeze(False) shared.outFlowMarkerPointLayer.triggerRepaint() shared.outFlowLineLayer.triggerRepaint() self.canvas.repaint() print("Thread done") self.myThread.quit() #self.myThread = None self.statusBar.progress.setValue(100) #QMessageBox.information(self, "End of run", shared.progName + ": flow routed") self.statusBar.showMessage("End of run: flow routed", shared.defaultMessageDisplayTime) # To prevent subsequent re-runs # self.actionRun.setEnabled(False) return #====================================================================================================================== #====================================================================================================================== def changeBackground(self): for n in range(len(shared.rasterInputLayersCategory)): if shared.rasterInputLayersCategory[n] == INPUT_RASTER_BACKGROUND: oldOpacity = shared.rasterInputLayers[n].renderer().opacity() if oldOpacity == 0: newOpacity = shared.rasterFileOpacity[n] else: newOpacity = 0 shared.rasterInputLayers[n].renderer().setOpacity(newOpacity) #layerID = shared.rasterInputLayers[n].id() #layerTreeNode = QgsProject.instance().layerTreeRoot().findLayer(layerID) #print(layerTreeNode.dump()) #layerTreeNode.setItemVisibilityChecked(not layerTreeNode.itemVisibilityChecked()) #print(layerTreeNode.dump()) #print("*****************") #for n in range(len(self.mapLayers)): #if self.mapLayersCategory[n] == INPUT_RASTER_BACKGROUND: #self.mapLayers[n].setVisible(not self.mapLayers[n].isVisible()) #self.canvas.setLayers(self.mapLayers) self.doRefresh() return
def _updateStatusBar(self): status = QStatusBar() status.showMessage('Josias') self.setStatusBar(status)
def _createStatusBar(self): status = QStatusBar() status.showMessage("I'm the status bar") self.setStatusBar(status)
class MyWidget(QWidget): def __init__(self, fig, ax, df, title, parent=None): super(MyWidget, self).__init__(parent) #super().__init__() self.legend = [] self.ax = ax self.df = df # Graph ctrl_sys = ControlSys(fig, ax) self.cg = CGraph(fig, ax, ctrl_sys, df, title) self.setWindowTitle(title) self.setGeometry(5,30,400,680) # Vbox self.topLayout = QVBoxLayout(self) # grid # message -> QLayout: Attempting to add QLayout "" to MyWidget "", which already has a layout self.grid=QGridLayout() # Line #self.grid.addWidget(self.Line,0,0) #combo box self.combo_L = QComboBox(self) self.combo_R = QComboBox(self) self.combo_I = QComboBox(self) for hd in df.columns.values: header = hd #str(unicode(hd)) #unicode(hd, 'cp949') # Korean character self.combo_L.addItem(header) self.combo_R.addItem(header) self.combo_I.addItem(header) # Check Box self.grid.addWidget(self.combo_L,0,0) self.cb_L = QCheckBox("L cursor", self) self.grid.addWidget(self.cb_L, 0, 1) self.grid.addWidget(self.combo_R,1,0) self.cb_R = QCheckBox("R cursor", self) self.grid.addWidget(self.cb_R, 1, 1) self.grid.addWidget(self.combo_I,2,0) self.cb_I = QCheckBox("Select X-axis", self) self.grid.addWidget(self.cb_I, 2, 1) # Push Button self.all_Visible=QPushButton('Show All', self) self.all_Visible.clicked.connect(self.AllVisible) self.all_Hide=QPushButton('Hide All', self) self.all_Hide.clicked.connect(self.AllHide) self.grid.addWidget(self.all_Visible,4,0) self.grid.addWidget(self.all_Hide,5,0) # Check Box self.cb_TS = QCheckBox("X-axis is TimeStamp", self) self.grid.addWidget(self.cb_TS, 4, 1) self.cb_scale = QCheckBox("Auto Fit Height", self) self.cb_scale.setCheckState(2) self.grid.addWidget(self.cb_scale, 5, 1) self.b_autoscale = True self.topLayout.addLayout(self.grid) # Scrollable Check Box self.scrollArea = QScrollArea(self) self.scrollArea.setWidgetResizable(True) self.scrollAreaWidgetContents = QWidget(self.scrollArea) self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(5,30,400,680)) self.scrollArea.setWidget(self.scrollAreaWidgetContents) self.topLayout.addWidget(self.scrollArea) self.gridScroll = QGridLayout(self.scrollAreaWidgetContents) self.cb = [] i = 0 # layout index for header in [column for column in df]: c = QCheckBox(header, self) c.stateChanged.connect(self.ToggleVisibility) col_number = 2 # how many columns j = (i-2) // col_number + 2 k = (i-2) % col_number self.gridScroll.addWidget(c, j, k) i += 1 self.cb.append(c) # Status bar self.StatusBar = QStatusBar(self) self.topLayout.addWidget(self.StatusBar) self.StatusBar.showMessage("Happy Day ") self.setLayout(self.topLayout) #self.Line,QtCore.SLOT('setText(QString)')) self.combo_L.activated.connect(lambda: self.select_cursor_data(1)) self.combo_R.activated.connect(lambda: self.select_cursor_data(2)) self.combo_I.activated.connect(self.select_index) self.cb_L.stateChanged.connect(self.cursor_on) self.cb_R.stateChanged.connect(self.cursor_on) self.cb_I.stateChanged.connect(self.index_on) self.cb_TS.stateChanged.connect(self.timestamp_on) self.cb_scale.stateChanged.connect(self.ToggelAutoScale) def index_on(self): if self.cb_I.isChecked(): idx = self.combo_I.currentText() self.cg.select_index(idx) else: self.cg.select_index(None) def select_index(self): self.cb_I.setCheckState(2) idx = self.combo_I.currentText() self.cg.select_index(idx) def timestamp_on(self): if self.cb_TS.isChecked(): idx = self.combo_I.currentText() self.cg.set_timestamp(idx) else: self.cg.set_timestamp(None) def closeEvent(self, event): print ("Closing GUI") sys.exit() def AllVisible(self): i = 0 for each in self.cb: each.setCheckState(2) self.cg.set_visible(i, True) i += 1 self.UpdateDraw() def AllHide(self): i = 0 for each in self.cb: each.setCheckState(0) self.cg.set_visible(i, False) i += 1 self.UpdateDraw() def ToggleVisibility(self): i = 0 for each in self.cb: if each.isChecked(): #checked self.cg.set_visible(i, True) else: self.cg.set_visible(i, False) i += 1 self.UpdateDraw() def UpdateDraw(self): if self.b_autoscale: self.cg.autoscale_y() self.cg.update_draw() def GetAddr(self): return self.addr def ToggelAutoScale(self): self.b_autoscale ^= True if self.b_autoscale: self.cg.autoscale_y() self.cg.update_draw() def cursor_on(self): if self.cb_L.isChecked(): self.cg.cursor_on(1, True) else: self.cg.cursor_on(1, False) if self.cb_R.isChecked(): self.cg.cursor_on(2, True) else: self.cg.cursor_on(2, False) def select_cursor_data(self, btn): if btn == 1: #Left header = self.combo_L.currentText() self.cb_L.setCheckState(2) else: header = self.combo_R.currentText() self.cb_R.setCheckState(2) self.cg.select_cursor_data(btn, header) # check box check clist = list(self.df.columns.values) # make headers to list i = clist.index(header) #find index of the header self.cb[i].setCheckState(2) #check checkbox self.cg.set_visible(i, True) #make visiabel
class MainWindow(QMainWindow): tableContents = [] tableColumnCount = 8 tableRowCount = 10 workerCount = config['worker_num'] # 线程数 workers = [] # 保存线程对象 q = Queue() wtime = [0, 0] bgColor = QColor(180, 200, 230, 40) progressVal = 0 taskVal = 0 def __init__(self): super(MainWindow, self).__init__() self.description = self.tr("""<b>Checker</b><br /><br /> Version: %s<br /> %s<br /><br /> Project: <a href=\"%s\">1dot75cm/repo-checker</a><br /> License: %s<br /> Author: <a href=\"mailto:%s\">%s</a>""") % (__version__, __descript__, __url__, __license__, __email__, __author__) self.tableHeaders = [self.tr("Name"), self.tr("URL"), self.tr("Branch"), self.tr("RPM date [commit]"), self.tr("Release date [commit]"), self.tr("Latest date [commit]"), self.tr("Status"), self.tr("Comment")] self.setupUi(self) def setupUi(self, MainWindow): """初始化主窗口""" MainWindow.setObjectName("MainWindow") MainWindow.setMinimumSize(QSize(910, 450)) MainWindow.setWindowTitle(self.tr("Checker")) MainWindow.setAnimated(True) self.centralwidget = QWidget(MainWindow) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.centralwidget.setSizePolicy(sizePolicy) self.verticalLayout = QVBoxLayout(self.centralwidget) self.verticalLayout.setContentsMargins(5, 5, 5, 5) self.tableWidget = QTableWidget(self.centralwidget) self.setupTable() self.verticalLayout.addWidget(self.tableWidget) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setContentsMargins(5, 5, 5, 5) self.addButton = QPushButton(self.centralwidget) self.addButton.setFixedSize(QSize(25, 25)) self.addButton.setText("+") self.horizontalLayout.addWidget(self.addButton) self.delButton = QPushButton(self.centralwidget) self.delButton.setFixedSize(QSize(25, 25)) self.delButton.setText("-") self.horizontalLayout.addWidget(self.delButton) self.upButton = QPushButton(self.centralwidget) self.upButton.setFixedSize(QSize(25, 25)) self.upButton.setText("↑") self.upButton.setObjectName("up") self.horizontalLayout.addWidget(self.upButton) self.downButton = QPushButton(self.centralwidget) self.downButton.setFixedSize(QSize(25, 25)) self.downButton.setText("↓") self.horizontalLayout.addWidget(self.downButton) spacerItem = QSpacerItem(40, 20, QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem) self.progressBar = QProgressBar(self.centralwidget) self.progressBar.hide() self.horizontalLayout.addWidget(self.progressBar) self.label = QLabel(self.centralwidget) self.horizontalLayout.addWidget(self.label) spacerItem = QSpacerItem(40, 20, QSizePolicy.Minimum, QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem) self.checkButton = QPushButton(self.centralwidget) self.checkButton.setText(self.tr("Check")) self.horizontalLayout.addWidget(self.checkButton) self.updateButton = QPushButton(self.centralwidget) self.updateButton.setText(self.tr("Update item")) self.horizontalLayout.addWidget(self.updateButton) self.editRuleButton = QPushButton(self.centralwidget) self.editRuleButton.setText(self.tr("Edit rule")) self.horizontalLayout.addWidget(self.editRuleButton) self.verticalLayout.addLayout(self.horizontalLayout) MainWindow.setCentralWidget(self.centralwidget) # 菜单 self.menubar = QMenuBar(MainWindow) self.menubar.setGeometry(QRect(0, 0, 780, 34)) MainWindow.setMenuBar(self.menubar) self.fileMenu = QMenu(self.menubar) self.fileMenu.setTitle(self.tr("File")) self.menubar.addAction(self.fileMenu.menuAction()) self.toolMenu = QMenu(self.menubar) self.toolMenu.setTitle(self.tr("Tool")) self.menubar.addAction(self.toolMenu.menuAction()) self.helpMenu = QMenu(self.menubar) self.helpMenu.setTitle(self.tr("Help")) self.menubar.addAction(self.helpMenu.menuAction()) self.statusbar = QStatusBar(MainWindow) MainWindow.setStatusBar(self.statusbar) # 菜单项 self.aboutAction = QAction(MainWindow) self.aboutAction.setText(self.tr("About")) self.aboutAction.setObjectName("about") self.aboutQtAction = QAction(MainWindow) self.aboutQtAction.setText(self.tr("About Qt")) self.aboutQtAction.setObjectName("about_qt") self.openAction = QAction(MainWindow) self.openAction.setText(self.tr("&Open")) self.openAction.setShortcut('Ctrl+O') self.openAction.setStatusTip(self.tr('Open a file')) self.openAction.setObjectName("open") self.openUrlAction = QAction(MainWindow) self.openUrlAction.setText(self.tr("Open &url")) self.openUrlAction.setShortcut('Ctrl+U') self.openUrlAction.setStatusTip(self.tr('Open a file with url')) self.saveAction = QAction(MainWindow) self.saveAction.setText(self.tr("&Save")) self.saveAction.setShortcut('Ctrl+S') self.saveAction.setStatusTip(self.tr('Save a file')) self.saveAction.setObjectName("save") self.saveAsAction = QAction(MainWindow) self.saveAsAction.setText(self.tr("Save As")) self.saveAsAction.setObjectName("save_as") self.closeAction = QAction(MainWindow) self.closeAction.setText(self.tr("&Close")) self.closeAction.setShortcut('Ctrl+W') self.closeAction.setStatusTip(self.tr('Close current page')) self.exitAction = QAction(MainWindow) self.exitAction.setText(self.tr("&Exit")) self.exitAction.setShortcut('Ctrl+Q') self.exitAction.setStatusTip(self.tr('Exit application')) self.settingAction = QAction(MainWindow) self.settingAction.setText(self.tr("&Settings")) self.settingAction.setShortcut('Ctrl+P') self.settingAction.setStatusTip(self.tr('Open settings dialog')) self.helpMenu.addAction(self.aboutAction) self.helpMenu.addAction(self.aboutQtAction) self.toolMenu.addAction(self.settingAction) self.fileMenu.addAction(self.openAction) self.fileMenu.addAction(self.openUrlAction) self.fileMenu.addSeparator() self.fileMenu.addAction(self.saveAction) self.fileMenu.addAction(self.saveAsAction) self.fileMenu.addSeparator() self.fileMenu.addAction(self.closeAction) self.fileMenu.addSeparator() self.fileMenu.addAction(self.exitAction) # Signal & Slot self.addButton.clicked.connect(self.addRowSlot) self.delButton.clicked.connect(self.delRowSlot) self.upButton.clicked.connect(self.moveRowSlot) self.downButton.clicked.connect(self.moveRowSlot) self.checkButton.clicked.connect(self.checkUpdateSlot) self.updateButton.clicked.connect(self.updateTableItemSlot) self.editRuleButton.clicked.connect(self.editTableItemRuleSlot) self.settingAction.triggered.connect(self.showSettingDialogSlot) self.aboutAction.triggered.connect(self.showAboutDialogSlot) self.aboutQtAction.triggered.connect(self.showAboutDialogSlot) self.openAction.triggered.connect(self.showFileDialogSlot) self.openUrlAction.triggered.connect(self.showOpenUrlDialogSlot) self.saveAction.triggered.connect(self.showFileDialogSlot) self.saveAsAction.triggered.connect(self.showFileDialogSlot) self.closeAction.triggered.connect(self.tableWidget.clearContents) self.exitAction.triggered.connect(self.close) self.tableWidget.itemChanged.connect(self.itemChangedSlot) self.tableWidget.itemClicked.connect(self.itemClickedForOpenUrlSlot) def closeEvent(self, event): """关闭应用提示""" reply = QMessageBox.question(self, self.tr('Message'), self.tr("Are you sure to quit?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: event.accept() # 接受关闭事件 else: event.ignore() # 拒绝关闭事件 def itemClickedForOpenUrlSlot(self, item): """Ctrl+left 打开链接""" # http://stackoverflow.com/questions/3100090/ if item.column() == 1 and item.text() and \ qApp.keyboardModifiers() == Qt.ControlModifier: QDesktopServices.openUrl(QUrl(item.text())) # open url def itemChangedSlot(self, item): # QTableWidgetItem """捕获itemChanged信号, 修改表项""" try: self.tableContents[item.row()].load(item.column(), item.text()) except IndexError: pass def moveRowSlot(self): """移动行""" try: sourceRow = self.tableWidget.currentRow() destRow = sourceRow-1 if self.sender().objectName() == "up" else sourceRow+1 if sourceRow != -1: sourceItems = self.getRow(sourceRow) destItems = self.getRow(destRow) self.setRow(destRow, sourceItems) self.setRow(sourceRow, destItems) self.tableWidget.selectRow(destRow) # 修改焦点 log.debug(self.tableContents) except AttributeError: if self.sender().objectName() == "up": QMessageBox.warning(self, self.tr("Warning"), self.tr("The row is to top.")) else: QMessageBox.warning(self, self.tr("Warning"), self.tr("The row is to bottom.")) def getRow(self, rowIndex): """获取行""" rowItems = [] for i in range(7): item = self.tableWidget.item(rowIndex, i) rowItems.append(item.text()) rowItems.append(self.tableContents[rowIndex].get_rules(ui=True)) return rowItems def setRow(self, rowIndex, rowItems): """设置行""" for n, i in enumerate(rowItems): if n == len(rowItems) - 1: self.tableContents[rowIndex].set_rules(i) else: item = self.tableWidget.item(rowIndex, n) item.setText(i) def addRowSlot(self): """添加行""" rowIndex = self.tableWidget.rowCount() self.tableWidget.setRowCount(rowIndex + 1) self.tableContents.append(Checker()) self.updateTableSlot(0) # 更新列表控件 log.debug(self.tableContents) def delRowSlot(self): """删除行""" # 焦点默认在第一行,要设置setFocusPolicy(Qt.NoFocus) rowIndex = self.tableWidget.currentRow() if rowIndex != -1: self.tableWidget.removeRow(rowIndex) self.tableContents.remove(self.tableContents[rowIndex]) log.debug(self.tableContents) else: QMessageBox.warning(self, self.tr("Warning"), self.tr("Please select a row.")) def loadData(self, data): """载入数据""" self.tableContents = [] # list.clear() Python 3 for i in data: self.tableContents.append(Checker(i)) def checkUpdateSlot(self): """执行更新检查""" self.wtime[0] = int(time.time()) # 计时 self.statusbar.showMessage(self.tr("checking...")) self.progressBar.setValue(0) self.progressBar.show() self.progressVal = 0 self.taskVal = 0 for t in range(self.workerCount): t = WorkThread(self.q) # 耗时任务需要用线程执行,再刷新进度条 t.triggered.connect(self.updateTableSlot) self.workers.append(t) t.start() # 执行工作线程 # 填充队列 for item in self.tableContents: self.q.put(item) def updateTableSlot(self, val): """线程通过该槽,刷新进度条,表格内容""" if val: self.taskVal += val self.progressVal = self.taskVal / len(self.tableContents) * 100 self.progressBar.setValue(self.progressVal) self.label.setText("%s/%s" % (self.taskVal, len(self.tableContents))) self.tableWidget.setRowCount(len(self.tableContents)) # 行数 for n, i in enumerate(self.tableContents): items = i.dump() for j in range(self.tableWidget.columnCount()): item = QTableWidgetItem(items[j]) if j in [0, 1]: item.setToolTip(item.text()) self.tableWidget.setItem(n, j, item) self.setStatusColor(n) self.setBackgroundColor(self.bgColor) if self.progressVal == 100: self.wtime[1] = int(time.time()) self.statusbar.showMessage(self.tr( "finished (work time %ds)") % (self.wtime[1] - self.wtime[0])) def updateTableItemSlot(self): """更新指定的 RPM 日期为 Release 日期""" rowIndex = self.tableWidget.currentRow() if rowIndex != -1: try: item = self.tableWidget.item(rowIndex, 4) self.tableWidget.item(rowIndex, 3).setText(item.text()) self.tableContents[rowIndex].load_meta(item.text()) except (IndexError, AttributeError): QMessageBox.warning(self, self.tr("Warning"), self.tr("The row is empty.")) else: QMessageBox.warning(self, self.tr("Warning"), self.tr("Please select a row.")) def editTableItemRuleSlot(self): """编辑列表项规则""" rowIndex = self.tableWidget.currentRow() if rowIndex != -1: try: # 父控件, 标题, 标签提示, 默认值, window flags rules, ok = QInputDialog.getMultiLineText(self, self.tr("Edit rule"), self.tr("XPath rule(format: \"[(time, commit), (time, commit)]\"):"), re.sub("\),|],|',", lambda x: "%s\n" % x.group(), str(self.tableContents[rowIndex].get_rules(ui=True)) )) if ok: self.tableContents[rowIndex].set_rules(rules) except (IndexError, UnboundLocalError): QMessageBox.warning(self, self.tr("Warning"), self.tr("The row is empty.")) else: QMessageBox.warning(self, self.tr("Warning"), self.tr("Please select a row.")) def showSettingDialogSlot(self): """显示设置对话框""" settingDialog = SettingDialog() settingDialog.exec_() def showAboutDialogSlot(self): """显示关于对话框""" if self.sender().objectName() == "about": QMessageBox.about(self, self.tr("Checker"), self.description) else: QMessageBox.aboutQt(self, self.tr("Checker")) def showOpenUrlDialogSlot(self): """通过 Url 打开文件""" url, _ = QInputDialog.getText(self, self.tr("Open url"), self.tr("Enter url:"), QLineEdit.Normal, "") try: resp = backend.get(url) self.loadData(resp.json()) self.updateTableSlot(0) # 更新列表控件 self.statusbar.showMessage(self.tr("open url successfully")) except Exception as e: QMessageBox.warning(self, self.tr("Error"), self.tr("Open url failed. See below:\n%s") % e) self.statusbar.showMessage(self.tr("open url failed")) def loadCsvFile(self, fname): """load csv file (old format)""" _data = [] with open(fname, 'r') as fp: content = csv.reader(fp) for row in content: if len(row) and row[0][0] != "#": _data.append(row) self.loadData(_data) def showFileDialogSlot(self): """打开/保存数据至文件""" if self.sender().objectName() == "open": fname = QFileDialog.getOpenFileName(self, self.tr("Open file"), os.getcwd()) fname = fname[0] if isinstance(fname, tuple) else fname # qt5 tuple, qt4 str if fname: try: with open(fname, 'r') as fp: self.loadData(json.load(fp)) except AttributeError as e: QMessageBox.warning(self, self.tr("Error"), self.tr("Open file failed. See below:\n%s") % e) except: # json.decoder.JSONDecodeError Python 3 try: # load csv file (old format) self.loadCsvFile(fname) except Exception as e: QMessageBox.warning(self, self.tr("Error"), self.tr("The file does not contain JSON or CSV. See below:\n%s") % e) self.updateTableSlot(0) # 更新列表控件 self.statusbar.showMessage(self.tr("open file successfully")) elif self.sender().objectName() in ["save", "save_as"]: fname = QFileDialog.getSaveFileName(self, self.tr("Save file"), os.getcwd()) fname = fname[0] if isinstance(fname, tuple) else fname # qt5 tuple, qt4 str if fname: try: with open(fname, 'w') as fp: json.dump([i.dump(mode="raw") for i in self.tableContents], fp, ensure_ascii=False) self.statusbar.showMessage(self.tr("saved successfully")) except AttributeError as e: QMessageBox.warning(self, self.tr("Error"), self.tr("Save file failed. See below:\n%s") % e) def setBackgroundColor(self, color): """修改背景色""" for i in range(self.tableWidget.rowCount()): if i % 2 != 0: for j in range(self.tableWidget.columnCount()): item = self.tableWidget.item(i, j) if item: item.setBackground(color) def setStatusColor(self, rowIndex): """修改状态文字颜色""" item = self.tableWidget.item(rowIndex, 6) if item.text() == "normal": item.setForeground(Qt.darkGreen) elif item.text() == "update": item.setForeground(Qt.darkRed) elif item.text() == "error": item.setForeground(Qt.darkYellow) elif item.text() == "none": item.setForeground(Qt.gray) def setupTable(self): """初始化列表""" self.tableWidget.setFocusPolicy(Qt.NoFocus) # 无焦点 self.tableWidget.setGridStyle(Qt.DashDotLine) # 线类型 self.tableWidget.setWordWrap(True) self.tableWidget.setCornerButtonEnabled(True) self.tableWidget.horizontalHeader().setVisible(True) # 显示表头 #self.tableWidget.horizontalHeader().setSortIndicatorShown(True) # 排序指示器 self.tableWidget.horizontalHeader().setStretchLastSection(True) # 扩展最后一列 self.tableWidget.setColumnCount(self.tableColumnCount) # 列数 self.tableWidget.setRowCount(self.tableRowCount) # 行数 # 行头 for i in range(self.tableRowCount): item = QTableWidgetItem("%s" % (i+1)) self.tableWidget.setVerticalHeaderItem(i, item) # 行号 # 列头 for i in range(self.tableColumnCount): item = QTableWidgetItem(self.tableHeaders[i]) # QIcon, str self.tableWidget.setHorizontalHeaderItem(i, item) # 初始化表头 for i in [3, 4, 5]: self.tableWidget.resizeColumnToContents(i) # 根据内容调整列宽 # 初始化项目 for i in range(self.tableRowCount): self.tableContents.append(Checker()) for j in range(self.tableColumnCount): item = QTableWidgetItem() self.tableWidget.setItem(i, j, item) self.setBackgroundColor(self.bgColor)
class Player(QWidget): fullScreenChanged = pyqtSignal(bool) def __init__(self, playlist, parent=None): super(Player, self).__init__(parent) self.setStyleSheet(stylesheet(self)) self.colorDialog = None self.trackInfo = "" self.statusInfo = "" self.duration = 0 self.url = "" self. settings = QSettings("QAudioPlayer", "QAudioPlayer") self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.player.setPlaylist(self.playlist) self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) self.player.metaDataChanged.connect(self.metaDataChanged) self.playlist.currentIndexChanged.connect(self.playlistPositionChanged) self.player.mediaStatusChanged.connect(self.statusChanged) self.player.bufferStatusChanged.connect(self.bufferingProgress) self.player.error.connect(self.displayErrorMessage) self.playlistModel = PlaylistModel() self.playlistModel.setPlaylist(self.playlist) self.playlistView = QListView() # self.playlistView.setSpacing(1) self.playlistView.setStyleSheet(stylesheet(self)) self.playlistView.setModel(self.playlistModel) self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) self.playlistView.activated.connect(self.jump) self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, self.player.duration() / 1000) self.slider.setStyleSheet(stylesheet(self)) self.labelDuration = QLabel() self.slider.sliderMoved.connect(self.seek) openButton = QPushButton("Open", clicked=self.open) openButton.setIcon(openButton.style().standardIcon(QStyle.SP_DialogOpenButton)) clearButton = QPushButton("", clicked=self.clearList) clearButton.setFixedWidth(36) clearButton.setIcon(QIcon.fromTheme("edit-delete")) clearButton.setToolTip("clear List") controls = PlayerControls() controls.setState(self.player.state()) controls.setVolume(self.player.volume()) controls.setMuted(controls.isMuted()) controls.play.connect(self.player.play) controls.pause.connect(self.player.pause) controls.stop.connect(self.player.stop) controls.next.connect(self.playlist.next) controls.previous.connect(self.previousClicked) controls.changeVolume.connect(self.player.setVolume) controls.changeMuting.connect(self.player.setMuted) controls.changeRate.connect(self.player.setPlaybackRate) self.player.stateChanged.connect(controls.setState) self.player.volumeChanged.connect(controls.setVolume) self.player.mutedChanged.connect(controls.setMuted) displayLayout = QHBoxLayout() displayLayout.addWidget(self.playlistView) controlLayout = QHBoxLayout() controlLayout.setContentsMargins(0, 0, 0, 0) controlLayout.addWidget(openButton) controlLayout.addWidget(clearButton) # controlLayout.addStretch(1) controlLayout.addWidget(controls) # controlLayout.addStretch(1) layout = QVBoxLayout() layout.addLayout(displayLayout) hLayout = QHBoxLayout() hLayout.addWidget(self.slider) hLayout.addWidget(self.labelDuration) layout.addLayout(hLayout) layout.addLayout(controlLayout) self.statusBar = QStatusBar() vlayout = QVBoxLayout() vlayout.addWidget(self.statusBar) layout.addLayout(vlayout) self.statusBar.showMessage("Welcome") self.setWindowTitle("QAudioPlayer") self.setMinimumSize(300, 200) # self.setBackgroundRole(QPalette.Window) self.setContentsMargins(0,0,0,0) self.setLayout(layout) self.readSettings() if not self.player.isAvailable(): QMessageBox.warning(self, "Service not available", "The QMediaPlayer object does not have a valid service.\n" "Please check the media service plugins are installed.") controls.setEnabled(False) self.playlistView.setEnabled(False) openButton.setEnabled(False) self.colorButton.setEnabled(False) self.fullScreenButton.setEnabled(False) self.metaDataChanged() self.addToPlaylist(playlist) def readSettings(self): if self.settings.contains("url"): self.url = self.settings.value("url") self.addToPlaylist(self.url) def writeSettings(self): self.settings.setValue("url", self.url) def closeEvent(self, event): print("writing settings") self.writeSettings() print("goodbye ...") event.accept() def open(self): fileNames, _ = QFileDialog.getOpenFileNames(self, "Open Files", "/home", "Audio Files *.mp3 *.m4a *.ogg *.wav *.m3u") if fileNames: self.url = fileNames self.addToPlaylist(fileNames) print("added Files to playlist") def openOnStart(self, name): fileInfo = QFileInfo(name) if fileInfo.exists(): url = QUrl.fromLocalFile(fileInfo.absoluteFilePath()) if fileInfo.suffix().lower() == 'm3u': self.playlist.load(url) else: self.playlist.addMedia(QMediaContent(url)) else: url = QUrl(name) if url.isValid(): self.playlist.addMedia(QMediaContent(url)) print("added Files to playlist") def clearList(self): self.playlist.clear() def addToPlaylist(self, fileNames): for name in fileNames: fileInfo = QFileInfo(name) if fileInfo.exists(): url = QUrl.fromLocalFile(fileInfo.absoluteFilePath()) if fileInfo.suffix().lower() == 'm3u': self.playlist.load(url) else: self.playlist.addMedia(QMediaContent(url)) else: url = QUrl(name) if url.isValid(): self.playlist.addMedia(QMediaContent(url)) def durationChanged(self, duration): duration /= 1000 self.duration = duration self.slider.setMaximum(duration) def positionChanged(self, progress): progress /= 1000 if not self.slider.isSliderDown(): self.slider.setValue(progress) self.updateDurationInfo(progress) def metaDataChanged(self): if self.player.isMetaDataAvailable(): self.setTrackInfo("%s - %s" % ( self.player.metaData(QMediaMetaData.AlbumArtist), self.player.metaData(QMediaMetaData.Title))) def previousClicked(self): # Go to the previous track if we are within the first 5 seconds of # playback. Otherwise, seek to the beginning. if self.player.position() <= 5000: self.playlist.previous() else: self.player.setPosition(0) def jump(self, index): if index.isValid(): self.playlist.setCurrentIndex(index.row()) self.player.play() def playlistPositionChanged(self, position): self.playlistView.setCurrentIndex( self.playlistModel.index(position, 0)) def seek(self, seconds): self.player.setPosition(seconds * 1000) def statusChanged(self, status): self.handleCursor(status) if status == QMediaPlayer.LoadingMedia: self.setStatusInfo("Loading...") elif status == QMediaPlayer.StalledMedia: self.setStatusInfo("Media Stalled") elif status == QMediaPlayer.EndOfMedia: QApplication.alert(self) elif status == QMediaPlayer.InvalidMedia: self.displayErrorMessage() else: self.setStatusInfo("") def handleCursor(self, status): if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia): self.setCursor(Qt.BusyCursor) else: self.unsetCursor() def bufferingProgress(self, progress): self.setStatusInfo("Buffering %d%" % progress) def setTrackInfo(self, info): self.trackInfo = info if self.statusInfo != "": self.statusBar.showMessage("%s | %s" % (self.trackInfo, self.statusInfo)) else: self.statusBar.showMessage(self.trackInfo) def setStatusInfo(self, info): self.statusInfo = info if self.statusInfo != "": self.statusBar.showMessage("%s | %s" % (self.trackInfo, self.statusInfo)) else: self.statusBar.showMessage(self.trackInfo) def displayErrorMessage(self): self.setStatusInfo(self.player.errorString()) def updateDurationInfo(self, currentInfo): duration = self.duration if currentInfo or duration: currentTime = QTime((currentInfo/3600)%60, (currentInfo/60)%60, currentInfo%60, (currentInfo*1000)%1000) totalTime = QTime((duration/3600)%60, (duration/60)%60, duration%60, (duration*1000)%1000); format = 'hh:mm:ss' if duration > 3600 else 'mm:ss' tStr = currentTime.toString(format) + " / " + totalTime.toString(format) else: tStr = "" self.labelDuration.setText(tStr)
class Window(QMainWindow): """ Represents the application's main window that will contain the UI widgets. All interactions with the UI go through the object created by this class. """ icon = 'icon.png' def __init__(self): """ Create the default start state. The window contains a root widget into which is placed: * A status bar widget at the top, containing curent user / status information. * A main-view widget, itself containing a list view for sources and a place for details / message contents / forms. """ super().__init__() self.setWindowTitle(_("SecureDrop Client {}").format(__version__)) self.setWindowIcon(load_icon(self.icon)) self.widget = QWidget() widget_layout = QVBoxLayout() self.widget.setLayout(widget_layout) self.tool_bar = ToolBar(self.widget) self.main_view = MainView(self.widget) self.main_view.source_list.itemSelectionChanged.\ connect(self.on_source_changed) widget_layout.addWidget(self.tool_bar, 1) widget_layout.addWidget(self.main_view, 6) self.setCentralWidget(self.widget) self.current_source = None # Tracks which source is shown self.show() self.autosize_window() def setup(self, controller): """ Create references to the controller logic and instantiate the various views used in the UI. """ self.controller = controller # Reference the Client logic instance. self.tool_bar.setup(self, controller) self.status_bar = QStatusBar(self) self.setStatusBar(self.status_bar) self.set_status('Started SecureDrop Client. Please sign in.', 20000) self.login_dialog = LoginDialog(self) self.main_view.setup(self.controller) def autosize_window(self): """ Ensure the application window takes up 100% of the available screen (i.e. the whole of the virtualised desktop in Qubes dom) """ screen = QDesktopWidget().screenGeometry() self.resize(screen.width(), screen.height()) def show_login(self): """ Show the login form. """ self.login_dialog = LoginDialog(self) self.login_dialog.setup(self.controller) self.login_dialog.reset() self.login_dialog.exec() def show_login_error(self, error): """ Display an error in the login dialog. """ if self.login_dialog and error: self.login_dialog.error(error) def hide_login(self): """ Kill the login dialog. """ self.login_dialog.accept() self.login_dialog = None def update_error_status(self, error=None): """ Show an error message on the sidebar. """ self.main_view.update_error_status(error) def show_sources(self, sources): """ Update the left hand sources list in the UI with the passed in list of sources. """ self.main_view.source_list.update(sources) def show_sync(self, updated_on): """ Display a message indicating the data-sync state. """ if updated_on: self.main_view.status.setText('Last Sync: ' + updated_on.humanize()) else: self.main_view.status.setText(_('Waiting to Synchronize')) def set_logged_in_as(self, username): """ Update the UI to show user logged in with username. """ self.tool_bar.set_logged_in_as(username) def logout(self): """ Update the UI to show the user is logged out. """ self.tool_bar.set_logged_out() def on_source_changed(self): """ React to when the selected source has changed. """ source_item = self.main_view.source_list.currentItem() source_widget = self.main_view.source_list.itemWidget(source_item) if source_widget: self.current_source = source_widget.source self.show_conversation_for(self.current_source) def show_conversation_for(self, source): """ Show conversation of messages and replies between a source and journalists. """ conversation = ConversationView(self) conversation.setup(self.controller) conversation.add_message('Source name: {}'.format( source.journalist_designation)) # Display each conversation item in the source collection. for conversation_item in source.collection: if conversation_item.filename.endswith('msg.gpg'): # TODO: Decrypt and display the message pass elif conversation_item.filename.endswith('reply.gpg'): # TODO: Decrypt and display the reply pass else: conversation.add_file(source, conversation_item) conversation.add_message('Hello, hello, is this thing switched on?') conversation.add_reply('Yes, I can hear you loud and clear!') conversation.add_reply('How can I help?') conversation.add_message('I have top secret documents relating to ' 'a massive technical scandal at the heart ' ' of the Freedom of the Press Foundation. ' 'In a shocking turn of events, it appears ' 'they give away all their software for FREE.') conversation.add_message("Hello: I’m a nurse at one of the trauma " "centers in town. We've had many patients in " "the last several months, all with " "similar/mysterious respiratory issues. My " "staff has noticed that most live down-wind " "from the Dole fields West of 696. Some of " "the patients say they have complained to " "local authorities about sewage smells. One " "said she's spotted a truck spraying a " "sludge of some kind, on the fields at " "night. I'm attaching a video from the " "patient who taped the trucks, and a PDF of " "redacted police reports that other patients " "shared. I don’t know if there's much you " "can do, but if there is I would be happy " "to help.") conversation.add_message("I work at the City Water Department, and a " "man named Reggie Esters is one of our board " "directors. I believe Reggie is related to " "Rep Monica Conyers. He's literally never " "here, and the resume on file for him makes " "no sense. I have a hunch he is not in his " "job legitimately, and think you should look " "into this. Also: someone I work with heard " "him on the phone once, talking about his " "'time' at Jackson—that contradicts his " "resume. It really seems fishy.") conversation.add_reply("THIS IS IT THIS IS THE TAPE EVERYONE'S " "LOOKING FOR!!!") conversation.add_reply("Hello: I read your story on Sally Dale, and " "her lawsuit against the St. Joseph's " "Orphanage. My great-aunt was one of the nuns " "there. She is willing to be interviewed, but " "does not want her name, location, or any " "identity details released. She feels " "horrible. She wants the children who survived " "to find peace. Thanks.") self.main_view.update_view(conversation) def set_status(self, message, duration=5000): """ Display a status message to the user. Optionally, supply a duration (in milliseconds), the default value being a duration of 5 seconds. """ self.status_bar.showMessage(message, duration)
class MainApp(QWidget): def __init__(self, parent=None): logging.debug("MainApp:init() instantiated") super().__init__() self.baseWidgets = {} self.vmWidgets = {} self.materialWidgets = {} self.cf = SystemConfigIO() self.ec = ExperimentConfigIO.getInstance() self.statusBar = QStatusBar() self.setMinimumSize(670, 565) quit = QAction("Quit", self) quit.triggered.connect(self.closeEvent) self.setWindowTitle("ARL South RES v0.1") self.tabWidget = QtWidgets.QTabWidget() self.tabWidget.setGeometry(QtCore.QRect(0, 15, 668, 565)) self.tabWidget.setObjectName("tabWidget") # Configuration Window (windowBox) contains: ## windowBoxHLayout contains: ###experimentTree (Left) ###basedataStackedWidget (Right) self.windowWidget = QtWidgets.QWidget() self.windowWidget.setObjectName("windowWidget") self.windowBoxHLayout = QtWidgets.QHBoxLayout() #self.windowBoxHLayout.setContentsMargins(0, 0, 0, 0) self.windowBoxHLayout.setObjectName("windowBoxHLayout") self.windowWidget.setLayout(self.windowBoxHLayout) self.experimentTree = QtWidgets.QTreeWidget() self.experimentTree.itemSelectionChanged.connect(self.onItemSelected) self.experimentTree.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.experimentTree.customContextMenuRequested.connect( self.showContextMenu) self.experimentTree.setEnabled(True) self.experimentTree.setMinimumSize(200, 521) self.experimentTree.setMaximumWidth(350) self.experimentTree.setObjectName("experimentTree") self.experimentTree.headerItem().setText(0, "Experiments") self.experimentTree.setSortingEnabled(False) self.windowBoxHLayout.addWidget(self.experimentTree) self.basedataStackedWidget = QStackedWidget() self.basedataStackedWidget.setObjectName("basedataStackedWidget") self.basedataStackedWidget.setEnabled(False) self.windowBoxHLayout.addWidget(self.basedataStackedWidget) self.tabWidget.addTab(self.windowWidget, "Configuration") # VBox Actions Tab self.experimentActionsWidget = ExperimentActionsWidget( statusBar=self.statusBar) self.experimentActionsWidget.setObjectName("experimentActionsWidget") self.tabWidget.addTab(self.experimentActionsWidget, "Experiment Actions") # Remote Connections Tab self.connectionWidget = ConnectionWidget(statusBar=self.statusBar) self.connectionWidget.setObjectName("connectionsWidget") self.tabWidget.addTab(self.connectionWidget, "Remote Connections") #Create the bottom layout so that we can access the status bar self.bottomLayout = QHBoxLayout() self.statusBar.showMessage("Loading GUI...") self.bottomLayout.addWidget(self.statusBar) self.saveButton = QtWidgets.QPushButton("Save Current") self.saveButton.clicked.connect(self.saveExperimentButton) self.saveButton.setEnabled(False) self.bottomLayout.addWidget(self.saveButton) self.populateUi() self.setupContextMenus() self.initMenu() self.mainLayout = QVBoxLayout() self.mainLayout.addWidget(self.mainMenu) self.mainLayout.addWidget(self.tabWidget) self.mainLayout.addLayout(self.bottomLayout) self.setLayout(self.mainLayout) #self.setCentralWidget(self.outerBox) self.tabWidget.setCurrentIndex(0) #self.statusBar.showMessage("Finished Loading GUI Components") # Plugin Section self.tabWidget.addTab(CTFi2GUI(), "CTFi2") def readSystemConfig(self): logging.debug("MainApp:readSystemConfig() instantiated") self.vboxPath = self.cf.getConfig()['VBOX']['VMANAGE_PATH'] self.experimentPath = self.cf.getConfig( )['EXPERIMENTS']['EXPERIMENTS_PATH'] self.statusBar.showMessage("Finished reading system config") def setupContextMenus(self): logging.debug("MainApp:setupContextMenus() instantiated") # Context menu for blank space self.blankTreeContextMenu = QtWidgets.QMenu() self.addExperiment = self.blankTreeContextMenu.addAction( "New Experiment") self.addExperiment.triggered.connect(self.addExperimentActionEvent) self.importExperiment = self.blankTreeContextMenu.addAction( "Import Experiment from RES archive") self.importExperiment.triggered.connect(self.importActionEvent) # Experiment context menu self.experimentContextMenu = QtWidgets.QMenu() self.addVMContextSubMenu = QtWidgets.QMenu() self.experimentContextMenu.addMenu(self.addVMContextSubMenu) self.addVMContextSubMenu.setTitle("Add") self.addVM = self.addVMContextSubMenu.addAction("Virtual Machines") self.addVM.triggered.connect(self.addVMActionEvent) self.addMaterial = self.addVMContextSubMenu.addAction("Material Files") self.addMaterial.triggered.connect(self.addMaterialActionEvent) # Add line separator here self.removeExperiment = self.experimentContextMenu.addAction( "Remove Experiment") self.removeExperiment.triggered.connect( self.removeExperimentItemActionEvent) self.exportExperiment = self.experimentContextMenu.addAction( "Export Experiment") self.exportExperiment.triggered.connect(self.exportActionEvent) # VM/Material context menu self.itemContextMenu = QtWidgets.QMenu() self.removeItem = self.itemContextMenu.addAction( "Remove Experiment Item") self.removeItem.triggered.connect(self.removeExperimentItemActionEvent) def populateUi(self): logging.debug("MainApp:populateUi() instantiated") self.statusBar.showMessage("Populating UI") self.readSystemConfig() #####Create the following based on the config file result = self.ec.getExperimentXMLFilenames() if result == None: return [xmlExperimentFilenames, xmlExperimentNames] = result if xmlExperimentFilenames == [] or xmlExperimentNames == []: self.statusBar.showMessage("No configs found") return #For all experiment files found for configname in xmlExperimentNames: ####Read Experiment Config Data and Populate Tree self.loadConfigname(configname) self.statusBar.showMessage( "Completed populating the User Interface from " + str(len(xmlExperimentNames)) + " config files read", 6000) ############################### def loadConfigname(self, configname): logging.debug("MainApp(): loadConfigname instantiated") logging.info("Reading XML data for " + str(configname)) jsondata = self.ec.getExperimentXMLFileData(configname) self.statusBar.showMessage("Finished reading experiment config") ##########testbed-setup data###### if jsondata == None: jsondata = {} if "xml" not in jsondata or jsondata["xml"] == None or str( jsondata["xml"]).strip() == "": jsondata["xml"] = {} if "testbed-setup" not in jsondata["xml"]: jsondata["xml"]["testbed-setup"] = {} if "vm-set" not in jsondata["xml"]["testbed-setup"]: jsondata["xml"]["testbed-setup"]["vm-set"] = {} #Temporary fix for older xml/json files. if "users-filename" not in jsondata["xml"]["testbed-setup"]["vm-set"]: jsondata["xml"]["testbed-setup"]["vm-set"]["users-filename"] = "" if "rdp-broker-ip" not in jsondata["xml"]["testbed-setup"]["vm-set"]: jsondata["xml"]["testbed-setup"]["vm-set"]["rdp-broker-ip"] = "" if "chat-server-ip" not in jsondata["xml"]["testbed-setup"]["vm-set"]: jsondata["xml"]["testbed-setup"]["vm-set"]["chat-server-ip"] = "" configTreeWidgetItem = QtWidgets.QTreeWidgetItem(self.experimentTree) configTreeWidgetItem.setText(0, configname) self.experimentActionsWidget.addExperimentItem( configname, config_jsondata=jsondata) self.connectionWidget.addExperimentItem(configname, config_jsondata=jsondata) basejsondata = jsondata["xml"] # Base Config Widget self.baseWidget = BaseWidget(self, configname, configname, basejsondata) self.baseWidgets[configname] = { "BaseWidget": {}, "VMWidgets": {}, "MaterialWidgets": {} } self.baseWidgets[configname]["BaseWidget"] = self.baseWidget self.basedataStackedWidget.addWidget(self.baseWidget) ##########vm data###### if "vm" in jsondata["xml"]["testbed-setup"]["vm-set"]: vmsjsondata = jsondata["xml"]["testbed-setup"]["vm-set"]["vm"] if isinstance(vmsjsondata, list): for vm in vmsjsondata: vm_item = QtWidgets.QTreeWidgetItem(configTreeWidgetItem) vmlabel = "V: " + vm["name"] vm_item.setText(0, vmlabel) # VM Config Widget vmWidget = VMWidget(None, configname, vm["name"], vm) self.baseWidgets[configname]["VMWidgets"][ vmlabel] = vmWidget self.basedataStackedWidget.addWidget(vmWidget) else: vm_item = QtWidgets.QTreeWidgetItem(configTreeWidgetItem) vmlabel = "V: " + vmsjsondata["name"] vm_item.setText(0, vmlabel) # VM Config Widget vmWidget = VMWidget(None, configname, vmsjsondata["name"], vmsjsondata) self.baseWidgets[configname]["VMWidgets"][vmlabel] = vmWidget self.basedataStackedWidget.addWidget(vmWidget) ##########material data###### if "material" in jsondata["xml"]["testbed-setup"]["vm-set"]: materialsjsondata = jsondata["xml"]["testbed-setup"]["vm-set"][ "material"] if isinstance(materialsjsondata, list): for material in materialsjsondata: material_item = QtWidgets.QTreeWidgetItem( configTreeWidgetItem) materiallabel = "M: " + material["name"] material_item.setText(0, materiallabel) # Material Config Widget materialWidget = MaterialWidget(None, configname, material["name"], material) self.baseWidgets[configname]["MaterialWidgets"][ materiallabel] = materialWidget self.basedataStackedWidget.addWidget(materialWidget) else: material_item = QtWidgets.QTreeWidgetItem(configTreeWidgetItem) materiallabel = "M: " + materialsjsondata["name"] material_item.setText(0, materiallabel) # Material Config Widget materialWidget = MaterialWidget(None, configname, materialsjsondata["name"], materialsjsondata) self.baseWidgets[configname]["MaterialWidgets"][ materiallabel] = materialWidget self.basedataStackedWidget.addWidget(materialWidget) logging.debug("MainApp(): Finished loading configname: " + str(configname)) def onItemSelected(self): logging.debug("MainApp:onItemSelected instantiated") # Get the selected item selectedItem = self.experimentTree.currentItem() if selectedItem == None: logging.debug("MainApp:onItemSelected no configurations left") self.statusBar.showMessage( "No configuration items selected or available.") return self.basedataStackedWidget.setEnabled(True) # Now enable the save button self.saveButton.setEnabled(True) self.saveExperimentMenuButton.setEnabled(True) #Check if it's the case that an experiment name was selected parentSelectedItem = selectedItem.parent() if (parentSelectedItem == None): #A base widget was selected self.basedataStackedWidget.setCurrentWidget( self.baseWidgets[selectedItem.text(0)]["BaseWidget"]) else: #Check if it's the case that a VM Name was selected if (selectedItem.text(0)[0] == "V"): logging.debug("Setting right widget: " + str(self.baseWidgets[parentSelectedItem.text(0)] ["VMWidgets"][selectedItem.text(0)])) self.basedataStackedWidget.setCurrentWidget( self.baseWidgets[parentSelectedItem.text(0)]["VMWidgets"][ selectedItem.text(0)]) #Check if it's the case that a Material Name was selected elif (selectedItem.text(0)[0] == "M"): logging.debug("Setting right widget: " + str(self.baseWidgets[parentSelectedItem.text(0)] ["MaterialWidgets"][selectedItem.text(0)])) self.basedataStackedWidget.setCurrentWidget( self.baseWidgets[parentSelectedItem.text( 0)]["MaterialWidgets"][selectedItem.text(0)]) def showContextMenu(self, position): logging.debug("MainApp:showContextMenu() instantiated: " + str(position)) if (self.experimentTree.itemAt(position) == None): self.blankTreeContextMenu.popup( self.experimentTree.mapToGlobal(position)) elif (self.experimentTree.itemAt(position).parent() == None): self.experimentContextMenu.popup( self.experimentTree.mapToGlobal(position)) else: self.itemContextMenu.popup( self.experimentTree.mapToGlobal(position)) def addExperimentActionEvent(self): logging.debug("MainApp:addExperimentActionEvent() instantiated") configname = ExperimentAddDialog().experimentAddDialog( self, self.baseWidgets.keys()) if configname != None: logging.debug( "configureVM(): OK pressed and valid configname entered: " + str(configname)) else: logging.debug("configureVM(): Cancel pressed or no VM selected") return ##Now add the item to the tree widget and create the baseWidget configTreeWidgetItem = QtWidgets.QTreeWidgetItem(self.experimentTree) configTreeWidgetItem.setText(0, configname) self.experimentActionsWidget.addExperimentItem(configname) self.connectionWidget.addExperimentItem(configname) # Base Config Widget self.baseWidget = BaseWidget(self, configname, configname) self.baseWidgets[configname] = { "BaseWidget": {}, "VMWidgets": {}, "MaterialWidgets": {} } self.baseWidgets[configname]["BaseWidget"] = self.baseWidget self.basedataStackedWidget.addWidget(self.baseWidget) self.statusBar.showMessage("Added new experiment: " + str(configname)) def importActionEvent(self): logging.debug("MainApp:importActionEvent() instantiated") #Check if it's the case that an experiment name was selected confignamesChosen = PackageImportDialog().packageImportDialog( self, self.baseWidgets.keys()) if confignamesChosen == []: logging.debug( "importActionEvent(): Canceled or a file could not be imported. make sure file exists." ) return #for fileChosen in filesChosen: logging.debug( "MainApp: importActionEvent(): Files choosen (getting only first): " + confignamesChosen) firstConfignameChosen = confignamesChosen self.loadConfigname(firstConfignameChosen) #Add the items to the tree self.statusBar.showMessage("Imported " + firstConfignameChosen) def addVMActionEvent(self): logging.debug("MainApp:addVMActionEvent() instantiated") selectedItem = self.experimentTree.currentItem() if selectedItem == None: logging.debug("MainApp:addVMActionEvent no configurations left") self.statusBar.showMessage( "Could not add VM. No configuration items selected or available." ) return selectedItemName = selectedItem.text(0) #Now allow the user to choose the VM: (response, vmsChosen) = VMRetrieveDialog(self).exec_() if response == QMessageBox.Ok and vmsChosen != None: logging.debug("configureVM(): OK pressed and VMs selected " + str(vmsChosen)) else: logging.debug("configureVM(): Cancel pressed or no VM selected") return if vmsChosen == []: logging.debug( "configureVM(): Canceled or a file could not be added. Try again later or check permissions" ) return for vmChosen in vmsChosen: logging.debug("MainApp: addVMActionEvent(): File choosen: " + str(vmChosen)) #Add the item to the tree vmItem = QtWidgets.QTreeWidgetItem(selectedItem) vmlabel = "V: " + vmChosen vmItem.setText(0, vmlabel) # VM Config Widget #Now add the item to the stack and list of baseWidgets vmjsondata = {"name": vmChosen} vmWidget = VMWidget(self, selectedItemName, vmChosen, vmjsondata) self.baseWidgets[selectedItemName]["VMWidgets"][vmlabel] = vmWidget self.basedataStackedWidget.addWidget(vmWidget) #Now add data to the experimentActionWidget associated with the current config #Check if it's the case that an experiment name was selected parentSelectedItem = selectedItem.parent() if parentSelectedItem != None: selectedItem = parentSelectedItem configname = selectedItem.text(0) config_jsondata = self.getWritableData(configname) self.experimentActionsWidget.resetExperiment( configname, config_jsondata=config_jsondata) self.connectionWidget.resetExperiment(configname, config_jsondata=config_jsondata) self.statusBar.showMessage("Added " + str(len(vmsChosen)) + " VM files to experiment: " + str(selectedItemName)) def startHypervisorActionEvent(self): logging.debug("MainApp:startHypervisorActionEvent() instantiated") logging.debug( "MainApp:startHypervisorActionEvent no configurations left") # Try to open the hypervisor and check if it worked or not result = HypervisorOpenDialog().hypervisorOpenDialog(self) if result != "success": logging.debug( "startHypervisorActionEvent(): Could not start the hypervisor") self.statusBar.showMessage("Hypervisor could not be started.") return self.statusBar.showMessage("Started hypervisor.") def addMaterialActionEvent(self): logging.debug("MainApp:addMaterialActionEvent() instantiated") selectedItem = self.experimentTree.currentItem() if selectedItem == None: logging.debug( "MainApp:addMaterialActionEvent no configurations left") self.statusBar.showMessage( "Could not add item. No configuration items selected or available." ) return selectedItemName = selectedItem.text(0) #Check if it's the case that an experiment name was selected filesChosen = MaterialAddFileDialog().materialAddFileDialog( selectedItemName) if filesChosen == []: logging.debug( "addMaterialActionEvent(): Canceled or a file could not be added. Try again later or check permissions" ) return for fileChosen in filesChosen: fileChosen = os.path.basename(fileChosen) logging.debug("MainApp: addMaterialActionEvent(): File choosen: " + fileChosen) #Add the item to the tree material_item = QtWidgets.QTreeWidgetItem(selectedItem) materiallabel = "M: " + fileChosen material_item.setText(0, materiallabel) # Material Config Widget #Now add the item to the stack and list of baseWidgets materialsjsondata = {"name": fileChosen} materialWidget = MaterialWidget(self, selectedItemName, fileChosen, materialsjsondata) self.baseWidgets[selectedItem.text( 0)]["MaterialWidgets"][materiallabel] = materialWidget self.basedataStackedWidget.addWidget(materialWidget) self.statusBar.showMessage("Added " + str(len(filesChosen)) + " material files to experiment: " + str(selectedItemName)) def removeExperimentItemActionEvent(self): logging.debug("MainApp:removeExperimentItemActionEvent() instantiated") selectedItem = self.experimentTree.currentItem() if selectedItem == None: logging.debug("MainApp:onItemSelected no configurations left") self.statusBar.showMessage( "Could not remove. No configuration items selected or available." ) return selectedItemName = selectedItem.text(0) #Check if it's the case that an experiment name was selected parentSelectedItem = selectedItem.parent() if (parentSelectedItem == None): #A base widget was selected successfilenames = ExperimentRemoveFileDialog( ).experimentRemoveFileDialog(selectedItemName) if successfilenames == [] or successfilenames == "": logging.debug( "removeExperimentItemActionEvent(): Canceled or a file could not be removed. Try again later or check permissions" ) return self.experimentTree.invisibleRootItem().removeChild(selectedItem) self.basedataStackedWidget.removeWidget( self.baseWidgets[selectedItemName]["BaseWidget"]) del self.baseWidgets[selectedItemName] self.experimentActionsWidget.removeExperimentItem(selectedItemName) self.experimentActionsWidget.removeExperimentItem(selectedItemName) self.statusBar.showMessage("Removed experiment: " + str(selectedItemName)) else: #Check if it's the case that a VM Name was selected if (selectedItem.text(0)[0] == "V"): parentSelectedItem.removeChild(selectedItem) configname = parentSelectedItem.text(0) self.basedataStackedWidget.removeWidget( self.baseWidgets[configname]["VMWidgets"][ selectedItem.text(0)]) del self.baseWidgets[configname]["VMWidgets"][ selectedItem.text(0)] self.statusBar.showMessage("Removed VM: " + str(selectedItemName) + " from experiment: " + str(parentSelectedItem.text(0))) #Also remove from the experiment action widget: config_jsondata = self.getWritableData(configname) self.experimentActionsWidget.resetExperiment( configname, config_jsondata=config_jsondata) self.connectionWidget.resetExperiment( configname, config_jsondata=config_jsondata) #Check if it's the case that a Material Name was selected elif (selectedItem.text(0)[0] == "M"): materialName = selectedItemName.split("M: ")[1] successfilenames = MaterialRemoveFileDialog( ).materialRemoveFileDialog(parentSelectedItem.text(0), materialName) if successfilenames == []: logging.debug( "Canceled or a file could not be removed. Try again later or check permissions" ) return parentSelectedItem.removeChild(selectedItem) self.basedataStackedWidget.removeWidget( self.baseWidgets[parentSelectedItem.text( 0)]["MaterialWidgets"][selectedItem.text(0)]) del self.baseWidgets[parentSelectedItem.text( 0)]["MaterialWidgets"][selectedItem.text(0)] self.statusBar.showMessage("Removed Material: " + str(materialName) + " from experiment: " + str(parentSelectedItem.text(0))) def exportActionEvent(self): logging.debug("MainApp:exportActionEvent() instantiated") #Check if it's the case that an experiment name was selected selectedItem = self.experimentTree.currentItem() if selectedItem == None: logging.debug("MainApp:exportActionEvent no configurations left") self.statusBar.showMessage( "Could not export experiment. No configuration items selected or available." ) return selectedItemName = selectedItem.text(0) folderChosen = PackageExportDialog().packageExportDialog( self, selectedItemName) if folderChosen == []: logging.debug( "exportActionEvent(): Canceled or the experiment could not be exported. Check folder permissions." ) return folderChosen = os.path.basename(folderChosen[0]) logging.debug("MainApp: exportActionEvent(): File choosen: " + folderChosen) #Add the items to the tree self.statusBar.showMessage("Exported to " + folderChosen) def editPathActionEvent(self): logging.debug("MainApp:editPathActionEvent() instantiated") result = ConfigurationDialog(self).exec_() def closeEvent(self, event): logging.debug("MainApp:closeEvent(): instantiated") logging.debug("closeEvent(): returning accept") event.accept() qApp.quit() return def initMenu(self): self.mainMenu = QMenuBar() self.fileMenu = self.mainMenu.addMenu("File") self.editMenu = self.mainMenu.addMenu("Edit") self.hypervisorMenu = self.mainMenu.addMenu("Hypervisor") self.newExperimentMenuButton = QAction(QIcon(), "New Experiment", self) self.newExperimentMenuButton.setShortcut("Ctrl+N") self.newExperimentMenuButton.setStatusTip("Create New Experiment") self.newExperimentMenuButton.triggered.connect( self.addExperimentActionEvent) self.fileMenu.addAction(self.newExperimentMenuButton) self.importExperimentMenuButton = QAction(QIcon(), "Import Experiment", self) self.importExperimentMenuButton.setShortcut("Ctrl+I") self.importExperimentMenuButton.setStatusTip( "Import Experiment from RES File") self.importExperimentMenuButton.triggered.connect( self.importActionEvent) self.fileMenu.addAction(self.importExperimentMenuButton) self.saveExperimentMenuButton = QAction(QIcon(), "Save Experiment", self) self.saveExperimentMenuButton.setShortcut("Ctrl+I") self.saveExperimentMenuButton.setStatusTip( "Save currently selected experiment") self.saveExperimentMenuButton.triggered.connect( self.saveExperimentButton) self.saveExperimentMenuButton.setEnabled(False) self.fileMenu.addAction(self.saveExperimentMenuButton) self.exitMenuButton = QAction(QIcon("exit24.png"), "Exit", self) self.exitMenuButton.setShortcut("Ctrl+Q") self.exitMenuButton.setStatusTip("Exit application") self.exitMenuButton.triggered.connect(self.close) self.fileMenu.addAction(self.exitMenuButton) self.pathMenuButton = QAction(QIcon(), "Edit Paths", self) self.pathMenuButton.setShortcut("Ctrl+E") self.pathMenuButton.setStatusTip("Edit Paths") self.pathMenuButton.triggered.connect(self.editPathActionEvent) self.editMenu.addAction(self.pathMenuButton) self.startHypervisorMenuButton = QAction(QIcon(), "Instantiate Hypervisor", self) self.startHypervisorMenuButton.setShortcut("Ctrl+O") self.startHypervisorMenuButton.setStatusTip( "Start the hypervisor that is currently configured") self.startHypervisorMenuButton.triggered.connect( self.startHypervisorActionEvent) self.hypervisorMenu.addAction(self.startHypervisorMenuButton) def getWritableData(self, configname): logging.debug("MainApp: getWritableData() instantiated") jsondata = {} jsondata["xml"] = {} #get baseWidget data baseWidget = self.baseWidgets[configname]["BaseWidget"] ###TODO: make this work for multiple experiments (current testing assumes only one) if isinstance(baseWidget, BaseWidget): jsondata["xml"] = baseWidget.getWritableData() ###Setup the dictionary if "testbed-setup" not in jsondata["xml"]: jsondata["xml"]["testbed-setup"] = {} if "vm-set" not in jsondata["xml"]["testbed-setup"]: jsondata["xml"]["testbed-setup"]["vm-set"] = {} if "vm" not in jsondata["xml"]["testbed-setup"]["vm-set"]: jsondata["xml"]["testbed-setup"]["vm-set"]["vm"] = [] if "material" not in jsondata["xml"]["testbed-setup"]["vm-set"]: jsondata["xml"]["testbed-setup"]["vm-set"]["material"] = [] for vmData in self.baseWidgets[configname]["VMWidgets"].values(): jsondata["xml"]["testbed-setup"]["vm-set"]["vm"].append( vmData.getWritableData()) for materialData in self.baseWidgets[configname][ "MaterialWidgets"].values(): jsondata["xml"]["testbed-setup"]["vm-set"]["material"].append( materialData.getWritableData()) return jsondata def saveExperimentButton(self): logging.debug("MainApp: saveExperiment() instantiated") self.saveExperiment() def saveExperiment(self, configname=None): logging.debug("MainApp: saveExperiment() instantiated") selectedItem = self.experimentTree.currentItem() if selectedItem == None: logging.debug("MainApp:onItemSelected no configurations left") self.statusBar.showMessage( "Could not save. No configuration items selected or available." ) return #Check if it's the case that an experiment name was selected parentSelectedItem = selectedItem.parent() if parentSelectedItem != None: selectedItem = parentSelectedItem configname = selectedItem.text(0) jsondata = self.getWritableData(configname) self.ec.writeExperimentXMLFileData(jsondata, configname) self.ec.writeExperimentJSONFileData(jsondata, configname) self.ec.getExperimentVMRolledOut(configname, jsondata, force_refresh=True) res = self.ec.getExperimentServerInfo(configname) #Now reset the experimentActions view self.experimentActionsWidget.resetExperiment(configname, jsondata) self.connectionWidget.resetExperiment(configname, jsondata) self.statusBar.showMessage( "Succesfully saved experiment file for " + str(configname), 2000)
class MainWindow(QMainWindow, metaclass=QSingleton): new_session = pyqtSignal() save_session = pyqtSignal(str) open_session = pyqtSignal(str) def __init__(self): super().__init__() self.setMinimumSize(500, 400) self._cue_add_menu = {} self.layout = None # Status Bar self.statusBar = QStatusBar(self) self.setStatusBar(self.statusBar) MainActionsHandler().action_done.connect(self._action_done) MainActionsHandler().action_undone.connect(self._action_undone) MainActionsHandler().action_redone.connect(self._action_redone) # Menubar self.menubar = QMenuBar(self) self.menubar.setGeometry(QtCore.QRect(0, 0, 0, 25)) self.menubar.setContextMenuPolicy(QtCore.Qt.PreventContextMenu) self.menuFile = QMenu(self.menubar) self.menuEdit = QMenu(self.menubar) self.menuLayout = QMenu(self.menubar) self.menuTools = QMenu(self.menubar) self.menuAbout = QMenu(self.menubar) self.menubar.addMenu(self.menuFile) self.menubar.addMenu(self.menuEdit) self.menubar.addMenu(self.menuLayout) self.menubar.addMenu(self.menuTools) self.menubar.addMenu(self.menuAbout) self.setMenuBar(self.menubar) # menuFile self.newSessionAction = QAction(self) self.newSessionAction.triggered.connect(self._new_session) self.openSessionAction = QAction(self) self.openSessionAction.triggered.connect(self._load_from_file) self.saveSessionAction = QAction(self) self.saveSessionAction.triggered.connect(self._save) self.saveSessionWithName = QAction(self) self.saveSessionWithName.triggered.connect(self._save_with_name) self.editPreferences = QAction(self) self.editPreferences.triggered.connect(self._show_preferences) self.fullScreenAction = QAction(self) self.fullScreenAction.triggered.connect(self._fullscreen) self.fullScreenAction.setCheckable(True) self.exitAction = QAction(self) self.exitAction.triggered.connect(self._exit) self.menuFile.addAction(self.newSessionAction) self.menuFile.addAction(self.openSessionAction) self.menuFile.addSeparator() self.menuFile.addAction(self.saveSessionAction) self.menuFile.addAction(self.saveSessionWithName) self.menuFile.addSeparator() self.menuFile.addAction(self.editPreferences) self.menuFile.addSeparator() self.menuFile.addAction(self.fullScreenAction) self.menuFile.addSeparator() self.menuFile.addAction(self.exitAction) # menuEdit self.actionUndo = QAction(self) self.actionUndo.triggered.connect(MainActionsHandler().undo_action) self.actionRedo = QAction(self) self.actionRedo.triggered.connect(MainActionsHandler().redo_action) self.multiEdit = QAction(self) self.selectAll = QAction(self) self.deselectAll = QAction(self) self.invertSelection = QAction(self) self.cueSeparator = self.menuEdit.addSeparator() self.menuEdit.addAction(self.actionUndo) self.menuEdit.addAction(self.actionRedo) self.menuEdit.addSeparator() self.menuEdit.addAction(self.selectAll) self.menuEdit.addAction(self.deselectAll) self.menuEdit.addAction(self.invertSelection) self.menuEdit.addSeparator() self.menuEdit.addAction(self.multiEdit) # menuAbout self.actionAbout = QAction(self) self.actionAbout.triggered.connect(about.About(self).show) self.actionAbout_Qt = QAction(self) self.actionAbout_Qt.triggered.connect(qApp.aboutQt) self.menuAbout.addAction(self.actionAbout) self.menuAbout.addSeparator() self.menuAbout.addAction(self.actionAbout_Qt) # Set component text self.retranslateUi() # The save file name self.filename = '' def retranslateUi(self): self.setWindowTitle('Linux Show Player') # menuFile self.menuFile.setTitle("&File") self.newSessionAction.setText("New session") self.newSessionAction.setShortcut("CTRL+N") self.openSessionAction.setText("Open") self.openSessionAction.setShortcut("CTRL+O") self.saveSessionAction.setText("Save session") self.saveSessionAction.setShortcut("CTRL+S") self.editPreferences.setText("Preferences") self.editPreferences.setShortcut("CTRL+P") self.saveSessionWithName.setText("Save with name") self.saveSessionWithName.setShortcut('CTRL+SHIFT+S') self.fullScreenAction.setText('Toggle fullscreen') self.fullScreenAction.setShortcut('F11') self.exitAction.setText("Exit") # menuEdit self.menuEdit.setTitle("&Edit") self.actionUndo.setText('Undo') self.actionUndo.setShortcut('CTRL+Z') self.actionRedo.setText('Redo') self.actionRedo.setShortcut('CTRL+Y') self.selectAll.setText("Select all") self.selectAll.setShortcut("CTRL+A") self.deselectAll.setText("Deselect all") self.deselectAll.setShortcut("CTRL+SHIFT+A") self.invertSelection.setText("Invert selection") self.invertSelection.setShortcut("CTRL+I") self.multiEdit.setText("Edit selected media") self.multiEdit.setShortcut("CTRL+SHIFT+E") # menuLayout self.menuLayout.setTitle("&Layout") # menuTools self.menuTools.setTitle("&Tools") self.multiEdit.setText("Edit selected media") # menuAbout self.menuAbout.setTitle("&About") self.actionAbout.setText("About") self.actionAbout_Qt.setText("About Qt") def set_layout(self, layout): if self.layout is not None: self.takeCentralWidget().hide() self.multiEdit.triggered.disconnect() self.selectAll.triggered.disconnect() self.deselectAll.triggered.disconnect() self.invertSelection.triggered.disconnect() self.layout = layout self.setCentralWidget(self.layout) self.layout.show() self.multiEdit.triggered.connect(self.layout.edit_selected_cues) self.selectAll.triggered.connect(self.layout.select_all) self.deselectAll.triggered.connect(self.layout.deselect_all) self.invertSelection.triggered.connect(self.layout.invert_selection) def contextMenuEvent(self, event): if self.layout.geometry().contains(event.pos()): self.menuEdit.move(event.globalPos()) self.menuEdit.show() # Adjust the menu position desktop = qApp.desktop().availableGeometry() menu_rect = self.menuEdit.geometry() if menu_rect.bottom() > desktop.bottom(): self.menuEdit.move(self.menuEdit.x(), self.menuEdit.y() - self.menuEdit.height()) if menu_rect.right() > desktop.right(): self.menuEdit.move(self.menuEdit.x() - self.menuEdit.width(), self.menuEdit.y()) def closeEvent(self, event): self._exit() event.ignore() def register_cue_menu_action(self, name, function, category='', shortcut=''): """Register a new-cue choice for the edit-menu param name: The name for the MenuAction param function: The function that add the new cue(s) param category: The optional menu where insert the MenuAction param shortcut: An optional shortcut for the MenuAction """ action = QAction(self) action.setText(name) action.triggered.connect(function) if shortcut != '': action.setShortcut(shortcut) if category != '': if category not in self._cue_add_menu: menu = QMenu(category, self) self._cue_add_menu[category] = menu self.menuEdit.insertMenu(self.cueSeparator, menu) self._cue_add_menu[category].addAction(action) else: self.menuEdit.insertAction(self.cueSeparator, action) def update_window_title(self): saved = MainActionsHandler().is_saved() if not saved and not self.windowTitle()[0] == '*': self.setWindowTitle('*' + self.windowTitle()) elif saved and self.windowTitle()[0] == '*': self.setWindowTitle(self.windowTitle()[1:]) def _action_done(self, action): self.statusBar.showMessage(action.log()) self.update_window_title() def _action_undone(self, action): self.statusBar.showMessage('Undone: ' + action.log()) self.update_window_title() def _action_redone(self, action): self.statusBar.showMessage('Redone: ' + action.log()) self.update_window_title() def _save(self): if self.filename == '': self._save_with_name() else: self.save_session.emit(self.filename) def _save_with_name(self): filename, _ = QFileDialog.getSaveFileName(parent=self, filter='*.lsp', directory=os.getenv('HOME')) if filename != '': if not filename.endswith('.lsp'): filename += '.lsp' self.filename = filename self._save() def _show_preferences(self): prefUi = AppSettings(configuration.config_to_dict(), parent=self) prefUi.exec_() if prefUi.result() == QDialog.Accepted: configuration.update_config_from_dict(prefUi.get_configuraton()) def _load_from_file(self): if self._check_saved(): path, _ = QFileDialog.getOpenFileName(filter='*.lsp', directory=os.getenv('HOME')) if os.path.exists(path): self.open_session.emit(path) self.filename = path def _new_session(self): if self._check_saved(): self.new_session.emit() def _check_saved(self): if not MainActionsHandler().is_saved(): msgBox = QMessageBox(self) msgBox.setIcon(QMessageBox.Warning) msgBox.setWindowTitle('Close session') msgBox.setText('The current session is not saved.') msgBox.setInformativeText('Discard the changes?') msgBox.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) msgBox.setDefaultButton(QMessageBox.Save) result = msgBox.exec_() if result == QMessageBox.Cancel: return False elif result == QMessageBox.Save: self._save() return True def _fullscreen(self, enable): if enable: self.showFullScreen() else: self.showMaximized() def _exit(self): if self._check_saved(): qApp.quit()
class Player(QtWidgets.QMainWindow): def __init__(self, muted=False, save_frames=False, master=None): QtWidgets.QMainWindow.__init__(self, master) self.setWindowIcon(QIcon("icons/app.svg")) self.title = "Bilkent Video Annotation Tool" self.muted = muted self.save_frames = save_frames self.setWindowTitle(self.title) options = QFileDialog.Options() options |= QFileDialog.ShowDirsOnly options |= QFileDialog.Directory # options |= QFileDialog.DontUseNativeDialog supported_formats = [ ".mp3", ".mp4", ".avi", ".wmv", ".mp4", ".mov", ".ogg", ".wav", ".ogm" ] self.video_paths = [] while len(self.video_paths) == 0: videos_dir = str( QFileDialog.getExistingDirectory(self, "Select Videos Directory", options=options)) self.video_paths = [] for fmt in supported_formats: self.video_paths += [ f for f in glob.glob(videos_dir + "**/*" + fmt, recursive=False) ] print(self.video_paths) if len(self.video_paths) == 0 or len(videos_dir) == 0: QtWidgets.QMessageBox.question( self, 'No videos exist', "Please select a directory containing videos.", QtWidgets.QMessageBox.Ok) self.annotations_dir = "" while len(self.annotations_dir) == 0: self.annotations_dir = str( QFileDialog.getExistingDirectory( self, "Select Annotations Directory", options=options)) print(self.annotations_dir) self.annotation_paths = [ f for f in glob.glob(self.annotations_dir + "**/*.json", recursive=False) ] if len(self.annotations_dir) == 0: QtWidgets.QMessageBox.question( self, 'No directory selected.', "Please select a directory for annotations", QtWidgets.QMessageBox.Ok) self.num_videos = len(self.video_paths) self.current_video = 0 self.annotations = {} for annotation_path in self.annotation_paths: j = json.load(open(annotation_path, "r")) self.annotations[j["name"]] = j print(self.annotation_paths) self.createVideoPlayer() self.createUI() self.createToolbar() self.statusbar = QStatusBar(self) self.setStatusBar(self.statusbar) self.current_annotation = "A" self.statusbar.showMessage("Current Annotation: " + self.current_annotation) self.createShortcuts() is_video_set = False for i, video_path in enumerate(self.video_paths): if "\\" in video_path: video_name = video_path.split("\\")[-1] else: video_name = video_path.split("/")[-1] if video_name not in self.annotations: self.file = self.OpenFile(video_path) self.current_video_attrs = self.annotations.get( video_name, { "name": video_name, "path": video_path, "annotations": {} }) self.annotations[self.current_video_attrs[ "name"]] = self.current_video_attrs self.current_video = i is_video_set = True break if not is_video_set: video_path = self.video_paths[0] if "\\" in video_path: video_name = video_path.split("\\")[-1] else: video_name = video_path.split("/")[-1] self.file = self.OpenFile(video_path) self.current_video_attrs = self.annotations.get( video_name, { "name": video_name, "path": video_path, "annotations": {} }) self.annotations[ self.current_video_attrs["name"]] = self.current_video_attrs self.play() self.next_visible = True self.prev_visible = True self.setVisibilities() def setPrevNextVisibility(self): self.prev_visible = self.current_video != 0 self.next_visible = self.current_video != self.num_videos - 1 self.remove_visible = self.current_video_attrs[ "name"] in self.annotations and len(self.annotations[ self.current_video_attrs["name"]]["annotations"]) > 0 self.action_previous.setVisible(self.prev_visible) self.action_next.setVisible(self.next_visible) self.action_remove_annotations.setVisible(self.remove_visible) self.statusbar.clearMessage() self.statusbar.showMessage("Current Annotation: " + self.current_annotation) def createShortcuts(self): self.shortcut_playpause = QShortcut(QKeySequence(QtCore.Qt.Key_Return), self) self.shortcut_playpause.activated.connect(self.playPauseShortcut) self.shortcut_previous = QShortcut(QKeySequence(QtCore.Qt.Key_Left), self) self.shortcut_previous.activated.connect(self.previousShortcut) self.shortcut_next = QShortcut(QKeySequence(QtCore.Qt.Key_Right), self) self.shortcut_next.activated.connect(self.nextShortcut) self.shortcut_annotate = QShortcut(QKeySequence(QtCore.Qt.Key_Space), self) self.shortcut_annotate.activated.connect(self.annotate) self.shortcut_remove_annotation = QShortcut( QKeySequence(QtCore.Qt.Key_Backspace), self) self.shortcut_remove_annotation.activated.connect( self.removeAnnotations) for s in string.ascii_uppercase: key = getattr(QtCore.Qt, "Key_" + s) shortcut = QShortcut(QKeySequence(key), self) shortcut.activated.connect(self.changeAnnotationShortcut(s)) def changeAnnotationShortcut(self, s): def annotationShortcut(): self.current_annotation = s self.statusbar.clearMessage() self.statusbar.showMessage("Current Annotation: " + self.current_annotation) return annotationShortcut def removeAnnotations(self): self.current_video_attrs["annotations"] = {} self.annotations[ self.current_video_attrs["name"]] = self.current_video_attrs self.setVisibilities() def previousShortcut(self): if self.prev_visible: self.previous() def nextShortcut(self): if self.next_visible: self.next() def setVisibilities(self): self.setPrevNextVisibility() self.markwidget.setAnnotations( self.annotations[self.current_video_attrs["name"]]["annotations"]) def annotate(self): self.current_video_attrs["annotations"][self.current_annotation] = [ self.mediaplayer.get_position() ] + self.current_video_attrs["annotations"].get( self.current_annotation, []) self.annotations[ self.current_video_attrs["name"]] = self.current_video_attrs self.setVisibilities() if self.save_frames: self.writeFrameToFile() def writeFrameToFile(self): path_to_save = os.path.join(self.annotations_dir, self.current_annotation) if not os.path.exists(path_to_save): os.mkdir(path_to_save) frame_file_name = os.path.join( path_to_save, f'{self.current_video_attrs["name"]}_{str(self.mediaplayer.get_position())}' .replace(".", "_") + '.png') self.mediaplayer.video_take_snapshot(0, frame_file_name, 0, 0) def saveAnnotation(self, annotation): with open( os.path.join(self.annotations_dir, annotation["name"] + ".json"), "w+") as f: json.dump(annotation, f) def playPauseShortcut(self): if self.isPaused: self.play() else: self.pause() def createVideoPlayer(self): self.instance = vlc.Instance() self.mediaplayer = self.instance.media_player_new() if self.muted: self.mediaplayer.audio_set_volume(0) self.isPaused = False def createToolbar(self): toolbar = QToolBar("Manage Video") toolbar.setIconSize(QSize(32, 32)) self.addToolBar(toolbar) self.action_play = QAction(QIcon("icons/play-button.png"), "Play", self) self.action_play.triggered.connect(self.play) self.action_play.setStatusTip("Play Video [Enter Key]") toolbar.addAction(self.action_play) self.action_pause = QAction(QIcon("icons/pause.png"), "Pause", self) self.action_pause.triggered.connect(self.pause) self.action_pause.setVisible(False) self.action_pause.setStatusTip("Pause Video [Enter Key]") toolbar.addAction(self.action_pause) self.action_previous = QAction(QIcon("icons/previous.png"), "Previous Video", self) self.action_previous.setStatusTip("Previous Video [Left Arrow]") self.action_previous.triggered.connect(self.previous) toolbar.addAction(self.action_previous) self.action_next = QAction(QIcon("icons/next.png"), "Next Video", self) self.action_next.triggered.connect(self.next) self.action_next.setStatusTip("Next Video [Right Arrow]") toolbar.addAction(self.action_next) self.action_annotate = QAction( QIcon("icons/plus.png"), "Annotate to current frame of the video", self) self.action_annotate.triggered.connect(self.annotate) self.action_annotate.setStatusTip( "Annotate to current frame of the video [Space Key]") toolbar.addAction(self.action_annotate) self.action_remove_annotations = QAction( QIcon("icons/cancel.png"), "Remove current video's annotations", self) self.action_remove_annotations.triggered.connect( self.removeAnnotations) self.action_remove_annotations.setStatusTip( "Remove current video's annotations [Backspace Key]") toolbar.addAction(self.action_remove_annotations) def play(self): print("Play clicked") self.PlayPause() def pause(self): print("Pause clicked") self.PlayPause() def previous(self): print("Previous clicked") if self.current_video - 1 < 0: return self.saveAnnotation(self.current_video_attrs) if not self.isPaused: self.Stop() self.current_video -= 1 video_path = self.video_paths[self.current_video] if "\\" in video_path: video_name = video_path.split("\\")[-1] else: video_name = video_path.split("/")[-1] self.file = self.OpenFile(video_path) if video_name in self.annotations: self.current_video_attrs = self.annotations[video_name] else: self.current_video_attrs = { "name": video_name, "path": video_path, "annotations": {} } self.annotations[video_name] = self.current_video_attrs self.progress.setValue(self.current_video) self.setVisibilities() self.play() def next(self): print("Next clicked") self.saveAnnotation(self.current_video_attrs) if not self.isPaused: self.Stop() self.current_video += 1 if self.current_video == self.num_videos: QtWidgets.QMessageBox.question( self, "No more videos left.", "All videos are annotated. Now, opening the first video...", QtWidgets.QMessageBox.Ok) self.current_video = 0 video_path = self.video_paths[self.current_video] if "\\" in video_path: video_name = video_path.split("\\")[-1] else: video_name = video_path.split("/")[-1] self.file = self.OpenFile(video_path) if video_name in self.annotations: self.current_video_attrs = self.annotations[video_name] else: self.current_video_attrs = { "name": video_name, "path": video_path, "annotations": {} } self.annotations[video_name] = self.current_video_attrs self.progress.setValue(self.current_video) self.setVisibilities() self.play() def createUI(self): """Set up the user interface, signals & slots """ self.widget = QtWidgets.QWidget(self) self.setCentralWidget(self.widget) # In this widget, the video will be drawn # if sys.platform == "darwin": # for MacOS # self.videoframe = QtWidgets.QMacCocoaViewContainer(0) # else: # self.videoframe = QtWidgets.QFrame() self.videoframe = QtWidgets.QFrame() self.palette = self.videoframe.palette() self.palette.setColor(QtGui.QPalette.Window, QtGui.QColor(0, 0, 0)) self.videoframe.setPalette(self.palette) self.videoframe.setAutoFillBackground(True) self.positionslider = QtWidgets.QSlider(QtCore.Qt.Horizontal, self) self.positionslider.setToolTip("Position") self.positionslider.setMaximum(1000) self.positionslider.sliderMoved.connect(self.setPosition) self.vboxlayout = QtWidgets.QVBoxLayout() self.vboxlayout.addWidget(self.videoframe) self.vboxlayout.addWidget(self.positionslider) self.markwidget = MarkWidget() self.vboxlayout.addWidget(self.markwidget) self.widget.setLayout(self.vboxlayout) self.progress = QtWidgets.QProgressBar(self) self.progress.setMaximum(self.num_videos) self.vboxlayout.addWidget(self.progress) self.timer = QtCore.QTimer(self) self.timer.setInterval(100) self.timer.timeout.connect(self.updateUI) def PlayPause(self): """Toggle play/pause status """ if self.mediaplayer.is_playing(): self.mediaplayer.pause() self.action_play.setVisible(True) self.action_pause.setVisible(False) self.isPaused = True else: self.mediaplayer.play() self.action_play.setVisible(False) self.action_pause.setVisible(True) self.timer.start() self.isPaused = False def Stop(self): """Stop player """ self.mediaplayer.stop() def OpenFile(self, filename=None): """Open a media file in a MediaPlayer """ if filename is None or filename is False: print("Attempt to openup OpenFile") filenameraw = QtWidgets.QFileDialog.getOpenFileName( self, "Open File", os.path.expanduser('~')) filename = filenameraw[0] if not filename: return # create the media if sys.version < '3': filename = unicode(filename) self.media = self.instance.media_new(filename) # put the media in the media player self.mediaplayer.set_media(self.media) # parse the metadata of the file self.media.parse() # set the title of the track as window title self.setWindowTitle(self.title + " | " + self.media.get_meta(0)) # the media player has to be 'connected' to the QFrame # (otherwise a video would be displayed in it's own window) # this is platform specific! # you have to give the id of the QFrame (or similar object) to # vlc, different platforms have different functions for this if sys.platform.startswith('linux'): # for Linux using the X Server self.mediaplayer.set_xwindow(self.videoframe.winId()) elif sys.platform == "win32": # for Windows self.mediaplayer.set_hwnd(self.videoframe.winId()) elif sys.platform == "darwin": # for MacOS self.mediaplayer.set_nsobject(int(self.videoframe.winId())) def setPosition(self, position): """Set the position """ # setting the position to where the slider was dragged self.mediaplayer.set_position(position / 1000.0) # the vlc MediaPlayer needs a float value between 0 and 1, Qt # uses integer variables, so you need a factor; the higher the # factor, the more precise are the results # (1000 should be enough) def updateUI(self): """updates the user interface""" # setting the slider to the desired position self.positionslider.setValue(self.mediaplayer.get_position() * 1000) if not self.mediaplayer.is_playing(): # no need to call this function if nothing is played self.timer.stop() if not self.isPaused: self.Stop() self.next()
class MainWindow_Ui(QMainWindow): def __init__(self, persepolis_setting): super().__init__() # MainWindow self.persepolis_setting = persepolis_setting icons = ':/' + \ str(self.persepolis_setting.value('settings/icons')) + '/' self.setWindowTitle("Persepolis Download Manager") self.setWindowIcon( QIcon.fromTheme('persepolis', QIcon(':/persepolis.svg'))) self.centralwidget = QWidget(self) self.verticalLayout = QVBoxLayout(self.centralwidget) # enable drag and drop self.setAcceptDrops(True) # frame self.frame = QFrame(self.centralwidget) # download_table_horizontalLayout download_table_horizontalLayout = QHBoxLayout() tabels_splitter = QSplitter(Qt.Horizontal) # category_tree self.category_tree_qwidget = QWidget(self) category_tree_verticalLayout = QVBoxLayout() self.category_tree = CategoryTreeView(self) category_tree_verticalLayout.addWidget(self.category_tree) self.category_tree_model = QStandardItemModel() self.category_tree.setModel(self.category_tree_model) category_table_header = ['Category'] self.category_tree_model.setHorizontalHeaderLabels( category_table_header) self.category_tree.header().setStretchLastSection(True) # queue_panel self.queue_panel_widget = QWidget(self) queue_panel_verticalLayout_main = QVBoxLayout(self.queue_panel_widget) # queue_panel_show_button self.queue_panel_show_button = QPushButton(self) queue_panel_verticalLayout_main.addWidget(self.queue_panel_show_button) # queue_panel_widget_frame self.queue_panel_widget_frame = QFrame(self) self.queue_panel_widget_frame.setFrameShape(QFrame.StyledPanel) self.queue_panel_widget_frame.setFrameShadow(QFrame.Raised) queue_panel_verticalLayout_main.addWidget( self.queue_panel_widget_frame) queue_panel_verticalLayout = QVBoxLayout(self.queue_panel_widget_frame) queue_panel_verticalLayout_main.setContentsMargins(50, -1, 50, -1) # start_end_frame self.start_end_frame = QFrame(self) # start time start_verticalLayout = QVBoxLayout(self.start_end_frame) self.start_checkBox = QCheckBox(self) start_verticalLayout.addWidget(self.start_checkBox) self.start_frame = QFrame(self) self.start_frame.setFrameShape(QFrame.StyledPanel) self.start_frame.setFrameShadow(QFrame.Raised) start_frame_verticalLayout = QVBoxLayout(self.start_frame) self.start_time_qDataTimeEdit = QDateTimeEdit(self.start_frame) self.start_time_qDataTimeEdit.setDisplayFormat('H:mm') start_frame_verticalLayout.addWidget(self.start_time_qDataTimeEdit) start_verticalLayout.addWidget(self.start_frame) # end time self.end_checkBox = QCheckBox(self) start_verticalLayout.addWidget(self.end_checkBox) self.end_frame = QFrame(self) self.end_frame.setFrameShape(QFrame.StyledPanel) self.end_frame.setFrameShadow(QFrame.Raised) end_frame_verticalLayout = QVBoxLayout(self.end_frame) self.end_time_qDateTimeEdit = QDateTimeEdit(self.end_frame) self.end_time_qDateTimeEdit.setDisplayFormat('H:mm') end_frame_verticalLayout.addWidget(self.end_time_qDateTimeEdit) start_verticalLayout.addWidget(self.end_frame) self.reverse_checkBox = QCheckBox(self) start_verticalLayout.addWidget(self.reverse_checkBox) queue_panel_verticalLayout.addWidget(self.start_end_frame) # limit_after_frame self.limit_after_frame = QFrame(self) # limit_checkBox limit_verticalLayout = QVBoxLayout(self.limit_after_frame) self.limit_checkBox = QCheckBox(self) limit_verticalLayout.addWidget(self.limit_checkBox) # limit_frame self.limit_frame = QFrame(self) self.limit_frame.setFrameShape(QFrame.StyledPanel) self.limit_frame.setFrameShadow(QFrame.Raised) limit_verticalLayout.addWidget(self.limit_frame) limit_frame_verticalLayout = QVBoxLayout(self.limit_frame) # limit_spinBox limit_frame_horizontalLayout = QHBoxLayout() self.limit_spinBox = QDoubleSpinBox(self) self.limit_spinBox.setMinimum(1) self.limit_spinBox.setMaximum(1023) limit_frame_horizontalLayout.addWidget(self.limit_spinBox) # limit_comboBox self.limit_comboBox = QComboBox(self) self.limit_comboBox.addItem("") self.limit_comboBox.addItem("") limit_frame_horizontalLayout.addWidget(self.limit_comboBox) limit_frame_verticalLayout.addLayout(limit_frame_horizontalLayout) # limit_pushButton self.limit_pushButton = QPushButton(self) limit_frame_verticalLayout.addWidget(self.limit_pushButton) # after_checkBox self.after_checkBox = QtWidgets.QCheckBox(self) limit_verticalLayout.addWidget(self.after_checkBox) # after_frame self.after_frame = QtWidgets.QFrame(self) self.after_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) self.after_frame.setFrameShadow(QtWidgets.QFrame.Raised) limit_verticalLayout.addWidget(self.after_frame) after_frame_verticalLayout = QVBoxLayout(self.after_frame) # after_comboBox self.after_comboBox = QComboBox(self) self.after_comboBox.addItem("") after_frame_verticalLayout.addWidget(self.after_comboBox) # after_pushButton self.after_pushButton = QPushButton(self) after_frame_verticalLayout.addWidget(self.after_pushButton) queue_panel_verticalLayout.addWidget(self.limit_after_frame) category_tree_verticalLayout.addWidget(self.queue_panel_widget) # keep_awake_checkBox self.keep_awake_checkBox = QCheckBox(self) queue_panel_verticalLayout.addWidget(self.keep_awake_checkBox) self.category_tree_qwidget.setLayout(category_tree_verticalLayout) tabels_splitter.addWidget(self.category_tree_qwidget) # download table widget self.download_table_content_widget = QWidget(self) download_table_content_widget_verticalLayout = QVBoxLayout( self.download_table_content_widget) self.download_table = DownloadTableWidget(self) download_table_content_widget_verticalLayout.addWidget( self.download_table) tabels_splitter.addWidget(self.download_table_content_widget) self.download_table.setColumnCount(13) self.download_table.setSelectionBehavior(QAbstractItemView.SelectRows) self.download_table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.download_table.verticalHeader().hide() # hide gid and download dictioanry section self.download_table.setColumnHidden(8, True) self.download_table.setColumnHidden(9, True) download_table_header = [ 'File Name', 'Status', 'Size', 'Downloaded', 'Percentage', 'Connections', 'Transfer rate', 'Estimate time left', 'Gid', 'Link', 'First try date', 'Last try date', 'Category' ] self.download_table.setHorizontalHeaderLabels(download_table_header) # fixing the size of download_table when window is Maximized! self.download_table.horizontalHeader().setSectionResizeMode(0) self.download_table.horizontalHeader().setStretchLastSection(True) tabels_splitter.setStretchFactor(0, 3) # category_tree width tabels_splitter.setStretchFactor(1, 10) # ratio of tables's width download_table_horizontalLayout.addWidget(tabels_splitter) self.frame.setLayout(download_table_horizontalLayout) self.verticalLayout.addWidget(self.frame) self.setCentralWidget(self.centralwidget) # menubar self.menubar = QMenuBar(self) self.menubar.setGeometry(QRect(0, 0, 600, 24)) self.setMenuBar(self.menubar) fileMenu = self.menubar.addMenu('&File') editMenu = self.menubar.addMenu('&Edit') viewMenu = self.menubar.addMenu('&View') downloadMenu = self.menubar.addMenu('&Download') queueMenu = self.menubar.addMenu('&Queue') helpMenu = self.menubar.addMenu('&Help') # viewMenu submenus sortMenu = viewMenu.addMenu('Sort by') # statusbar self.statusbar = QStatusBar(self) self.setStatusBar(self.statusbar) self.statusbar.showMessage("Persepolis Download Manager") # toolBar self.toolBar2 = QToolBar(self) self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar2) self.toolBar2.setWindowTitle('Menu') self.toolBar2.setIconSize(QSize(32, 32)) self.toolBar2.setFloatable(False) self.toolBar2.setMovable(False) self.toolBar = QToolBar(self) self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) self.toolBar.setWindowTitle('Toolbar') self.toolBar.setIconSize(QSize(32, 32)) self.toolBar.setFloatable(False) self.toolBar.setMovable(False) #toolBar and menubar and actions self.stopAllAction = QAction(QIcon(icons + 'stop_all'), 'Stop all active downloads', self, statusTip='Stop all active downloads', triggered=self.stopAllDownloads) downloadMenu.addAction(self.stopAllAction) self.sort_file_name_Action = QAction('File name', self, triggered=self.sortByName) sortMenu.addAction(self.sort_file_name_Action) self.sort_file_size_Action = QAction('File size', self, triggered=self.sortBySize) sortMenu.addAction(self.sort_file_size_Action) self.sort_first_try_date_Action = QAction( 'First try date', self, triggered=self.sortByFirstTry) sortMenu.addAction(self.sort_first_try_date_Action) self.sort_last_try_date_Action = QAction('Last try date', self, triggered=self.sortByLastTry) sortMenu.addAction(self.sort_last_try_date_Action) self.sort_download_status_Action = QAction('Download status', self, triggered=self.sortByStatus) sortMenu.addAction(self.sort_download_status_Action) self.trayAction = QAction('Show system tray icon', self, statusTip="Show/Hide system tray icon", triggered=self.showTray) self.trayAction.setCheckable(True) viewMenu.addAction(self.trayAction) self.showMenuBarAction = QAction('Show menubar', self, statusTip='Show menubar', triggered=self.showMenuBar) self.showMenuBarAction.setCheckable(True) viewMenu.addAction(self.showMenuBarAction) self.showSidePanelAction = QAction('Show side panel', self, statusTip='Show side panel', triggered=self.showSidePanel) self.showSidePanelAction.setCheckable(True) viewMenu.addAction(self.showSidePanelAction) self.minimizeAction = QAction(QIcon(icons + 'minimize'), 'Minimize to system tray', self, shortcut="Ctrl+W", statusTip="Minimize to system tray", triggered=self.minMaxTray) viewMenu.addAction(self.minimizeAction) self.addlinkAction = QAction(QIcon(icons + 'add'), 'Add New Download Link', self, shortcut="Ctrl+N", statusTip="Add New Download Link", triggered=self.addLinkButtonPressed) fileMenu.addAction(self.addlinkAction) self.addtextfileAction = QAction( QIcon(icons + 'file'), 'Import links from text file', self, statusTip='Create a Text file and put links in it.line by line!', triggered=self.importText) fileMenu.addAction(self.addtextfileAction) self.resumeAction = QAction(QIcon(icons + 'play'), 'Resume Download', self, shortcut="Ctrl+R", statusTip="Resume Download", triggered=self.resumeButtonPressed) downloadMenu.addAction(self.resumeAction) self.pauseAction = QAction(QIcon(icons + 'pause'), 'Pause Download', self, shortcut="Ctrl+C", statusTip="Pause Download", triggered=self.pauseButtonPressed) downloadMenu.addAction(self.pauseAction) self.stopAction = QAction(QIcon(icons + 'stop'), 'Stop Download', self, shortcut="Ctrl+S", statusTip="Stop/Cancel Download", triggered=self.stopButtonPressed) downloadMenu.addAction(self.stopAction) self.removeAction = QAction(QIcon(icons + 'remove'), 'Remove Download', self, shortcut="Ctrl+D", statusTip="Remove Download", triggered=self.removeButtonPressed) downloadMenu.addAction(self.removeAction) self.propertiesAction = QAction(QIcon(icons + 'setting'), 'Properties', self, shortcut="Ctrl+P", statusTip="Properties", triggered=self.propertiesButtonPressed) downloadMenu.addAction(self.propertiesAction) self.progressAction = QAction(QIcon(icons + 'window'), 'Progress', self, shortcut="Ctrl+Z", statusTip="Progress", triggered=self.progressButtonPressed) downloadMenu.addAction(self.progressAction) self.openFileAction = QAction(QIcon(icons + 'file'), 'Open file', self, statusTip='Open file', triggered=self.openFile) fileMenu.addAction(self.openFileAction) self.openDownloadFolderAction = QAction( QIcon(icons + 'folder'), 'Open download folder', self, statusTip='Open download folder', triggered=self.openDownloadFolder) fileMenu.addAction(self.openDownloadFolderAction) self.deleteFileAction = QAction(QIcon(icons + 'trash'), 'Delete file', self, statusTip='Delete file', triggered=self.deleteFile) fileMenu.addAction(self.deleteFileAction) self.openDefaultDownloadFolderAction = QAction( QIcon(icons + 'folder'), 'Open default download folder', self, statusTip='Open default download folder', triggered=self.openDefaultDownloadFolder) fileMenu.addAction(self.openDefaultDownloadFolderAction) self.exitAction = QAction(QIcon(icons + 'exit'), 'Exit', self, shortcut="Ctrl+Q", statusTip="Exit", triggered=self.closeEvent) fileMenu.addAction(self.exitAction) self.clearAction = QAction( QIcon(icons + 'multi_remove'), 'Clear download list', self, statusTip='Clear all items in download list', triggered=self.clearDownloadList) editMenu.addAction(self.clearAction) self.selectAction = QAction('Select multiple items ', self, statusTip='Select multiple items', triggered=self.selectDownloads) self.selectAction.setCheckable(True) editMenu.addAction(self.selectAction) self.selectAllAction = QAction(QIcon(icons + 'select_all'), 'Select All', self, statusTip='Select All', triggered=self.selectAll) editMenu.addAction(self.selectAllAction) self.selectAllAction.setEnabled(False) self.removeSelectedAction = QAction( QIcon(icons + 'multi_remove'), 'Remove selected downloads form list', self, statusTip='Remove selected downloads form list', triggered=self.removeSelected) editMenu.addAction(self.removeSelectedAction) self.removeSelectedAction.setEnabled(False) self.deleteSelectedAction = QAction( QIcon(icons + 'multi_trash'), 'Delete selected download files', self, statusTip='Delete selected download files', triggered=self.deleteSelected) editMenu.addAction(self.deleteSelectedAction) self.deleteSelectedAction.setEnabled(False) self.createQueueAction = QAction(QIcon(icons + 'add_queue'), 'Create new queue', self, statusTip='Create new download queue', triggered=self.createQueue) queueMenu.addAction(self.createQueueAction) self.removeQueueAction = QAction(QIcon(icons + 'remove_queue'), 'Remove this queue', self, statusTip='Remove this queue', triggered=self.removeQueue) queueMenu.addAction(self.removeQueueAction) self.startQueueAction = QAction(QIcon(icons + 'start_queue'), 'Start this queue', self, statusTip='Start this queue', triggered=self.startQueue) queueMenu.addAction(self.startQueueAction) self.stopQueueAction = QAction(QIcon(icons + 'stop_queue'), 'Stop this queue', self, statusTip='Stop this queue', triggered=self.stopQueue) queueMenu.addAction(self.stopQueueAction) self.moveUpAction = QAction( QIcon(icons + 'up'), 'Move up this item', self, statusTip='Move currently selected item up by one row', triggered=self.moveUp) queueMenu.addAction(self.moveUpAction) self.moveDownAction = QAction( QIcon(icons + 'down'), 'Move down this item', self, statusTip='Move currently selected item down by one row', triggered=self.moveDown) queueMenu.addAction(self.moveDownAction) self.moveUpSelectedAction = QAction( QIcon(icons + 'multi_up'), 'Move up selected items', self, statusTip='Move currently selected items up by one row', triggered=self.moveUpSelected) queueMenu.addAction(self.moveUpSelectedAction) self.moveDownSelectedAction = QAction( QIcon(icons + 'multi_down'), 'Move down selected items', self, statusTip='Move currently selected items down by one row', triggered=self.moveDownSelected) queueMenu.addAction(self.moveDownSelectedAction) self.preferencesAction = QAction(QIcon(icons + 'preferences'), 'Preferences', self, statusTip='Preferences', triggered=self.openPreferences, menuRole=5) editMenu.addAction(self.preferencesAction) self.aboutAction = QAction(QIcon(icons + 'about'), 'About', self, statusTip='About', triggered=self.openAbout, menuRole=4) helpMenu.addAction(self.aboutAction) self.issueAction = QAction(QIcon(icons + 'about'), 'Report an issue', self, statusTip='Report an issue', triggered=self.reportIssue) helpMenu.addAction(self.issueAction) self.updateAction = QAction(QIcon(icons + 'about'), 'Check for newer version', self, statusTip='Check for newer release', triggered=self.newUpdate) helpMenu.addAction(self.updateAction) self.logAction = QAction(QIcon(icons + 'about'), 'Show log file', self, statusTip='Help', triggered=self.showLog) helpMenu.addAction(self.logAction) self.helpAction = QAction(QIcon(icons + 'about'), 'Help', self, statusTip='Help', triggered=self.persepolisHelp) helpMenu.addAction(self.helpAction) self.qmenu = MenuWidget(self) self.toolBar2.addWidget(self.qmenu) # labels self.queue_panel_show_button.setText("Hide options") self.start_checkBox.setText("Start Time") self.end_checkBox.setText("End Time") self.reverse_checkBox.setText("Download bottom of\n the list first") self.limit_checkBox.setText("Limit Speed") self.limit_comboBox.setItemText(0, "KB/S") self.limit_comboBox.setItemText(1, "MB/S") self.limit_pushButton.setText("Apply") self.after_checkBox.setText("After download") self.after_comboBox.setItemText(0, "Shut Down") self.keep_awake_checkBox.setText("Keep system awake!") self.keep_awake_checkBox.setToolTip( "<html><head/><body><p>This option is preventing system from going to sleep.\ This is necessary if your power manager is suspending system automatically. </p></body></html>" ) self.after_pushButton.setText("Apply") def changeIcon(self, icons): icons = ':/' + str(icons) + '/' action_icon_dict = { self.stopAllAction: 'stop_all', self.minimizeAction: 'minimize', self.addlinkAction: 'add', self.addtextfileAction: 'file', self.resumeAction: 'play', self.pauseAction: 'pause', self.stopAction: 'stop', self.removeAction: 'remove', self.propertiesAction: 'setting', self.progressAction: 'window', self.openFileAction: 'file', self.openDownloadFolderAction: 'folder', self.deleteFileAction: 'trash', self.openDefaultDownloadFolderAction: 'folder', self.exitAction: 'exit', self.selectAllAction: 'select_all', self.removeSelectedAction: 'multi_remove', self.deleteSelectedAction: 'multi_trash', self.createQueueAction: 'add_queue', self.removeQueueAction: 'remove_queue', self.startQueueAction: 'start_queue', self.stopQueueAction: 'stop_queue', self.moveUpAction: 'up', self.moveDownAction: 'down', self.preferencesAction: 'preferences', self.aboutAction: 'about', self.issueAction: 'about', self.updateAction: 'about', self.qmenu: 'menu' } for key in action_icon_dict.keys(): key.setIcon(QIcon(icons + str(action_icon_dict[key])))
class ProcessDialog(QDialog): def __init__(self, port, **kwargs): super().__init__() self.setWindowTitle('Cooking your TinyGS station...') self.setFixedWidth(400) self.exception = None esptool.sw.progress.connect(self.update_progress) self.nam = QNetworkAccessManager() self.nrBinFile = QNetworkRequest() self.bin_data = b'' self.setLayout(VLayout(5, 5)) self.actions_layout = QFormLayout() self.actions_layout.setSpacing(5) self.layout().addLayout(self.actions_layout) self._actions = [] self._action_widgets = {} self.port = port self.auto_reset = kwargs.get('auto_reset', False) self.file_path = kwargs.get('file_path') if self.file_path and self.file_path.startswith('http'): self._actions.append('download') self.backup = kwargs.get('backup') if self.backup: self._actions.append('backup') self.backup_size = kwargs.get('backup_size') self.erase = kwargs.get('erase') if self.erase: self._actions.append('erase') if self.file_path: self._actions.append('write') self.create_ui() self.start_process() def create_ui(self): for action in self._actions: pb = QProgressBar() pb.setFixedHeight(35) self._action_widgets[action] = pb self.actions_layout.addRow(action.capitalize(), pb) self.btns = QDialogButtonBox(QDialogButtonBox.Abort) self.btns.rejected.connect(self.abort) self.layout().addWidget(self.btns) self.sb = QStatusBar() self.layout().addWidget(self.sb) def appendBinFile(self): self.bin_data += self.bin_reply.readAll() def saveBinFile(self): if self.bin_reply.error() == QNetworkReply.NoError: self.file_path = self.file_path.split('/')[-1] with open(self.file_path, 'wb') as f: f.write(self.bin_data) self.run_esp() else: raise NetworkError def updateBinProgress(self, recv, total): self._action_widgets['download'].setValue(recv // total * 100) def download_bin(self): self.nrBinFile.setUrl(QUrl(self.file_path)) self.bin_reply = self.nam.get(self.nrBinFile) self.bin_reply.readyRead.connect(self.appendBinFile) self.bin_reply.downloadProgress.connect(self.updateBinProgress) self.bin_reply.finished.connect(self.saveBinFile) def show_connection_state(self, state): self.sb.showMessage(state, 0) def run_esp(self): params = { 'file_path': self.file_path, 'auto_reset': self.auto_reset, 'erase': self.erase } if self.backup: backup_size = f'0x{2 ** self.backup_size}00000' params['backup_size'] = backup_size self.esp_thread = QThread() self.esp = ESPWorker(self.port, self._actions, **params) esptool.sw.connection_state.connect(self.show_connection_state) self.esp.waiting.connect(self.wait_for_user) self.esp.done.connect(self.accept) self.esp.error.connect(self.error) self.esp.moveToThread(self.esp_thread) self.esp_thread.started.connect(self.esp.run) self.esp_thread.start() def start_process(self): if 'download' in self._actions: self.download_bin() self._actions = self._actions[1:] else: self.run_esp() def update_progress(self, action, value): self._action_widgets[action].setValue(value) @pyqtSlot() def wait_for_user(self): dlg = QMessageBox.information( self, 'User action required', 'Please power cycle the device, wait a moment and press OK', QMessageBox.Ok | QMessageBox.Cancel) if dlg == QMessageBox.Ok: self.esp.continue_ok() elif dlg == QMessageBox.Cancel: self.esp.abort() self.esp.continue_ok() self.abort() def stop_thread(self): self.esp_thread.wait(2000) self.esp_thread.exit() def accept(self): self.stop_thread() self.done(QDialog.Accepted) def abort(self): self.sb.showMessage('Aborting...', 0) QApplication.processEvents() self.esp.abort() self.stop_thread() self.reject() def error(self, e): self.exception = e self.abort() def closeEvent(self, e): self.stop_thread()
def _createStatusBar(self): statusBar = QStatusBar() self.setStatusBar(statusBar) statusBar.showMessage("I am the f*****g status bar!")
class MainView(QMainWindow): def __init__(self, prb, model=None): super(MainView, self).__init__() self.prb = prb if model is not None: self._model = model self.initUI() def initUI(self): self.setAutoFillBackground(True) p = self.palette() p.setColor(self.backgroundRole(), Qt.darkGray) p.setColor(self.foregroundRole(), Qt.white) self.setPalette(p) self.setWindowTitle("Spiketag") self.status_bar = QStatusBar(self) self.setStatusBar(self.status_bar) self.status_bar.showMessage('Ready') self.centralWidget = QWidget(self) self.setCentralWidget(self.centralWidget) hbox = QHBoxLayout(self) self.splitter0 = QSplitter(Qt.Horizontal) self.splitter1 = QSplitter(Qt.Horizontal) self.splitter2 = QSplitter(Qt.Horizontal) self.splitter_fet = QSplitter(Qt.Vertical) self.splitter3 = QSplitter(Qt.Vertical) self.splitter3.addWidget(self.splitter1) self.splitter3.addWidget(self.splitter2) self.splitter3.setSizes([70, 30]) # uppper and down (up, down) self.splitter_prb_cpu = QSplitter(Qt.Vertical) self.prb_view = probe_view() self.clu_view = cluster_view() self.prb_view.set_data(self.prb, font_size=35) self.clu_view.set_data(self._model.clu_manager) self.splitter_prb_cpu.addWidget(self.prb_view.native) self.splitter_prb_cpu.addWidget(self.clu_view.native) self.splitter0.addWidget(self.splitter_prb_cpu) self.splitter0.addWidget(self.splitter3) self.splitter0.setSizes([20, 180]) # prb_view and all others (left, right) hbox.addWidget(self.splitter0) self.centralWidget.setLayout(hbox) self.spkview = spike_view() self.fetview0 = scatter_3d_view() self.fetview1 = scatter_3d_view() self.ampview = amplitude_view(fs=self.prb.fs, scale=1) self.corview = correlogram_view(fs=self.prb.fs) # self.treeview = ctree_view() self.pfview = pf_view(pc=self._model.pc) self.traceview = trace_view(data=self._model.mua.data, fs=self.prb.fs) self.splitter1.addWidget(self.traceview.native) self.splitter1.addWidget(self.splitter_fet) self.splitter_fet.addWidget(self.fetview0.native) self.splitter_fet.addWidget(self.fetview1.native) self.splitter1.addWidget(self.spkview.native) self.splitter1.setSizes([30, 50, 80]) # trace_view, fet_view, spk_view self.splitter2.addWidget(self.corview.native) self.splitter2.addWidget(self.pfview.native) self.splitter2.addWidget(self.ampview.native) self.splitter2.setSizes([40, 40, 100]) # corview, treeview, ampview def set_data(self, group_id, mua, spk, fet, clu): ### init view and set_data self.clu = clu chs = self.prb[group_id] self.spkview.set_data(spk, clu) # self.fetview0.set_data(fet, clu) # if fet.shape[1]>3: self.fetview0.dimension = [0, 1, 2] self.fetview0.set_data(fet, clu) #[:,[0,1,2]].copy() self.fetview1.dimension = [0, 1, 3] self.fetview1.set_data(fet, clu) #[:,[0,1,3]].copy() # else: self.ampview.set_data(spk, clu, mua.spk_times[group_id]) # self.treeview.set_data(clu) self.traceview.set_data(chs, clu, mua.spk_times[group_id]) try: self.corview.set_data(clu, mua.spk_times[group_id]) except Exception as e: pass self.pfview.set_data(clu, mua.spk_times[group_id] / self.prb.fs) self.traceview.locate_buffer = 1500 # everytime when view.set_data # the corresponding clu will go through its registration process # then won'g go through it again if self.clu._event_reg_enable is True: self.register_event() def register_event(self): self.spkview.register_event() self.fetview0.register_event() self.fetview1.register_event() self.ampview.register_event() self.traceview.register_event() self.corview.register_event() self.pfview.register_event() # make sure self.pfview already get pc self.clu._event_reg_enable = False def set_data_from_model(self, group_id): ### init view and set_data model = self._model chs = self.prb[group_id] self.spkview.set_data(model.spk[group_id], model.clu[group_id]) self.fetview0.dimension = [0, 1, 2] self.fetview0.set_data(model.fet[group_id], model.clu[group_id]) #[:,[0,1,2]].copy() self.fetview1.dimension = [0, 1, 3] self.fetview1.set_data(model.fet[group_id], model.clu[group_id]) #[:,[0,1,3]].copy() # else: self.ampview.set_data(model.spk[group_id], model.clu[group_id], model.mua.spk_times[group_id]) # self.treeview.set_data(model.clu[group_id]) self.traceview.set_data(self.prb[group_id], model.clu[group_id], model.mua.spk_times[group_id]) # try: # self.corview.set_data(model.clu[group_id], model.mua.spk_times[group_id]) # except Exception as e: # pass self.traceview.locate_buffer = 2000
class App(QWidget): def __init__(self, data, showRows): super().__init__() self.data = data self.showRows = showRows self.initUI() def initUI(self): self.setWindowTitle('DataFrame Viewer') self.showMaximized() self.activePage = 0 self.sortIndex = 0 self.sortAscending = False #Buttons self.prevButton = QPushButton("< Prev", self) self.nextButton = QPushButton("Next >", self) self.lastButton = QPushButton("Last >>", self) self.firstButton = QPushButton("<< First", self) self.nextButton.clicked.connect(self.nextPage) self.prevButton.clicked.connect(self.prevPage) self.lastButton.clicked.connect(self.lastPage) self.firstButton.clicked.connect(self.firstPage) #Search self.searchBox = QLineEdit(self) self.searchBox.setPlaceholderText('Search in selected column...') self.searchBox.returnPressed.connect(self.loadDataFrame) self.searchComboBox = QComboBox() for col_name in list(self.data.columns): self.searchComboBox.addItem(col_name) self.searchComboBox.currentIndexChanged.connect(self.loadDataFrame) self.searchQueryCheckBox = QCheckBox("Search Query") self.searchQueryCheckBox.stateChanged.connect(self.loadDataFrame) #Table widget self.tableWidget = QTableWidget() self.tableWidget.horizontalHeader().sectionDoubleClicked.connect( self.changeSortCriteria) #Status bar self.statusBar = QStatusBar() #Layout self.Vlayout = QHBoxLayout() self.layout = QVBoxLayout() self.Vlayout.addWidget(self.searchBox) self.Vlayout.addWidget(self.searchComboBox) self.Vlayout.addWidget(self.searchQueryCheckBox) self.Vlayout.addWidget(self.prevButton) self.Vlayout.addWidget(self.nextButton) self.Vlayout.addWidget(self.firstButton) self.Vlayout.addWidget(self.lastButton) self.layout.addLayout(self.Vlayout) self.layout.addWidget(self.tableWidget) self.layout.addWidget(self.statusBar) self.setLayout(self.layout) self.loadDataFrame() self.show() @pyqtSlot() def nextPage(self): if self.activePage != self.maxPageNumber: self.activePage += 1 self.loadDataFrame() def prevPage(self): if self.activePage != 0: self.activePage -= 1 self.loadDataFrame() def lastPage(self): self.activePage = self.maxPageNumber self.loadDataFrame() def firstPage(self): self.activePage = 0 self.loadDataFrame() def changeSortCriteria(self, i): if i == self.sortIndex: if self.sortAscending == True: self.sortAscending = False else: self.sortAscending = True self.sortIndex = i self.loadDataFrame() def loadDataFrame(self): try: df = self.data if len(self.searchBox.text()) >= 1: if self.searchQueryCheckBox.isChecked(): #Query mode df = df.query(self.searchBox.text()) #We print query to log print("Search Query: {}".format(self.searchBox.text())) else: df = df[df[self.searchComboBox.currentText()].astype( str).str.contains(self.searchBox.text())] self.rowsCount = df.shape[0] self.colsCount = df.shape[1] self.maxPageNumber = int(np.ceil( self.rowsCount / self.showRows)) - 1 #to fix wrong page bug in search mode if self.activePage > self.maxPageNumber: self.activePage = 0 self.statusBar.showMessage("Page {}/{}, Rows: {} - {}, Total Results : {}"\ .format(self.activePage,\ self.maxPageNumber,\ (self.activePage*self.showRows),\ (self.activePage*self.showRows+self.showRows),\ self.rowsCount)) df = df.reset_index()\ .sort_values(self.data.columns[self.sortIndex], ascending=self.sortAscending)\ .iloc[(self.activePage*self.showRows):(self.activePage*self.showRows+self.showRows)] self.tableWidget.setRowCount(0) self.tableWidget.setColumnCount(0) self.tableWidget.setColumnCount(self.colsCount) self.tableWidget.setHorizontalHeaderLabels(list(self.data.columns)) self.tableWidget.setRowCount(df.shape[0]) i = 0 for index, row in df.iterrows(): for col in range(self.colsCount): w_item = QTableWidgetItem(str(row[col + 1])) self.tableWidget.setItem(i, col, w_item) i += 1 except Exception as e: print("An error occured. {}".format(e))
class Widgets: """Contains widgets which store shared state.""" def __init__(self, window: QWidget) -> None: self.input_value = QLineEdit(window) self.output_value = QLineEdit(window) self.rootfamily_value = QComboBox(window) self.familydepth_value = QSpinBox(window) self.imagedir_value = QLineEdit(window) self.nameorder_value = QCheckBox(window) self.statusbar = QStatusBar() def set_input(self) -> None: """Handler for the input button.""" try: dialog = QFileDialog() dialog.setFileMode(QFileDialog.FileMode.ExistingFile) # pylint: disable=no-member dialog.setNameFilters(["GEDCOM files (*.ged)"]) if not dialog.exec(): return files = dialog.selectedFiles() assert len(files) == 1 ged_path = files[0] self.input_value.setText(ged_path) import_config = { 'input': ged_path, } ged_import = ged2dot.GedcomImport() graph = ged_import.load(import_config) self.rootfamily_value.clear() for node in graph: if not isinstance(node, ged2dot.Family): continue help_string = "" if node.husb and node.husb.get_surname(): help_string += node.husb.get_surname() help_string += "-" if node.wife and node.wife.get_surname(): help_string += node.wife.get_surname() key = f"{node.get_identifier()} ({help_string})" self.rootfamily_value.addItem(key, node.get_identifier()) self.update_status() except Exception: # pylint: disable=broad-except self.print_traceback() def set_output(self) -> None: """Handler for the output button.""" dialog = QFileDialog() dialog.setAcceptMode(QFileDialog.AcceptMode.AcceptSave) # pylint: disable=no-member name_filters = [ "SVG files (*.svg)", "PNG files (*.png)", "Graphviz files (*.dot)", ] dialog.setNameFilters(name_filters) if not dialog.exec(): return files = dialog.selectedFiles() assert len(files) == 1 self.output_value.setText(files[0]) self.update_status() def set_imagedir(self) -> None: """Handler for the imagedir button.""" dialog = QFileDialog() dialog.setFileMode(QFileDialog.FileMode.Directory) # pylint: disable=no-member if not dialog.exec(): return files = dialog.selectedFiles() assert len(files) == 1 self.imagedir_value.setText(files[0]) def convert(self) -> None: """Does the actual conversion.""" try: config = { "input": self.input_value.text(), "output": self.output_value.text(), "rootfamily": self.rootfamily_value.currentData(), "familydepth": str(self.familydepth_value.value()), "imagedir": self.imagedir_value.text(), "nameorder": "little", } if not self.nameorder_value.isChecked(): config["nameorder"] = "big" invoke_dot = False if not self.output_value.text().endswith(".dot"): invoke_dot = True config["output"] = self.output_value.text() + ".dot" self.statusbar.showMessage("Converting to " + config["output"] + "...") ged2dot.convert(config) if invoke_dot: self.statusbar.showMessage("Converting to " + self.output_value.text() + "...") self.to_graphic(config["output"], self.output_value.text()) webbrowser.open("file://" + self.output_value.text()) self.statusbar.showMessage("Conversion finished successfully.") except Exception: # pylint: disable=broad-except self.print_traceback() @staticmethod def to_graphic(dot_path: str, graphic_path: str) -> None: """Convert the generated .dot further to .png/.svg, using dot.""" graph = pygraphviz.AGraph(dot_path) if graphic_path.endswith(".png"): graph.draw(graphic_path, format="png", prog="dot") else: graph.draw(graphic_path, format="svg", prog="dot") @staticmethod def print_traceback() -> None: """Shows the exception to the user when it would not be caught.""" msg = QMessageBox() msg.setIcon(QMessageBox.Icon.Warning) # pylint: disable=no-member msg.setText("Conversion failed.") with io.StringIO() as stream: traceback.print_exc(file=stream) stream.seek(0) msg.setDetailedText(stream.read()) msg.exec() def update_status(self) -> None: """Updates the statusbar depending on what should be the next action.""" if not self.input_value.text(): message = "Select an input." elif not self.output_value.text(): message = "Select an output." else: message = "Press OK to start the conversion." self.statusbar.showMessage(message)
class ScoreDB(QWidget): def __init__(self): super().__init__() self.initUI() self.dbfilename = 'assignment6.dat' self.scoredb = [] self.readScoreDB() self.showScoreDB() def initUI(self): self.setGeometry(300, 300, 500, 250) self.setWindowTitle('Assignment6') namelable = QLabel("Name : ") self.nameedit = QLineEdit() agelable = QLabel("Age : ") self.ageedit = QLineEdit() scorelable = QLabel("Score : ") self.scoreedit = QLineEdit() vbox = QVBoxLayout() hbox1 = QHBoxLayout() hbox2 = QHBoxLayout() hbox3 = QHBoxLayout() hbox4 = QHBoxLayout() hbox5 = QHBoxLayout() hbox6 = QHBoxLayout() hbox7 = QHBoxLayout() amountlable = QLabel("Amount : ") self.amountedit = QLineEdit() keylable = QLabel("Key : ") self.selectedkey = QLabel("Age") funtionlabel = QLabel("Functions : ") addbutton = QPushButton("Add") addbutton.clicked.connect(self.addScoreDB) delbutton = QPushButton("Del") delbutton.clicked.connect(self.delScoreDB) findbutton = QPushButton("Find") findbutton.clicked.connect(self.findScoreDB) incbutton = QPushButton("Inc") incbutton.clicked.connect(self.incScoreDB) showbutton = QPushButton("Show") showbutton.clicked.connect(self.showScoreDB) keybuttonlabel = QLabel("Keys : ") agebutton = QPushButton("Age") agebutton.clicked.connect(self.SetKeyAsAge) scorebutton = QPushButton("Score") scorebutton.clicked.connect(self.SetKeyAsScore) namebutton = QPushButton("Name") namebutton.clicked.connect(self.SetKeyAsName) resultlable = QLabel("Result:") self.resultbox = QTextEdit() self.bar = QStatusBar() hbox1.addWidget(namelable) hbox1.addWidget(self.nameedit) hbox1.addWidget(agelable) hbox1.addWidget(self.ageedit) hbox1.addWidget(scorelable) hbox1.addWidget(self.scoreedit) hbox2.addStretch(1) hbox2.addWidget(amountlable) hbox2.addWidget(self.amountedit) hbox2.addWidget(keylable) hbox2.addWidget(self.selectedkey) hbox3.addStretch(1) hbox3.addWidget(funtionlabel) hbox3.addWidget(addbutton) hbox3.addWidget(delbutton) hbox3.addWidget(findbutton) hbox3.addWidget(incbutton) hbox3.addWidget(showbutton) hbox4.addStretch(1) hbox4.addWidget(keybuttonlabel) hbox4.addWidget(agebutton) hbox4.addWidget(scorebutton) hbox4.addWidget(namebutton) hbox5.addWidget(resultlable) hbox5.addStretch(1) hbox6.addWidget(self.resultbox) hbox7.addWidget(self.bar) vbox.addLayout(hbox1) vbox.addLayout(hbox2) vbox.addLayout(hbox3) vbox.addLayout(hbox4) vbox.addLayout(hbox5) vbox.addLayout(hbox6) vbox.addLayout(hbox7) self.setLayout(vbox) self.show() def closeEvent(self, event): self.writeScoreDB() def readScoreDB(self): try: fH = open(self.dbfilename, 'rb') except FileNotFoundError as e: self.scoredb = [] return try: self.scoredb = pickle.load(fH) except: pass else: pass fH.close() # write the data into person db def writeScoreDB(self): fH = open(self.dbfilename, 'wb') pickle.dump(self.scoredb, fH) fH.close() def showScoreDB(self): self.resultbox.setText("") for p in sorted(self.scoredb, key=lambda person: person[self.selectedkey.text()]): for attr in sorted(p): self.resultbox.insertPlainText(attr + "=" + str(p[attr]) + "\t") self.resultbox.append("") pass def addScoreDB(self): self.bar.showMessage('') try: record = { 'Name': self.nameedit.text(), 'Age': int(self.ageedit.text()), 'Score': int(self.scoreedit.text()) } except ValueError: self.bar.showMessage('Value Error') else: self.scoredb += [record] self.showScoreDB() def delScoreDB(self): try: co_scdb = self.scoredb[:] for l in range(len(self.scoredb)): for p in self.scoredb: if p['Name'] == self.nameedit.text(): self.scoredb.remove(p) if len(co_scdb) == len(self.scoredb): self.bar.showMessage('Name not found') except ValueError: self.bar.showMessage('Value Error') self.showScoreDB() def findScoreDB(self): try: findedDB = [] for i in self.scoredb: if i['Name'] == self.nameedit.text(): findedDB += [i] if len(findedDB) > 0: self.resultbox.setText("") for p in sorted( findedDB, key=lambda person: person[self.selectedkey.text()]): for attr in sorted(p): self.resultbox.insertPlainText(attr + "=" + str(p[attr]) + "\t") self.resultbox.append("") else: self.bar.showMessage('Name not found') except ValueError: self.bar.showMessage('Value Error') def incScoreDB(self): try: for i in self.scoredb: if i['Name'] == self.nameedit.text(): i['Score'] += int(self.amountedit.text()) self.showScoreDB() except ValueError: self.bar.showMessage('Value Error') def SetKeyAsAge(self): self.selectedkey.setText("Age") def SetKeyAsName(self): self.selectedkey.setText("Name") def SetKeyAsScore(self): self.selectedkey.setText("Score")
class ConfigParamEditWindow(QDialog): def __init__(self, parent, node, target_node_id, param_struct, update_callback): super(ConfigParamEditWindow, self).__init__(parent) self.setWindowTitle('Edit configuration parameter') self.setModal(True) self._node = node self._target_node_id = target_node_id self._param_struct = param_struct self._update_callback = update_callback min_val = get_union_value(param_struct.min_value) if 'uavcan.protocol.param.Empty' in str(min_val): min_val = None max_val = get_union_value(param_struct.max_value) if 'uavcan.protocol.param.Empty' in str(max_val): max_val = None value = get_union_value(param_struct.value) self._value_widget = None value_type = uavcan.get_active_union_field(param_struct.value) if value_type == 'integer_value': min_val = min_val if min_val is not None else -0x8000000000000000 max_val = max_val if max_val is not None else 0x7FFFFFFFFFFFFFFF if min_val >= -0x80000000 and \ max_val <= +0x7FFFFFFF: self._value_widget = QSpinBox(self) self._value_widget.setMaximum(max_val) self._value_widget.setMinimum(min_val) self._value_widget.setValue(value) if value_type == 'real_value': min_val = round_float(min_val) if min_val is not None else -3.4028235e+38 max_val = round_float(max_val) if max_val is not None else 3.4028235e+38 value = round_float(value) if value_type == 'boolean_value': self._value_widget = QCheckBox(self) self._value_widget.setChecked(bool(value)) if self._value_widget is None: self._value_widget = QLineEdit(self) self._value_widget.setText(str(value)) self._value_widget.setFont(get_monospace_font()) layout = QGridLayout(self) def add_const_field(label, *values): row = layout.rowCount() layout.addWidget(QLabel(label, self), row, 0) if len(values) == 1: layout.addWidget(FieldValueWidget(self, values[0]), row, 1) else: sub_layout = QHBoxLayout(self) for idx, v in enumerate(values): sub_layout.addWidget(FieldValueWidget(self, v)) layout.addLayout(sub_layout, row, 1) add_const_field('Name', param_struct.name) add_const_field('Type', uavcan.get_active_union_field(param_struct.value).replace('_value', '')) add_const_field('Min/Max', min_val, max_val) add_const_field('Default', render_union(param_struct.default_value)) layout.addWidget(QLabel('Value', self), layout.rowCount(), 0) layout.addWidget(self._value_widget, layout.rowCount() - 1, 1) fetch_button = make_icon_button('refresh', 'Read parameter from the node', self, text='Fetch', on_clicked=self._do_fetch) set_default_button = make_icon_button('fire-extinguisher', 'Restore default value', self, text='Restore', on_clicked=self._restore_default) send_button = make_icon_button('flash', 'Send parameter to the node', self, text='Send', on_clicked=self._do_send) cancel_button = make_icon_button('remove', 'Close this window; unsent changes will be lost', self, text='Cancel', on_clicked=self.close) controls_layout = QGridLayout(self) controls_layout.addWidget(fetch_button, 0, 0) controls_layout.addWidget(send_button, 0, 1) controls_layout.addWidget(set_default_button, 1, 0) controls_layout.addWidget(cancel_button, 1, 1) layout.addLayout(controls_layout, layout.rowCount(), 0, 1, 2) self._status_bar = QStatusBar(self) self._status_bar.setSizeGripEnabled(False) layout.addWidget(self._status_bar, layout.rowCount(), 0, 1, 2) left, top, right, bottom = layout.getContentsMargins() bottom = 0 layout.setContentsMargins(left, top, right, bottom) self.setLayout(layout) def show_message(self, text, *fmt): self._status_bar.showMessage(text % fmt) def _assign(self, value_union): value = get_union_value(value_union) if uavcan.get_active_union_field(value_union) == 'real_value': value = round_float(value) if hasattr(self._value_widget, 'setValue'): self._value_widget.setValue(value) self._update_callback(value) elif hasattr(self._value_widget, 'setChecked'): self._value_widget.setChecked(bool(value)) self._update_callback(bool(value)) else: self._value_widget.setText(str(value)) self._update_callback(value) def _on_response(self, e): if e is None: self.show_message('Request timed out') else: logger.info('Param get/set response: %s', e.response) self._assign(e.response.value) self.show_message('Response received') def _restore_default(self): self._assign(self._param_struct.default_value) def _do_fetch(self): try: request = uavcan.protocol.param.GetSet.Request(name=self._param_struct.name) self._node.request(request, self._target_node_id, self._on_response, priority=REQUEST_PRIORITY) except Exception as ex: show_error('Node error', 'Could not send param get request', ex, self) else: self.show_message('Fetch request sent') def _do_send(self): value_type = uavcan.get_active_union_field(self._param_struct.value) try: if value_type == 'integer_value': if hasattr(self._value_widget, 'value'): value = int(self._value_widget.value()) else: value = int(self._value_widget.text()) self._param_struct.value.integer_value = value elif value_type == 'real_value': value = float(self._value_widget.text()) self._param_struct.value.real_value = value elif value_type == 'boolean_value': value = bool(self._value_widget.isChecked()) self._param_struct.value.boolean_value = value elif value_type == 'string_value': value = self._value_widget.text() self._param_struct.value.string_value = value else: raise RuntimeError('This is not happening!') except Exception as ex: show_error('Format error', 'Could not parse value', ex, self) return try: request = uavcan.protocol.param.GetSet.Request(name=self._param_struct.name, value=self._param_struct.value) logger.info('Sending param set request: %s', request) self._node.request(request, self._target_node_id, self._on_response, priority=REQUEST_PRIORITY) except Exception as ex: show_error('Node error', 'Could not send param set request', ex, self) else: self.show_message('Set request sent')
class PlottingWidget(QtWidgets.QMainWindow): def __init__(self): super().__init__() # super(PrettyWidget, self).__init__() self.initUI() def initUI(self): self.setGeometry(600, 300, 1000, 600) self.center() self.setWindowTitle("Plot Trajectory") mainMenu = self.menuBar() fileMenu = mainMenu.addMenu("File") saveAction = QAction("Save as...") saveAction.setShortcut("Ctrl+S") saveAction.setStatusTip("Save plot to file") saveAction.setMenuRole(QAction.NoRole) saveAction.triggered.connect(self.file_save) fileMenu.addAction(saveAction) exitAction = QAction("&Exit", self) exitAction.setShortcut("Ctrl+Q") exitAction.setStatusTip("Exit Application") exitAction.setMenuRole(QAction.NoRole) exitAction.triggered.connect(self.close) fileMenu.addAction(exitAction) settingsMenu = mainMenu.addMenu("Settings") self.setStyleMenu = QMenu("Set Style", self) settingsMenu.addMenu(self.setStyleMenu) for style_name in [ "default", "fast", "ggplot", "grayscale", "seaborn" ]: styleAction = QAction(style_name, self, checkable=True) if style_name is CUR_STYLE: styleAction.setChecked(True) styleAction.triggered.connect(partial(self.set_style, style_name)) self.setStyleMenu.addAction(styleAction) self.setTimeWindowMenu = QMenu("Set Time Window", self) settingsMenu.addMenu(self.setTimeWindowMenu) for window_str in ["None", "s", "30s", "H", "D"]: windowAction = QAction(window_str, self, checkable=True) if window_str is TIME_WINDOW: windowAction.setChecked(True) windowAction.triggered.connect( partial(self.set_time_window, window_str)) self.setTimeWindowMenu.addAction(windowAction) # Grid Layout grid = QtWidgets.QGridLayout() widget = QtWidgets.QWidget(self) self.setCentralWidget(widget) widget.setLayout(grid) # Import CSV Button btn1 = QtWidgets.QPushButton("Import CSV", self) btn1.resize(btn1.sizeHint()) btn1.clicked.connect(self.getCSV) grid.addWidget(btn1, 1, 0) # Canvas and Toolbar self.figure = plt.figure(figsize=(15, 5)) self.canvas = FigureCanvas(self.figure) self.canvas.setContextMenuPolicy(Qt.CustomContextMenu) self.canvas.customContextMenuRequested.connect(self.popup) grid.addWidget(self.canvas, 2, 0, 1, 2) # DropDown mean / comboBox self.df = pd.DataFrame() self.columns = [] self.plot_list = [] self.comboBox = QtWidgets.QComboBox(self) self.comboBox.addItems(self.columns) grid.addWidget(self.comboBox, 0, 0) self.comboBox2 = QtWidgets.QComboBox(self) self.comboBox2.addItems(self.plot_list) grid.addWidget(self.comboBox2, 0, 1) # Plot Button btn2 = QtWidgets.QPushButton("Plot", self) btn2.resize(btn2.sizeHint()) btn2.clicked.connect(self.plot) grid.addWidget(btn2, 1, 1) # Progress bar self.progress = QProgressBar(self) # self.progress.setRange(0, 1) grid.addWidget(self.progress, 3, 0, 1, 2) self.statusBar = QStatusBar() self.setStatusBar(self.statusBar) self.show() def set_style(self, style_name: str): global CUR_STYLE self.statusBar.showMessage(f"Style set to {style_name}") actions = self.setStyleMenu.actions() CUR_STYLE = style_name for action in actions: if action.text() == CUR_STYLE: # print(f"✓ {CUR_STYLE}") action.setChecked(True) else: action.setChecked(False) print(f"Style set to {CUR_STYLE}") def popup(self, pos): menu = QMenu() saveAction = menu.addAction("Save...") action = menu.exec_(self.canvas.viewport().mapToGlobal(pos)) if action == saveAction: self.file_save() def file_save(self, target="figure"): name = QtGui.QFileDialog.getSaveFileName(self, "Save File") if target == "figure": self.figure.savefig(name) def update_progress_bar(self, i: int): self.progress.setValue(i) max = self.progress.maximum() self.statusBar.showMessage(f"Loading ... {100*i/max:.0f}%") def set_progress_bar_max(self, max: int): self.progress.setMaximum(max) def clear_progress_bar(self): self.progress.hide() self.statusBar.showMessage("Completed.") def getCSV(self): self.statusBar.showMessage("Loading CSV...") filepath, _ = QtWidgets.QFileDialog.getOpenFileName( self, "Open CSV", (QtCore.QDir.homePath()), "CSV (*.csv *.tsv)") if filepath != "": self.filepath = filepath self.loaderThread = QThread() self.loaderWorker = QtFileLoader(filepath) self.loaderWorker.moveToThread(self.loaderThread) self.loaderThread.started.connect(self.loaderWorker.read_in_chunks) self.loaderWorker.intReady.connect(self.update_progress_bar) self.loaderWorker.progressMaximum.connect( self.set_progress_bar_max) # self.loaderWorker.read_in_chunks.connect(self.df) self.loaderWorker.completed.connect(self.list_to_df) self.loaderWorker.completed.connect(self.clear_progress_bar) self.loaderThread.finished.connect(self.loaderThread.quit) self.loaderThread.start() @pyqtSlot(list) def list_to_df(self, dfs: list): df = pd.concat(dfs) self.df = df self.columns = self.df.columns.tolist() self.plot_list = [ "Actogram", "Polar Bar", "Polar Histogram", "Trajectory" ] self.comboBox.clear() self.comboBox.addItems(self.columns) self.comboBox2.clear() self.comboBox2.addItems(self.plot_list) self.statusBar.clearMessage() def mousePressEvent(self, QMouseEvent): if QMouseEvent.button() == Qt.RightButton: print("Right Button Clicked") def load_project_structure(self, startpath, tree): """ Load Project structure tree :param startpath: :param tree: :return: """ from PyQt5.QtWidgets import QTreeWidgetItem from PyQt5.QtGui import QIcon for element in os.listdir(startpath): path_info = startpath + "/" + element parent_itm = QTreeWidgetItem(tree, [os.path.basename(element)]) if os.path.isdir(path_info): self.load_project_structure(path_info, parent_itm) parent_itm.setIcon(0, QIcon("assets/folder.ico")) else: parent_itm.setIcon(0, QIcon("assets/file.ico")) def set_time_window(self, window: str): global TIME_WINDOW TIME_WINDOW = window self.statusBar.showMessage(f"Time window set to {window}") actions = self.setTimeWindowMenu.actions() for action in actions: if action.text() == TIME_WINDOW: action.setChecked(True) else: action.setChecked(False) print(f"Time window set to {window}") def plot(self): plt.clf() plot_kind = self.comboBox2.currentText() self.statusBar.showMessage(f"Plotting {plot_kind}") projection = ("polar" if plot_kind in ["Polar Bar", "Polar Histogram"] else "rectilinear") ax = self.figure.add_subplot(111, projection=projection) title = f"{basename(self.filepath)}" # TODO: Move mapping to separate method if plot_kind == "Actogram": displacement = traja.trajectory.calc_displacement(self.df) if TIME_WINDOW != "None": displacement = displacement.rolling(TIME_WINDOW).mean() # from pyqtgraph.Qt import QtGui, QtCore traja.plotting.plot_actogram(displacement, ax=ax, interactive=False) elif plot_kind == "Trajectory": traja.plotting.plot(self.df, ax=ax, interactive=False) elif plot_kind == "Quiver": traja.plotting.plot_quiver(self.df, ax=ax, interactive=False) elif plot_kind == "Polar Bar": traja.plotting.polar_bar(self.df, ax=ax, title=title, interactive=False) elif plot_kind == "Polar Histogram": traja.plotting.polar_bar(self.df, ax=ax, title=title, overlap=False, interactive=False) plt.tight_layout() self.canvas.draw() self.statusBar.clearMessage() def center(self): qr = self.frameGeometry() cp = QtWidgets.QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft())
def showMessage(self, message, timeout): if settings.SHOW_STATUS_NOTIFICATIONS: self._widgetStatus.hide() self._replaceWidget.setVisible(False) self.show() QStatusBar.showMessage(self, message, timeout)
class Dimili(QMainWindow): def baslat(self, anaPencere): anaPencere.resize(600, 400) anaPencere.setWindowTitle("Dimili-Türkçe Sözlük") anaPencere.setFixedSize(600,400) icon =QIcon() icon.addPixmap(QPixmap("Dictionary.png"),QIcon.Normal,QIcon.Off) anaPencere.setWindowIcon(icon) zemin=QWidget(anaPencere) zemin.setGeometry(QRect(0,30,600,390)) zemin.setStyleSheet("background-color:rgb(167, 196, 233);") self.araKutu = QLineEdit(anaPencere) self.araKutu.setGeometry(QRect(10, 80, 200, 20)) self.araKutu.textChanged.connect(self.benzerKelimeler) self.kelimeGir = QLabel("Kelimeler:",anaPencere) self.kelimeGir.setGeometry(QRect(10, 110, 141, 21)) self.kelimeGor = QLabel("Kelime Ara",anaPencere) self.kelimeGor.setGeometry(QRect(10, 30, 91, 16)) self.harfGrup=QButtonGroup(anaPencere) aharf=QPushButton("â",anaPencere) aharf.setGeometry(QRect(10,50,25,25)) eharf=QPushButton("é",anaPencere) eharf.setGeometry(QRect(30,50,25,25)) self.DilGrup=QButtonGroup(anaPencere) self.Dil1 = QPushButton("Zazaca-Türkçe",anaPencere) self.Dil1.setGeometry(QRect(230, 80, 91, 23)) self.Dil1.setCheckable(True) self.Dil1.setAutoExclusive(True) self.Dil1.setChecked(True) self.Dil1.setStyleSheet("background-color: rgb(102, 255, 0);") self.Dil2 = QPushButton("Türkçe-Zazaca",anaPencere) self.Dil2.setGeometry(QRect(330, 80, 91, 23)) self.Dil2.setCheckable(True) self.Dil2.setAutoExclusive(True) self.Dil2.setStyleSheet("background-color: rgb(255, 94, 105);") self.DilGrup.addButton(self.Dil1,1) self.DilGrup.addButton(self.Dil2,2) self.DilGrup.buttonClicked[int].connect(self.dilSecme) self.kelimeListesi=QListWidget(anaPencere) self.kelimeListesi.setGeometry(QRect(10, 130, 191, 231)) self.kelimeListesi.itemClicked.connect(self.kelimeAcikla) self.kelimeAnlam = QLabel("Kelimenin Anlamı:",anaPencere) self.kelimeAnlam.setGeometry(QRect(230, 110, 131, 21)) self.cumleList1 = QListWidget(anaPencere) self.cumleList1.setGeometry(QRect(230, 130, 351, 51)) self.ornekCumle1 = QLabel("Örnek Zazaca Cümle:",anaPencere) self.ornekCumle1.setGeometry(QRect(230, 200, 101, 21)) self.cumleList2 = QListWidget(anaPencere) self.cumleList2.setGeometry(QRect(230, 220, 351, 51)) self.ornekCumle2 = QLabel("Örnek Türkçe Cümle:",anaPencere) self.ornekCumle2.setGeometry(QRect(230, 290, 111, 16)) self.cumleList3 = QListWidget(anaPencere) self.cumleList3.setGeometry(QRect(230, 310, 351, 51)) self.anaMenu = QMenuBar(anaPencere) self.anaMenu.setGeometry(QRect(0, 0, 600, 21)) self.menuDosya = QMenu("Dosya",self.anaMenu) self.menuDuzenle = QMenu("Düzenle",self.anaMenu) self.menuYardim = QMenu("Yardım",self.anaMenu) anaPencere.setMenuBar(self.anaMenu) self.durum = QStatusBar(zemin) anaPencere.setStatusBar(self.durum) self.durum.setStyleSheet("background-color:white") self.durum.showMessage("Hazır") self.cikis= QAction(QIcon("Exit.ico"),"&Çıkış",anaPencere) self.cikis.setShortcut("Ctrl+X") self.cikis.triggered.connect(anaPencere.close) self.actionHakkinda = QAction("Hakkında",anaPencere) self.actionHakkinda.triggered.connect(self.hakkinda) self.actionSecenekler = QAction("Seçenekler",anaPencere) self.menuDosya.addAction(self.cikis) self.menuDuzenle.addAction(self.actionSecenekler) self.menuYardim.addAction(self.actionHakkinda) self.anaMenu.addAction(self.menuDosya.menuAction()) self.anaMenu.addAction(self.menuDuzenle.menuAction()) self.anaMenu.addAction(self.menuYardim.menuAction()) def kelimeAcikla(self): if self.DilGrup.checkedId()==1: self.cumleList1.clear() self.cumleList2.clear() self.cumleList3.clear() itemtext= [str(x.text()) for x in self.kelimeListesi.selectedItems()] for it in itemtext: itemtext=it self.im.execute("select Tur from DimTur where Zazaca=?",[itemtext]) turliste=[tur[0] for tur in self.im.fetchall()] for tura in turliste: turliste=tura self.im.execute("select Turkce from DimTur where Zazaca=?",[itemtext]) turkAnlam=[tur[0] for tur in self.im.fetchall()] for tr in turkAnlam: self.cumleList1.addItem(itemtext+"("+turliste+")"+" : "+tr) self.im.execute("select OrnekZazacaCumle from DimTur where Zazaca=?",[itemtext]) ornekZaza=[zaza[0] for zaza in self.im.fetchall()] for za in ornekZaza: ornekZaza=za self.cumleList2.addItem(ornekZaza) self.im.execute("select OrnekTurkceCumle from DimTur where Zazaca=?",[itemtext]) ornekTurk=[turk[0] for turk in self.im.fetchall()] for orn in ornekTurk: ornekTurk=orn self.cumleList3.addItem(ornekTurk) if self.DilGrup.checkedId()==2: self.cumleList1.clear() self.cumleList2.clear() self.cumleList3.clear() itemtext= [str(x.text()) for x in self.kelimeListesi.selectedItems()] for it in itemtext: itemtext=it self.im.execute("select Tur from DimTur where Turkce=?",[itemtext]) turliste=[tur[0] for tur in self.im.fetchall()] for tura in turliste: turliste=tura self.im.execute("select Zazaca from DimTur where Turkce=?",[itemtext]) zazaAnlam=[tur[0] for tur in self.im.fetchall()] for tr in zazaAnlam: self.cumleList1.addItem(itemtext+"("+turliste+")"+" : "+tr) self.im.execute("select OrnekZazacaCumle from DimTur where Turkce=?",[itemtext]) ornekTurk=[turk[0] for turk in self.im.fetchall()] for orn in ornekTurk: ornekTurk=orn self.cumleList2.addItem(ornekTurk) self.im.execute("select OrnekTurkceCumle from DimTur where Turkce=?",[itemtext]) ornekZaza=[zaza[0] for zaza in self.im.fetchall()] for za in ornekZaza: ornekZaza=za self.cumleList3.addItem(ornekZaza) def benzerKelimeler(self): if self.DilGrup.checkedId()==1: self.VT=sqlite3.connect("DimiliVT.sqlite") self.im=self.VT.cursor() self.kelimeListesi.clear() kelime=self.araKutu.text() if kelime=="" or kelime==None: self.kelimeListesi.clear() else: self.im.execute("select Zazaca from DimTur where Zazaca like ? order by Zazaca ",[kelime+'%']) zazaListe=[za[0] for za in self.im.fetchall()] for i in zazaListe: self.kelimeListesi.addItem(i) if self.DilGrup.checkedId()==2: self.VT=sqlite3.connect("DimiliVT.sqlite") self.im=self.VT.cursor() kelime=self.araKutu.text() self.kelimeListesi.clear() if kelime=="" or kelime==None: self.kelimeListesi.clear() else: self.im.execute("select Turkce from DimTur where Turkce like ? ",[kelime+'%']) turkListe=[tu[0] for tu in self.im.fetchall()] for i in turkListe: self.kelimeListesi.addItem(i) def dilSecme(self,ind): if ind==1: self.araKutu.setText("") self.kelimeListesi.clear() self.cumleList1.clear() self.cumleList2.clear() self.cumleList3.clear() self.Dil1.setStyleSheet("background:#66FF00") self.Dil2.setStyleSheet("background-color:#E41841") if ind==2: self.araKutu.setText("") self.kelimeListesi.clear() self.cumleList1.clear() self.cumleList2.clear() self.cumleList3.clear() self.Dil2.setStyleSheet("background:#66FF00") self.Dil1.setStyleSheet("background-color:#E41841") def hakkinda(self): QMessageBox.about(self, "Program Hakkında", "Bu program <b>bla bla</b> tarafından programlanmıştır. 2015")
class help_class(QWidget): def move_window(self): shape=QDesktopWidget().screenGeometry() w=shape.width() h=shape.height() win_w=self.frameGeometry().width() win_h=self.frameGeometry().height() x=w-win_w y=50 self.move(x,y) def help_show(self): self.show() self.move_window() def toggle_visible(self): if self.isVisible()==True: self.setVisible(False) else: self.setVisible(True) self.move_window() def init(self): QWidget.__init__(self) self.item_height=10 self.setWindowFlags(Qt.FramelessWindowHint|Qt.WindowStaysOnTopHint) #self.setFixedSize(400,160) self.setStyleSheet(" padding:0px; margin-top:0px; margin-bottom:0px") #; border:2px solid rgb(0, 0, 0); self.last=[] self.pos=-1 self.move_window() self.vbox = QVBoxLayout() #self.vbox.setAlignment(Qt.AlignTop) self.box=[] self.image=[] self.label=[] for i in range(0,5): l=QHBoxLayout() label=QLabel() label.setWordWrap(True) image=QLabel() image.setFixedWidth(48) self.box.append( QWidget()) self.image.append(image) label.setAlignment(Qt.AlignLeft | Qt.AlignTop) self.label.append(label) self.box[i].setLayout(l) #self.box[i].setFixedSize(380,80) #setMinimumSize(400, 500)# l.addWidget(self.image[i]) l.addWidget(self.label[i]) toolbar=QToolBar() toolbar.setIconSize(QSize(48, 48)) self.back = QAction(QIcon(os.path.join(get_image_file_path(),"left.png")), 'Back', self) self.back.triggered.connect(self.callback_back) toolbar.addAction(self.back) self.forward= QAction(QIcon(os.path.join(get_image_file_path(),"right.png")), 'Next', self) self.forward.triggered.connect(self.callback_forward) toolbar.addAction(self.forward) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) toolbar.addWidget(spacer) self.undo = QAction(QIcon(os.path.join(get_image_file_path(),"www.png")), 'Online help', self) self.undo.setStatusTip(_("On line help")) self.undo.triggered.connect(self.on_line_help) toolbar.addAction(self.undo) self.undo = QAction(QIcon(os.path.join(get_image_file_path(),"close.png")), 'Hide', self) self.undo.setStatusTip(_("Close")) self.undo.triggered.connect(self.callback_close) toolbar.addAction(self.undo) self.vbox.addWidget(toolbar) for i in range(0,5): self.vbox.addWidget(self.box[i]) self.vbox.addStretch() self.status_bar = QStatusBar() self.vbox.addWidget(self.status_bar) self.setLayout(self.vbox) self.show() def callback_close(self,widget): self.toggle_visible() def callback_forward(self,widget): self.pos=self.pos+1 if self.pos>=len(self.last): self.pos=len(self.last)-1 self.update() def callback_back(self,widget): self.pos=self.pos-1 if self.pos<0: self.pos=0 self.update() def on_line_help(self,widget): webbrowser.open('http://www.gpvdm.com/man/index.html') def update(self): items=int(len(self.last[self.pos])/2) for i in range(0,5): self.box[i].hide() for i in range(0,items): pixmap = QPixmap(os.path.join(get_image_file_path(),self.last[self.pos][i*2])) self.image[i].setPixmap(pixmap) text=self.last[self.pos][i*2+1]+"<br>" self.label[i].setText(text) height=(len(text)/80)*30 self.label[i].setFixedSize(380,height) self.box[i].show() #self.image[i].show() self.resize(300, items*self.item_height) self.forward.setEnabled(True) self.back.setEnabled(True) if self.pos==0: self.back.setEnabled(False) if self.pos==len(self.last)-1: self.forward.setEnabled(False) self.status_bar.showMessage(str(self.pos)+"/"+str(len(self.last)-1)) def help_set_help(self,array): add=True if len(self.last)!=0: if self.last[self.pos][1]==array[1]: add=False if add==True: self.pos=self.pos+1 self.last.append(array) self.update() self.move_window() def help_append(self,array): last_item=len(self.last)-1 self.last[last_item]=self.last[last_item] + array self.update() #self.resize(300, 150) self.move_window()
class MainWindow(QMainWindow): l = logging.getLogger('MainWindow') def __init__(self, app): QMainWindow.__init__(self, None) self.l.debug('Initializing MainWindow ...') self.setWindowTitle('MynPad') app.setWindowIcon(QIcon(':/icons/mynpad.png')) if os.name == 'nt': # On Windows, make sure to use a unique Application User Model Id, otherwise # Windows shows the default python icon in the taskbar # see http://stackoverflow.com/questions/1551605/how-to-set-applications-taskbar-icon-in-windows-7 myappid = 'afester.mynpad' import ctypes; ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid) self.theApplication = app app.aboutToQuit.connect(self.saveState) # read the local configuration file iniPath = 'mynpad.ini' if not os.path.exists(iniPath): iniPath = os.path.join(expanduser("~"), iniPath) self.settings = Settings(iniPath) self.settings.load() # Set up the menu bar menuBar = QMenuBar(self) exitAction = QAction("Exit", self, triggered=self.theApplication.exit) fileMenu = menuBar.addMenu("&File") fileMenu.addAction(exitAction) aboutAction = QAction("About ...", self, triggered = self.handleAbout) helpMenu = menuBar.addMenu("&Help") helpMenu.addAction(aboutAction) self.setMenuBar(menuBar) # Setup the status bar self.statusBar = QStatusBar() self.statusBar.showMessage("Ready.") self.setStatusBar(self.statusBar) self.mainWidget = CentralWidget(self, self.settings) self.mainWidget.updateWindowTitle.connect(self.updateWindowTitle) self.setCentralWidget(self.mainWidget) # Reset main window size and position pos = self.settings.getMainWindowPos() self.move(pos.x(), pos.y()) size = self.settings.getMainWindowSize() self.resize(size) # initialize the browser tree (add the top nodes and expand the saved path) self.mainWidget.browserWidget.initialize() def updateWindowTitle(self, title): self.setWindowTitle('{} - MynPad'.format(title)) def saveState(self): # Make sure that the current notepad page is saved self.mainWidget.editorWidget.save() # Note: there is no way to have eclipse shutdown the application faithfully, # see also http://stackoverflow.com/questions/677531/is-it-possible-for-eclipse-to-terminate-gently-instead-of-using-sigkill path = self.mainWidget.browserWidget.getCurrentPath() self.settings.setBrowserPath(path) self.settings.setMainWindowPos(self.pos()) self.settings.setMainWindowSize(self.size()) self.settings.save() # Close all notepads - TODO (HACK) for x in range (0, self.mainWidget.browserWidget.browserView.topLevelItemCount()): notepad = self.mainWidget.browserWidget.browserView.topLevelItem(x).getNotepad() notepad.close() def handleAbout(self): appVersion = "Development version" pythonVersion = "%s.%s.%s (%s)" % (sys.version_info[0], sys.version_info[1], sys.version_info[2], sys.version_info[3]) pyQtVersion = PYQT_VERSION_STR pyQtQtVersion = QT_VERSION_STR qtRuntimeVersion = qVersion() platformSystem = platform.system() platformRelease = platform.release() QMessageBox.about(self, "About MynPad", "Copyright \u00a9 2015 by Andreas Fester<br/>"+ "<table>"+ "<tr><th align=\"right\">Application version:</th><td>{}</td></tr>".format(appVersion) + "<tr><th align=\"right\">Python version:</th><td>{}</td></tr>".format(pythonVersion) + "<tr><th align=\"right\">PyQt version:</th><td>{} for Qt {}</td></tr>".format(pyQtVersion, pyQtQtVersion) + "<tr><th align=\"right\">Qt runtime version:</th><td>{}</td></tr>".format(qtRuntimeVersion)+ "<tr><th align=\"right\">Operating System:</th><td>{} {}</td></tr>".format(platformSystem, platformRelease)+ "<tr><th align=\"right\">sqlite version:</th><td>{}</td></tr>".format(sqlite3.version) + "<tr><th align=\"right\">sqlite runtime version:</th><td>{}</td></tr>".format(sqlite3.sqlite_version)+ "</table>")
class DatasFilterWindow(QMainWindow): manual_get_coor = pyqtSignal() def __init__(self): super(DatasFilterWindow, self).__init__() self.setObjectName('MainWindow') self.setStyleSheet(StyleTool.readQSS('./style_bright.qss')) self.setWindowTitle('数据筛选') self.resize(650, 600) self.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowCloseButtonHint) self.setFocus(Qt.MouseFocusReason) self.setup_ui() self.conn = sqlite3.connect('target_company.db') self.signal_slot() self.area = '' self.Id = None self.jobId = None # 标志 self.is_begined = False def setup_ui(self): # 创建布局 layout = QVBoxLayout() layout1 = QHBoxLayout() layout2 = QHBoxLayout() layout3 = QHBoxLayout() layout4 = QHBoxLayout() layout5 = QHBoxLayout() # 创建控件 company_name_tag = QLabel('公司名称') self.company_name = QLabel('') company_addr_tag = QLabel('公司地址') self.company_addr = QLabel('') company_scale_tag = QLabel('公司规模') self.company_scale = QLabel('') company_area_tag = QLabel('所处地区') self.company_area = QLabel('') job_name_tag = QLabel('职位名称') self.job_name = QLabel('') job_url = QLabel('职位链接') self.job_url = QLabel('') coordinate_tag = QLabel('经纬度') self.coordinate = QLineEdit() # QTextBrowser self.company_desc_browser = QTextBrowser() self.job_desc_browser = QTextBrowser() # QLineEdit self.note_ledit = QLineEdit() self.note_ledit.setPlaceholderText('备注') self.possible_ledit = QLineEdit() self.possible_ledit.setFixedWidth(132) self.possible_ledit.setPlaceholderText('可能性') self.keyword_edit = QLineEdit() self.keyword_edit.setFixedWidth(62) self.keyword_edit.setPlaceholderText('城市') # 按钮 self.save_btn = QPushButton('保存') self.save_btn.setContentsMargins(0, 0, 0, 0) self.begin_btn = QPushButton('开始') self.begin_btn.setContentsMargins(0, 0, 0, 0) self.del_btn = QPushButton('删除') self.del_btn.setContentsMargins(0, 0, 0, 0) self.view_final_result_btn = QPushButton('查看筛选结果') # 进度栏 self.process_bar = QProgressBar() self.process_bar.setFormat('%v/%m') # 状态栏 self.status = QStatusBar() self.setStatusBar(self.status) self.status.setStyleSheet('QStatusBar{color:red;}') # 布置布局 layout.addLayout(layout1) layout1.addWidget(job_name_tag) layout1.addWidget(self.job_name) layout1.addStretch(1) layout1.addWidget(self.keyword_edit) layout1.addWidget(self.begin_btn) layout1.addWidget(self.view_final_result_btn) layout.addLayout(layout2) layout2.addWidget(company_name_tag) layout2.addWidget(self.company_name) layout2.addStretch(1) layout2.addWidget(self.note_ledit, 1) layout.addLayout(layout3) layout3.addWidget(company_scale_tag) layout3.addWidget(self.company_scale) layout3.addStretch(1) layout3.addWidget(company_area_tag) layout3.addWidget(self.company_area) layout3.addStretch(3) layout3.addWidget(self.possible_ledit) layout.addLayout(layout4) layout4.addWidget(company_addr_tag) layout4.addWidget(self.company_addr) layout4.addStretch(1) layout4.addWidget(self.save_btn) layout4.addWidget(self.del_btn) layout.addLayout(layout5) layout5.addWidget(job_url) layout5.addWidget(self.job_url) layout5.addStretch(1) layout5.addWidget(coordinate_tag) layout5.addWidget(self.coordinate) layout.addWidget(self.company_desc_browser) layout.addWidget(self.job_desc_browser) layout.addWidget(self.process_bar) center_widget = QWidget() center_widget.setLayout(layout) self.setCentralWidget(center_widget) def signal_slot(self): self.save_btn.clicked.connect(self.save) self.del_btn.clicked.connect(self.delete) self.begin_btn.clicked.connect(self.begin) self.view_final_result_btn.clicked.connect(self.view_final_result) # self.begin_btn.setShortcut(_translate('MainWindow', 'Enter')) self.del_shortcut = QShortcut(QKeySequence('Ctrl+D'), self) self.del_shortcut.activated.connect(self.delete) self.begin_sc = QShortcut(QKeySequence('ctrl+b'), self) self.begin_sc.activated.connect(self.begin) self.quit_sc = QShortcut(QKeySequence('Meta+q'), self) self.quit_sc.activated.connect( lambda: sys.exit(QApplication(sys.argv).exec_())) self.save_sc = QShortcut(QKeySequence('ctrl+s'), self) self.save_sc.activated.connect(self.save) self.manual_get_coor.connect(self.manual_save_coor) def begin(self): c = self.conn.cursor() # 根据输入的城市 获取对应的城市数据 city = self.keyword_edit.text() if city: self.keyword_edit.clearFocus() sql = "select id from areas where area='{}';".format(city) print(sql) try: area_id = c.execute(sql).fetchone()[0] except IndexError: print('该城市数据不存在') except Exception as e: print(e) # 筛选出该区域的所有数据 else: sql = "select id, company_id, job_id from raw_datas where area_id='{}' and is_read=0 order by weight desc;".format( area_id) results = c.execute(sql).fetchall() total = len(results) self.status.showMessage('数据量:{}'.format(total), 10000) self.process_bar.setMaximum(total) # 主要效果 阻塞for循环 通过按钮解除阻塞 self.t = Thread(results) self.t.id_pipLine.connect(self.show_loop) self.t.valueChange.connect(self.process_bar.setValue) self.t.task_finished.connect(self.finished) self.t.start() self.area = city self.is_begined = True print('--') else: print('未输入城市') def show_loop(self, e): """循环显示""" self.Id = e[0] company_id = e[1] self.jobId = e[2] c = self.conn.cursor() sql = "select company_name, company_address, company_scale, company_desc from companies where id={};".format( company_id) self.company_info = c.execute(sql).fetchone() sql = "select job_name, job_desc, job_url from jobs where id={};".format( self.jobId) self.job_info = c.execute(sql).fetchone() # print(self.company_info, '\n', self.job_info, sep='') if self.company_info and self.job_info: self.job_name.setText(self.job_info[0].strip()) self.company_name.setText(self.company_info[0]) self.company_scale.setText(self.company_info[2]) self.company_area.setText(self.area) self.company_addr.setText(self.company_info[1]) self.company_desc_browser.setPlainText(self.company_info[-1]) self.job_desc_browser.setPlainText(self.job_info[1]) # todo:职位链接太长 # self.job_url.setText(self.job_info[2]) def save(self): """ 保存该组数据到新的数据表 并更新地图用数据 并显示下一条""" possible = self.possible_ledit.text() note = self.note_ledit.text() if possible: c = self.conn.cursor() # 获取公司地址的经纬度 addr = self.company_info[1] try: result = get_coordinate(addr) except requests.exceptions.ConnectTimeout: self.status.showMessage('获取坐标超时,请检查网络连接', 5000) return else: print('result', result) if not result: self.status.showMessage('抱歉无法获取该位置定位', 3000) self.manual_get_coor.emit() elif result['precise'] == 0: self.status.showMessage('该位置的坐标准确性未知', 3000) else: # 插入数据到map_datas sql = "insert into map_datas(locate_addr, lat, lng, precise) " \ "values('{}', {}, {}, {});".format(result['locate_addr'], result['lat'], result['lng'], result['precise']) c.execute(sql) # 获取刚刚插入数据的map_id sql = "select max(id) from map_datas;" max_map_id = c.execute(sql).fetchone()[0] # 插入数据到final_datas sql = "insert into final_datas(possible, note, raw_id, map_id) values('{}','{}',{}, {});".format( possible, note, self.Id, max_map_id) c.execute(sql) # 更新raw_datas的is_read值 表示已经筛选过,下次不再显示 sql = "update raw_datas set is_read=1 where id={};".format(self.Id) c.execute(sql) self.conn.commit() # 清除输入控件当前的数据 self.note_ledit.clear() self.possible_ledit.clear() self.coordinate.clear() self.possible_ledit.clearFocus() # 检测当前城市是否还有未筛选的数据组 if self.is_begined and self.process_bar.value( ) < self.process_bar.maximum(): self.t.next() else: print('没有next了') else: # 提醒没有填写可能性 self.status.showMessage('没填可能性', 3000) def delete(self): """删除该组数据 并显示下一条""" c = self.conn.cursor() sql = "delete from raw_datas where id={};".format(self.Id) try: c.execute(sql) except sqlite3.OperationalError: self.status.showMessage('当前没有数据', 3000) return sql = "delete from jobs where id={};".format(self.jobId) c.execute(sql) self.conn.commit() self.note_ledit.clear() self.possible_ledit.clear() if self.is_begined and self.process_bar.value( ) < self.process_bar.maximum(): self.t.next() else: print('没有next了') def finished(self): self.status.showMessage('任务结束', 5000) self.job_name.clear() self.company_name.clear() self.company_scale.clear() self.company_addr.clear() self.company_area.clear() self.note_ledit.clear() self.possible_ledit.clear() self.company_desc_browser.clear() self.job_desc_browser.clear() def get_position(self, addr): """ 百度坐标系获取 :param addr: :return: """ ak = 'ysZHXY6AwYQYcXLuhTCkV2a1YvOk5Dm2' url = 'http://api.map.baidu.com/geocoding/v3/?address={}&output=json&ak={}'.format( addr, ak) return requests.get(url=url).json() def manual_save_coor(self): result = self.coordinate.text() if result: c = self.conn.cursor() # 插入数据到map_datas result = result.split(',') sql = "insert into map_datas(lat, lng) " \ "values('{}', {});".format(float(result[0].strip()), float(result[1].strip())) c.execute(sql) self.conn.commit() self.status.showMessage('已手动定位', 3000) else: return def view_final_result(self): # 使用poltly制图 对应的数据格式整理 save_plotly_map(get_plotly_datas())
class MainWindow_Ui(QMainWindow): def __init__(self): super().__init__() #MainWindow self.resize(600, 400) self.setMinimumSize(QSize(600, 400)) self.setMaximumSize(QSize(16777215, 16777215)) self.setWindowTitle("Persepolis Download Manager") self.setWindowIcon(QIcon('icon')) self.centralwidget = QWidget(self) self.verticalLayout = QVBoxLayout(self.centralwidget) #enable drag and drop self.setAcceptDrops(True) #frame self.frame = QFrame(self.centralwidget) self.frame.setGeometry(QRect(10, 10, 581, 251)) self.frame.setFrameShape(QFrame.StyledPanel) self.frame.setFrameShadow(QFrame.Raised) self.gridLayout = QGridLayout(self.frame) #tablewidget self.download_table = QTableWidget(self.frame) self.download_table.setGeometry(QRect(10, 10, 560, 231)) self.download_table.setSizeIncrement(QSize(0, 0)) self.download_table.setColumnCount(10) self.download_table.setSelectionBehavior(QAbstractItemView.SelectRows) self.download_table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.download_table.verticalHeader().hide() self.download_table.setColumnHidden(8 , True) self.download_table.setColumnHidden(9 , True) self.gridLayout.addWidget(self.download_table, 0, 0, 1, 1) self.verticalLayout.addWidget(self.frame) self.setCentralWidget(self.centralwidget) download_table_header = ['File Name' , 'Status' , 'Size' , 'Downloaded' , 'Percentage' , 'Connections' , 'Transfer rate' , 'Estimate time left' , 'Gid' , 'Info'] self.download_table.setHorizontalHeaderLabels(download_table_header) #fixing the size of download_table when window is Maximized! self.download_table.horizontalHeader().setSectionResizeMode(0) self.download_table.horizontalHeader().setStretchLastSection(True) #finding number od row that user selected! self.download_table.itemSelectionChanged.connect(self.selectedRow) #menubar self.menubar = QMenuBar(self) self.menubar.setGeometry(QRect(0, 0, 600, 24)) self.setMenuBar(self.menubar) fileMenu = self.menubar.addMenu('File') editMenu = self.menubar.addMenu('Edit') viewMenu = self.menubar.addMenu('View') downloadMenu = self.menubar.addMenu('Download') helpMenu = self.menubar.addMenu('Help') #statusbar self.statusbar = QStatusBar(self) self.setStatusBar(self.statusbar) self.statusbar.showMessage("Persepolis Download Manager") #toolBar self.toolBar = QToolBar(self) self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) self.toolBar.setWindowTitle("toolBar") self.toolBar.setIconSize(QSize(38 , 38)) self.toolBar.setFloatable(False) self.toolBar.setMovable(False) #toolBar and menubar and actions self.stopAllAction = QAction(QIcon(icons + 'stop_all') , 'Stop all active downloads' , self , statusTip = 'Stop all active downloads', triggered = self.stopAllDownloads ) downloadMenu.addAction(self.stopAllAction) self.pauseAllAction = QAction(QIcon(icons + 'pause_all') , 'Pause all active downloads' , self , statusTip = 'Pause all active downloads', triggered = self.pauseAllDownloads ) downloadMenu.addAction(self.pauseAllAction) self.minimizeAction = QAction(QIcon(icons + 'minimize') , 'Minimize to system tray' , self , shortcut = "Ctrl+W" , statusTip = "Minimize to system tray" , triggered = self.minMaxTray) viewMenu.addAction(self.minimizeAction) self.addlinkAction = QAction(QIcon(icons + 'add') , 'Add New Download Link' , self , shortcut = "Ctrl+N" , statusTip = "Add New Download Link" , triggered = self.addLinkButtonPressed) fileMenu.addAction(self.addlinkAction) self.resumeAction = QAction(QIcon(icons + 'play') , 'Resume Download' , self , shortcut = "Ctrl+R" , statusTip = "Resume Download" , triggered = self.resumeButtonPressed) downloadMenu.addAction(self.resumeAction) self.pauseAction = QAction(QIcon(icons + 'pause') , 'Pause Download' , self , shortcut = "Ctrl+C" , statusTip = "Pause Download" , triggered = self.pauseButtonPressed) downloadMenu.addAction(self.pauseAction) self.stopAction = QAction(QIcon(icons + 'stop') , 'Stop Download' , self , shortcut = "Ctrl+S" , statusTip = "Stop/Cancel Download" , triggered = self.stopButtonPressed) downloadMenu.addAction(self.stopAction) self.removeAction = QAction(QIcon(icons + 'trash') , 'Remove Download' , self , shortcut = "Ctrl+D" , statusTip = "Remove Download" , triggered = self.removeButtonPressed) downloadMenu.addAction(self.removeAction) self.propertiesAction = QAction(QIcon(icons + 'setting') , 'Properties' , self , shortcut = "Ctrl+P" , statusTip = "Properties" , triggered = self.propertiesButtonPressed ) downloadMenu.addAction(self.propertiesAction) self.progressAction = QAction(QIcon(icons + 'window') , 'Progress' , self , shortcut = "Ctrl+Z" , statusTip = "Progress" , triggered = self.progressButtonPressed ) downloadMenu.addAction(self.progressAction) self.exitAction = QAction(QIcon(icons + 'exit') , 'Exit' , self , shortcut = "Ctrl+Q" , statusTip = "Exit" , triggered = self.close) fileMenu.addAction(self.exitAction) self.preferencesAction = QAction(QIcon(icons + 'preferences') , 'Preferences' , self , statusTip = 'Preferences' , triggered = self.openPreferences) editMenu.addAction(self.preferencesAction) self.aboutAction = QAction(QIcon(icons + 'about') , 'About' , self , statusTip = 'About' , triggered = self.openAbout) helpMenu.addAction(self.aboutAction) for i in self.addlinkAction,self.resumeAction, self.pauseAction , self.stopAction, self.removeAction , self.propertiesAction, self.progressAction , self.exitAction : self.toolBar.addAction(i) self.toolBar.insertSeparator(self.addlinkAction) self.toolBar.insertSeparator(self.resumeAction) self.toolBar.insertSeparator(self.removeAction) self.toolBar.insertSeparator(self.exitAction) self.toolBar.addSeparator()
class ConfigParamEditWindow(QDialog): def __init__(self, parent, node, target_node_id, param_struct, update_callback): super(ConfigParamEditWindow, self).__init__(parent) self.setWindowTitle("Edit configuration parameter") self.setModal(True) self._node = node self._target_node_id = target_node_id self._param_struct = param_struct self._update_callback = update_callback min_val = get_union_value(param_struct.min_value) if "uavcan.protocol.param.Empty" in str(min_val): min_val = None max_val = get_union_value(param_struct.max_value) if "uavcan.protocol.param.Empty" in str(max_val): max_val = None value = get_union_value(param_struct.value) self._value_widget = None value_type = uavcan.get_active_union_field(param_struct.value) if value_type == "integer_value": min_val = min_val if min_val is not None else -0x8000000000000000 max_val = max_val if max_val is not None else 0x7FFFFFFFFFFFFFFF if min_val >= -0x80000000 and max_val <= +0x7FFFFFFF: self._value_widget = QSpinBox(self) self._value_widget.setMaximum(max_val) self._value_widget.setMinimum(min_val) self._value_widget.setValue(value) if value_type == "real_value": min_val = round_float(min_val) if min_val is not None else -3.4028235e38 max_val = round_float(max_val) if max_val is not None else 3.4028235e38 value = round_float(value) if value_type == "boolean_value": self._value_widget = QCheckBox(self) self._value_widget.setChecked(bool(value)) if self._value_widget is None: self._value_widget = QLineEdit(self) self._value_widget.setText(str(value)) self._value_widget.setFont(get_monospace_font()) layout = QGridLayout(self) def add_const_field(label, *values): row = layout.rowCount() layout.addWidget(QLabel(label, self), row, 0) if len(values) == 1: layout.addWidget(FieldValueWidget(self, values[0]), row, 1) else: sub_layout = QHBoxLayout(self) for idx, v in enumerate(values): sub_layout.addWidget(FieldValueWidget(self, v)) layout.addLayout(sub_layout, row, 1) add_const_field("Name", param_struct.name) add_const_field("Type", uavcan.get_active_union_field(param_struct.value).replace("_value", "")) add_const_field("Min/Max", min_val, max_val) add_const_field("Default", render_union(param_struct.default_value)) layout.addWidget(QLabel("Value", self), layout.rowCount(), 0) layout.addWidget(self._value_widget, layout.rowCount() - 1, 1) fetch_button = make_icon_button( "refresh", "Read parameter from the node", self, text="Fetch", on_clicked=self._do_fetch ) set_default_button = make_icon_button( "fire-extinguisher", "Restore default value", self, text="Restore", on_clicked=self._restore_default ) send_button = make_icon_button( "flash", "Send parameter to the node", self, text="Send", on_clicked=self._do_send ) cancel_button = make_icon_button( "remove", "Close this window; unsent changes will be lost", self, text="Cancel", on_clicked=self.close ) controls_layout = QGridLayout(self) controls_layout.addWidget(fetch_button, 0, 0) controls_layout.addWidget(send_button, 0, 1) controls_layout.addWidget(set_default_button, 1, 0) controls_layout.addWidget(cancel_button, 1, 1) layout.addLayout(controls_layout, layout.rowCount(), 0, 1, 2) self._status_bar = QStatusBar(self) self._status_bar.setSizeGripEnabled(False) layout.addWidget(self._status_bar, layout.rowCount(), 0, 1, 2) left, top, right, bottom = layout.getContentsMargins() bottom = 0 layout.setContentsMargins(left, top, right, bottom) self.setLayout(layout) def show_message(self, text, *fmt): self._status_bar.showMessage(text % fmt) def _assign(self, value_union): value = get_union_value(value_union) if uavcan.get_active_union_field(value_union) == "real_value": value = round_float(value) if hasattr(self._value_widget, "setValue"): self._value_widget.setValue(value) self._update_callback(value) elif hasattr(self._value_widget, "setChecked"): self._value_widget.setChecked(bool(value)) self._update_callback(bool(value)) else: self._value_widget.setText(str(value)) self._update_callback(value) def _on_response(self, e): if e is None: self.show_message("Request timed out") else: logger.info("Param get/set response: %s", e.response) self._assign(e.response.value) self.show_message("Response received") def _restore_default(self): self._assign(self._param_struct.default_value) def _do_fetch(self): try: request = uavcan.protocol.param.GetSet.Request(name=self._param_struct.name) self._node.request(request, self._target_node_id, self._on_response, priority=REQUEST_PRIORITY) except Exception as ex: show_error("Node error", "Could not send param get request", ex, self) else: self.show_message("Fetch request sent") def _do_send(self): value_type = uavcan.get_active_union_field(self._param_struct.value) try: if value_type == "integer_value": if hasattr(self._value_widget, "value"): value = int(self._value_widget.value()) else: value = int(self._value_widget.text()) self._param_struct.value.integer_value = value elif value_type == "real_value": value = float(self._value_widget.text()) self._param_struct.value.real_value = value elif value_type == "boolean_value": value = bool(self._value_widget.isChecked()) self._param_struct.value.boolean_value = value elif value_type == "string_value": value = self._value_widget.text() self._param_struct.value.string_value = value else: raise RuntimeError("This is not happening!") except Exception as ex: show_error("Format error", "Could not parse value", ex, self) return try: request = uavcan.protocol.param.GetSet.Request(name=self._param_struct.name, value=self._param_struct.value) logger.info("Sending param set request: %s", request) self._node.request(request, self._target_node_id, self._on_response, priority=REQUEST_PRIORITY) except Exception as ex: show_error("Node error", "Could not send param set request", ex, self) else: self.show_message("Set request sent")
class MainWindow(QMainWindow): """ 主窗口界面 """ def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) # 初始化 self.init() # ui设计 self.setup_ui() # 创建右键菜单 self.create_context_menu() # 主框体设计 self.set_main_form() # 加载qss样式 self.load_qss() def init(self): self.setGeometry(Const.WIN_X, Const.WIN_Y, Const.WIN_WIDTH, Const.WIN_HEIGHT) self.setObjectName('mainWindow') self.setWindowIcon(QIcon("./image/Logo/logo.png")) self.setWindowTitle('IFR智能公式识别系统') # 加载图片缩放公共类 self.imageScale = ImageScale() def setup_ui(self): """ 创建状态栏、菜单栏、工具栏 """ # 状态栏 self.statusBar = QStatusBar() self.setStatusBar(self.statusBar) self.statusBar.showMessage('准备就绪', 5000) # self.statusBar().setStyleSheet('background-color:lightGray;') # 菜单栏 self.menubar = QMenuBar() self.setMenuBar(self.menubar) # self.menuBar().setStyleSheet('background-color:lightGray;') # 文件 self.fileMenu = self.menubar.addMenu('&文件(F)') # 调用自定义action self.openPimax = Action.action_b_2(self, 'openPimax', '&打开图片文件', 'Ctrl+P', '打开图片文件') self.openPimax.setIcon(QIcon('./image/openQpixmap.jpg')) self.openText = Action.action_b_2(self, 'openText', '&打开文本文件', 'Ctrl+T', '打开文本文件') self.openText.setIcon(QIcon('./image/openText.ico')) self.openFile = Action.action_b_3(self, 'openFile', '打开文件', '打开文件', self.fileMenu) self.openFile.addAction(self.openPimax) self.openFile.addAction(self.openText) self.openPimax.triggered.connect(lambda: self.get_image()) self.openText.triggered.connect(lambda: self.get_text()) self.openRecentFile = Action.action_a_2(self, 'openRecentFile', '&最近打开的文件', 'Ctrl+O', '最近打开的文件', self.fileMenu) # self.openRecentFile.triggered.connect(self.) self.save = Action.action_a_2(self, 'save', '&保存分析结果', 'Ctrl+S', '保存数据分析结果', self.fileMenu) # self.save.triggered.connect(self.) self.saveAs = Action.action_a_2(self, 'saveAs', '&另保存分析结果', 'Ctrl+Shift+S', '另保存数据分析结果', self.fileMenu) # self.saveAs.triggered.connect(self.) self.printf = Action.action_a_2(self, 'printef', '&打印分析结果', 'Ctrl+P', '打印数据分析结果', self.fileMenu) # self.printf.triggered.connect(self.) self.exitAction = Action.action_a_1(self, 'exitAction', './image/mainWindowIcon/toolBarIcon/exit.png', '&退出', 'Ctrl+Q', '退出应用程序', self.fileMenu) self.exitAction.triggered.connect(self.close) # 编辑 self.exitMenu = self.menubar.addMenu('&编辑(E)') # # ####################查找与替换####################开始 self.search = Action.action_b_2(self, 'search', '&快速查找', 'Ctrl+F', '快速查找') self.replace = Action.action_b_2(self, 'replace', '&快速替换', 'Ctrl+H', '快速替换') # 新增二级菜单 self.searchAndReplaceMenu = Action.action_b_3(self, 'searchAndReplaceMenu', '查找与替换', '查找与替换', self.exitMenu) self.searchAndReplaceMenu.addAction(self.search) self.searchAndReplaceMenu.addAction(self.replace) # self.search.triggered.connect(self.) # self.replace.triggered.connect(self.) # ####################查找与替换####################结束 self.cut = Action.action_a_2(self, 'cut', '&剪切', 'Ctrl+X', '剪切', self.exitMenu) # self.cut.triggered.connect(self.) self.copy = Action.action_a_2(self, 'copy', '&复制', 'Ctrl+C', '复制', self.exitMenu) # self.copy.triggered.connect(self.) self.paste = Action.action_a_2(self, 'paste', '&粘贴', 'Ctrl+V', '粘贴', self.exitMenu) # self.paste.triggered.connect(self.) self.delete = Action.action_a_2(self, 'delect', '&删除', 'Del', '删除', self.exitMenu) # self.delect.triggered.connect(self.) self.selectAll = Action.action_a_2(self, 'selectAll', '&全选', 'Ctrl+Alt', '全选', self.exitMenu) # self.selectAll.triggered.connect(self.) # 视图 self.viewMenu = self.menubar.addMenu('&视图(V)') self.notice = Action.action_a_2(self, 'notice', '&通知', 'Ctrl+Alt+X', '信息通知提醒', self.viewMenu) # self.notice.triggered.connect(self.) # ####################窗口管理####################开始 self.window = Action.action_b_3(self, 'window', '&窗口', '展示一些基本窗口', self.viewMenu) # ####################窗口管理####################结束 # # # # ####################工具栏####################开始 self.tool = Action.action_b_3(self, 'tool', '&工具栏', '基本工具', self.viewMenu) self.calculator = Action.action_a_1(self, 'calculator', './image/calculator.jpg', '&计算器', 'C', '计算器', self.viewMenu) self.calculator.triggered.connect(lambda: self.calculator_win()) # ####################工具####################结束 self.fullScreen = Action.action_a_2(self, 'fullScreen', '&全屏幕', 'Shift+Alt+Enter', '全屏', self.viewMenu) # self.fullScreen.triggered.connect(self.) self.propertyWindow = Action.action_a_2(self, 'propertyWindow', '&属性窗口', 'F4', '属性窗口', self.viewMenu) # self.propertyWindow.triggered.connect(self.) # # 分析 self.navigateMenu = self.menubar.addMenu('&分析(N)') # # 工具 self.toolMenu = self.menubar.addMenu('&工具(T)') # # 扩展 self.extendMenu = self.menubar.addMenu('&扩展(X)') # # 窗口 self.windowMenu = self.menubar.addMenu('&窗口(W)') # # 帮助 self.helpMenu = self.menubar.addMenu('&帮助(H)') self.help = Action.action_a_2(self, 'help ', '&查看帮助', 'Ctrl+F1', '查看帮助', self.helpMenu) # self.help.triggered.connect(self.) # ####################菜单####################结束 ################################################################################################################ # ####################工具栏####################开始 # 工具 self.pixmapToolbar = self.addToolBar('打开图形文件') self.textToolbar = self.addToolBar('打开文本文件') self.pixmapToolbar.addAction(self.openPimax) self.textToolbar.addAction(self.openText) self.exitToolbar = self.addToolBar('退出') self.exitToolbar.addAction(self.exitAction) self.calculatorTooolbar = self.addToolBar('计算器') self.calculatorTooolbar.addAction(self.calculator) # ####################工具栏####################结束 # 槽函数线程 # 创建右键菜单 def create_context_menu(self): """ 创建右键菜单 :return: """ self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.show_context_menu) # 创建QMenu self.contextMenu = QMenu(self) # ####################工具栏管理####################开始 self.toolBarManagementMenu = Action.action_b_4(self, 'toolBarManagementMenu', '&工具栏管理', self.contextMenu) # 未完成 # ####################工具栏管理####################结束 self.minAtion = Action.action_a_1(self, 'minAction', './image/min.png', '&最小化', 'Ctrl+M', '最小化窗口', self.contextMenu) self.contextMenu.addSeparator() # 添加分隔线 self.cutAction = Action.action_a_2(self, 'cutAction', '&剪切', 'Ctrl+X', '剪切', self.contextMenu) self.copyAction = Action.action_a_2(self, 'copyAction', '&复制', 'Ctrl+C', '复制', self.contextMenu) self.pasteAction = Action.action_a_2(self, 'pasteAction', '&粘贴', 'Ctrl+V', '粘贴', self.contextMenu) self.deleteAction = Action.action_a_2(self, 'delectAction', '&删除', 'Del', '删除', self.contextMenu) self.selectAllAction = Action.action_a_2(self, 'selectAllAction', '&全选', 'Ctrl+Alt', '全选', self.contextMenu) self.contextMenu.addSeparator() # 添加分隔线 self.closeAction = Action.action_a_1(self, 'closeAction', './image/Exit.png', '&退出', 'Ctrl+W', '退出', self.contextMenu) self.minAtion.triggered.connect(self.show_mininized_window) self.closeAction.triggered.connect(self.quit_window) # self.selectAllAction.triggered.connect(self.) # self.cutAction.triggered.connect(self.) # self.copyAction.triggered.connect(self.) # self.pasteAction.triggered.connect(self.) # self.delectAction.triggered.connect(self.) # ****************************** 业务逻辑 ********************************* def load_qss(self): """ 加载Qss样式表 :return: """ style_file = './Window/mainWindow/Qss/mainWindow.qss' qss_style = CommonhelperQss.read_qss(style_file) self.setStyleSheet(qss_style) def set_action_connect(self): """ 菜单栏、工具栏槽函数连接 :return: """ pass def calculator_win(self): """ 加载计算器窗口 :return: """ self.calculator_Win = Calculatormainwindow() self.calculator_Win.show() def set_main_form(self): """ 窗体布局以及主框体设计 :return: """ # 主框体 self.mainSpiltter = QSplitter(Qt.Vertical) self.mainSpiltter.setObjectName('mainSpiltter') self.mainSpiltterLayout = QVBoxLayout() # 设置主窗口中心窗体 self.setCentralWidget(self.mainSpiltter) # *******工作区间******* self.workWidget = QSplitter() self.workWidget.setObjectName('workWidget') self.mainSpiltter.addWidget(self.workWidget) self.workWidgetLayout = QHBoxLayout() self.workWidget.setLayout(self.workWidgetLayout) self.leftWidget = QFrame() self.leftWidget.setObjectName('leftWidget') self.leftWidget.setFrameShape(QFrame.StyledPanel) self.leftWidget.setMaximumWidth(230) self.leftWidgetLayout = QVBoxLayout() self.leftWidgetLayout.setContentsMargins(0, 0, 0, 0) self.leftWidget.setLayout(self.leftWidgetLayout) # self.hideBtn = QLabel() # self.hideBtn.setObjectName('hideBtn') # self.hideBtn.setPixmap(QPixmap('./image/mainWindowIcon/showAndHideIcon/hide0.ico')) # # self.showBtn = QLabel() # self.showBtn.setObjectName('showBtn') # self.showBtn.setPixmap(QPixmap('./image/mainWindowIcon/showAndHideIcon/show0.ico')) # 存放按钮 self.widget = QWidget() self.widget.setObjectName('widget') self.leftWidgetLayout.addWidget(self.widget) pixmap = self.imageScale.pixmap_scale('./image/Logo/logo0.png', 204, 80) self.logoIamgeLabel = QLabel(self.widget) self.logoIamgeLabel.setObjectName('logoImageLabel') self.logoIamgeLabel.setPixmap(pixmap) self.widgetLayout = QGridLayout() self.widget.setLayout(self.widgetLayout) self.widgetLayout.addWidget(self.logoIamgeLabel, 0, 1) # 多界面 # QListWidget + QStackedWidget实现 self.leftListWidget = QListWidget() # 左侧选项列表 self.leftListWidget.setObjectName('leftListWidget') self.rightWidget = QStackedWidget() # 右侧框体 self.rightWidget.setObjectName('rightWidget') self.leftWidgetLayout.addWidget(self.leftListWidget) self.workWidgetLayout.addWidget(self.leftWidget) self.workWidgetLayout.addWidget(self.rightWidget) # ********左侧选项列表布局以及设置****************************** # 设置左侧选项列表大小 self.leftListWidget.setMinimumWidth(Const.LEFTWIDGET_WIDTH) # 左侧选项列表与右侧框体的index对应绑定 self.leftListWidget.currentRowChanged.connect(self.rightWidget.setCurrentIndex) # 去掉边框 self.leftListWidget.setFrameShape(QListWidget.NoFrame) # 隐藏滚动条 self.leftListWidget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.leftListWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) list_str = ['智能识别', '公式生成器', '学习资源区', '设置', '关于'] # 左侧选项添加 for i in range(5): self.item = QListWidgetItem(list_str[i], self.leftListWidget) self.item.setSizeHint(QSize(Const.ITEM_WIDTH, Const.ITEM_HEIGHT)) # 居中显示 self.item.setTextAlignment(Qt.AlignCenter) # 设置默认选中item[1] self.leftListWidget.setCurrentRow(0) # ********右侧主框体布局以及设置********************************** self.rightForm1 = RightForm1() self.rightForm2 = RightForm2() self.rightForm3 = RightForm3() self.rightForm4 = RightForm4() self.rightForm5 = RightForm5() self.rightWidget.addWidget(self.rightForm1) self.rightWidget.addWidget(self.rightForm2) self.rightWidget.addWidget(self.rightForm3) self.rightWidget.addWidget(self.rightForm4) self.rightWidget.addWidget(self.rightForm5) # ############################################################# # 消息通知框 self.messageInform = MesageFrame() self.messageInform.setObjectName('messageInform') # 消息通知框默认隐藏 self.messageInform.hide() self.mainSpiltter.addWidget(self.messageInform) # *****侧边栏***** # 右侧边栏 self.rightBar = QFrame() self.rightBar.setObjectName('rightBar') self.rightBar.setFixedWidth(35) self.rightBar.setFrameShape(QFrame.StyledPanel) self.rightBarLayout = QVBoxLayout() self.rightBar.setLayout(self.rightBarLayout) self.workWidgetLayout.addWidget(self.rightBar) # 右侧边栏控件 # 右侧边栏添加控件 # 下侧边栏 self.bottomBar = QFrame() self.bottomBar.setObjectName('bottomBar') self.bottomBar.setMaximumHeight(35) self.bottomBar.setFrameShape(QFrame.StyledPanel) self.bottomBarLayout = QHBoxLayout() self.bottomBarLayout.setAlignment(Qt.AlignRight) # 右对齐 self.bottomBar.setLayout(self.bottomBarLayout) self.mainSpiltter.addWidget(self.bottomBar) # 下侧边栏控件 # 留白控件 blank = QLabel(self.bottomBar) blank.setObjectName('blank') self.informText = QLabel(self.bottomBar) self.informText.setObjectName('informText') self.informText.setText('通知') self.informBtn = QPushButton(self.bottomBar) self.informBtn.setObjectName('informBtn') self.informBtn.resize(QSize(35, 35)) self.informBtn.setIcon(QIcon('./image/mainWindowIcon/messageBarBtnIcon/inform0.png')) self.informBtn.clicked.connect(lambda: self.open_inform_frame()) # 下侧边栏添加控件 self.bottomBarLayout.addWidget(self.informBtn) self.bottomBarLayout.addWidget(self.informText) self.bottomBarLayout.addWidget(blank) # ****************************业务逻辑****************************** # 右键菜单 def show_context_menu(self): """ 右键点击时调用的函数 :return: """ # 显示菜单前,将它移动到鼠标点击的位置 self.contextMenu.exec_(QCursor.pos()) # 最小化窗口 def show_mininized_window(self): """ :return: """ self.showMinimized() # 最大化窗口 def show_maximized_window(self): """ :return: """ self.showMaximized() # 复原窗口 def show_restore_window(self): """ :return: """ if self.isMaximized(): self.showNormal() else: self.showMaximized() # 关闭窗口 def quit_window(self): """ :return: """ self.close() # 打开文件 def get_image(self): """ getOpenFileName():返回用户所选择文件的名称,并打开该文件 第一个参数用于指定父组件 第二个参数指定对话框标题 第三个参数指定目录 第四个参数是文件扩展名过滤器 """ pass # fname, _ = QFileDialog.getOpenFileName(self, '选择图形文件', 'C:\\', "*.jpg *.gif *.png") # self.pixmapLabel.setPixmap(QPixmap(fname)) def get_text(self): """ :return: """ pass # # 初始化实例,并设置一些参数 # # textDialog = QFileDialog() # # textDialog.setFileMode(QFileDialog.AnyFile) # # textDialog.setFilter(QDir.Files) # textDialog = QFileDialog.getOpenFileName(self, '选择文本文件', 'C:\\', "*.txt *.doc *.docx") # # 当选择器关闭的时候 # if textDialog.exec_(): # # 拿到所选择的文本 # filenames = textDialog.selectedFiles() # # 读取文本内容设置到textEdit中 # f = open(filenames[0], 'r') # with f: # data = f.read() # self.textEdit.setText(data) def open_inform_frame(self): self.messageInform.show()
class ShowPoints(QWidget): def __init__(self): super().__init__() self.webView = QtWebEngineWidgets.QWebEngineView() self.sourceType = QComboBox() self.sourceType.addItems(['国测局坐标GCJ02(MX数据库/高德)','GPS坐标(wgs84/NMEA0183)']) self.inputText = QTextEdit() self.inputText.setFixedWidth(280) self.runButton = QPushButton('确定') self.runButton.setFixedWidth(100) self.clrButton = QPushButton('清除') self.clrButton.setFixedWidth(100) self.statusBar = QStatusBar() self.statusBar.showMessage(STATUS_TIP+"Ready") self.init_ui() def init_ui(self): path = os.getcwd() url = path + HTM_FILE self.webView.setUrl(QtCore.QUrl(url)) self.webView.page().loadFinished.connect(self.load_finished) # for test self.inputText.setEnabled(False) self.inputText.setAcceptRichText(False) self.inputText.setToolTip("每行一组经纬度,纬度lat在前\n" + "以空格、逗号或制表符分隔") self.runButton.clicked.connect(self.add_points) # show all points in input text window self.clrButton.clicked.connect(self.clr_points) buttonBox = QHBoxLayout() # button box buttonBox.addStretch() buttonBox.addWidget(self.runButton) buttonBox.addWidget(self.clrButton) rightBox = QVBoxLayout() # right box rightBox.addWidget(self.sourceType) rightBox.addWidget(self.inputText) rightBox.addLayout(buttonBox) rightBox.addWidget(self.statusBar) layout = QHBoxLayout() # main box layout.addWidget(self.webView) layout.addLayout(rightBox) self.setLayout(layout) self.setWindowTitle('经纬度地图显示') self.show() def load_finished(self): self.inputText.setEnabled(True) def add_marker(self): """ 添加标记,ok :return: """ a = self.webView.page() # a.runJavaScript("addMarker(114.39387,30.505299,true,1);") # a.runJavaScript("var point = new BMap.Point(114,30);var marker = new BMap.Marker(point);map.addOverlay(marker);") a.runJavaScript("testfunc(1);") # ok a.runJavaScript("addMarker(114,30.01,true,2);") def run_script(self, script): a = self.webView.page() a.runJavaScript(script) def add_points(self): self.statusBar.showMessage(STATUS_TIP+"Running...") points_text = self.inputText.toPlainText() # 获取输入 source_type = self.sourceType.currentIndex() if_mars = 'true' if (source_type == 0) else 'false' if points_text == "": # 使用示例输入 points_text = SAMPLE_DATA self.inputText.setPlainText(points_text) points = Point.points_parser(points_text) # 解析输入 lats = [p.lat for p in points] lons = [p.lon for p in points] N = len(lats) # 共N组经纬度 G = math.ceil((N - 1) / 9) # 每10个一组,首尾相接,共G组 if N == 1: G = 1 for g in range(G): # 0,1,...,G-1 index_s = 9 * g index_e = 9 * g + 10 index_e = N if (index_e > N) else index_e latsStr = "[" + ",".join(lats[index_s:index_e]) + "]" lonsStr = "[" + ",".join(lons[index_s:index_e]) + "]" script = "addSimpleMarker(%s,%s,%s);" % (latsStr, lonsStr, if_mars) self.run_script(script) time.sleep(0.1) # seconds,延时0.1秒,避免回调函数的执行顺序被打乱 self.statusBar.showMessage(STATUS_TIP+"Done") def clr_points(self): self.run_script("clearMarkers();") self.inputText.setPlainText("") self.statusBar.showMessage(STATUS_TIP+"Ready")
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setObjectName("myGitClone") root = QFileInfo.path(QFileInfo(QCoreApplication.arguments()[0])) print("root", root) self.icon = QIcon(f"{root}/favicon.ico") self.setWindowIcon(self.icon) self.setGeometry(0, 0, 800, 600) self.setAttribute(Qt.WA_DeleteOnClose) self.setMinimumSize(400, 300) self.setDocumentMode(True) self.settings = QSettings('Axel Schneider', self.objectName()) self.createStatusbar() self.createActions() self.createWidgets() QMetaObject.connectSlotsByName(self) self.readSettings() self.statusbar.showMessage("Ready") self.setWindowTitle("myGitClone") ### process ### shell settings self.process = QProcess(self) self.process.setProcessChannelMode(QProcess.MergedChannels) self.process.readyReadStandardError.connect(lambda: self.msg("Error")) self.process.started.connect(lambda: self.msg("starting shell")) self.process.finished.connect(lambda: self.msg("shell ended")) ### widgets ### def createWidgets(self): self.username = "" self.url = "https://github.com/%s?tab=repositories" % self.username self.repoList = [] self.gitList = [] self.dlFolder = QDir.homePath() + "/Downloads" ### table ### self.lb = QTableWidget() self.lb.setColumnCount(2) self.lb.setColumnWidth(0, 60) self.lb.horizontalHeader().setStretchLastSection(True) self.lb.setHorizontalHeaderItem(0, QTableWidgetItem("Select")) self.lb.setHorizontalHeaderItem(1, QTableWidgetItem("Repository Name")) ### username field ### self.uname = QLineEdit("") self.uname.setFixedWidth(180) self.uname.setPlaceholderText("insert user name") self.uname.returnPressed.connect(self.listRepos) ### get repos button ### self.uBtn = QPushButton(QIcon(self.icon), "get Repos List") self.uBtn.setToolTip("get all repos from user") self.uBtn.clicked.connect(self.listRepos) ### get repos button ### self.dlBtn = QPushButton(QIcon.fromTheme("download"), "download selected Repos") self.dlBtn.setToolTip("download selected repos from user") self.dlBtn.setFixedWidth(180) self.dlBtn.clicked.connect(self.create_dl_list) ### Layout self.ubox = QHBoxLayout() self.ubox.addWidget(self.uname) self.ubox.addWidget(self.uBtn) self.ubox.addStretch(1) self.ubox.addWidget(self.dlBtn) self.layout = QVBoxLayout() self.wid = QWidget() self.layout.addLayout(self.ubox) self.layout.addWidget(self.lb) self.wid.setLayout(self.layout) self.setCentralWidget(self.wid) ### actions ### def createActions(self): self.tbar = QToolBar() self.tbar.setIconSize(QSize(16, 16)) self.tbar.setMovable(False) self.tbar.setToolButtonStyle(0) self.tbar.setContextMenuPolicy(Qt.PreventContextMenu) self.tbar.setObjectName("tbar") self.addToolBar(self.tbar) self.actionSettings = QAction(self, triggered=self.appSettings, toolTip="set output directory") icon = QIcon.fromTheme("preferences-system") self.actionSettings.setIcon(icon) self.actionSettings.setObjectName("actionSettings") self.actionAbout = QAction(self, triggered=self.aboutApp) icon = QIcon.fromTheme("help-about") self.actionAbout.setIcon(icon) self.tbar.addAction(self.actionSettings) self.tbar.addAction(self.actionAbout) ### statusbar### def createStatusbar(self): self.statusbar = QStatusBar(self) font = QFont() font.setPointSize(7) self.statusbar.setFont(font) self.statusbar.setObjectName("statusbar") self.setStatusBar(self.statusbar) ### get username from textfield def changeUsername(self): self.username = self.uname.text() self.url = "https://github.com/%s?tab=repositories" % self.username ### get user repos ## def listRepos(self): self.changeUsername() if self.username == "": self.msgBox("please type a username") else: self.lb.setRowCount(0) self.repoList = [] repositories = self.get_repositories() print("%s %s" % ("get repos from", self.username)) self.repoList = list(repositories) self.fillTable() self.msg("repos loaded") ### fill table with user repos def fillTable(self): self.lb.setRowCount(len(self.repoList)) if self.lb.rowCount() > 0: for x in range(len(self.repoList)): rep = QTableWidgetItem(self.repoList[x]) checkbox = QCheckBox(self.lb) checkbox.setStyleSheet("margin-left:20%; margin-right:10%;") checkbox.setCheckState(0) self.lb.setCellWidget(x, 0, checkbox) self.lb.setItem(x, 1, rep) ### table context menu def contextMenuEvent(self, event): self.menu = QMenu(self) if self.lb.selectionModel().hasSelection(): # copy downloadAction = QAction(QIcon.fromTheme("download"), 'download Repo', self) downloadAction.triggered.connect( lambda: self.downloadRepoFromList()) ### self.menu.addAction(downloadAction) self.menu.popup(QCursor.pos()) def listChanged(self): self.create_dl_list() ### get download list from selected repos def create_dl_list(self): r = "" self.gitList = [] for x in range(self.lb.rowCount()): if self.lb.cellWidget(x, 0).checkState() == 2: r = self.lb.item(x, 1).text() self.gitList.append(r) print("%s %s" % (r, "is selected")) self.downloadRepo(r) ### download repo def downloadRepo(self, gitrepo): merror = "" cmd = "git clone --progress --verbose https://github.com/" + str( self.username) + "/" + str(gitrepo) + " " + str( self.dlFolder) + "/" + str(gitrepo) print("%s %s" % ("username is:", self.username)) print(cmd) try: self.process.execute(cmd) except Exception as e: s = str(e) self.errorBox(s) ### download selected repo (context menu) def downloadRepoFromList(self): row = self.lb.selectionModel().selectedIndexes()[0].row() gitrepo = self.lb.item(row, 1).text() cmd = "git clone --progress --verbose https://github.com/" + str( self.username) + "/" + str(gitrepo) + " " + str( self.dlFolder) + "/" + str(gitrepo) print(cmd) self.process.execute(cmd) ### preferences def appSettings(self): if self.dlFolder == "": self.dlFolder = QDir.homePath() self.msg("settings called") path = QFileDialog.getExistingDirectory(self, "select Folder", self.dlFolder) if path: self.dlFolder = path print("%s %s" % ("download folder changed to", self.dlFolder)) def closeEvent(self, e): self.writeSettings() e.accept() ### read settings from config file def readSettings(self): print("reading settings") if self.settings.contains('geometry'): self.setGeometry(self.settings.value('geometry')) if self.settings.contains('downloadFolder'): self.dlFolder = self.settings.value('downloadFolder') self.msg(self.dlFolder) print("%s %s" % ("download folder:", self.dlFolder)) ### write settings to config file def writeSettings(self): print("writing settings") self.settings.setValue('geometry', self.geometry()) self.settings.setValue('downloadFolder', self.dlFolder) ### about window def aboutApp(self): title = "about myGitClone" message = """ <span style='color: #3465a4; font-size: 18pt;font-weight: bold;' >myGitClone</strong></span></p> <h3>based on <a title='git_clones' href='https://github.com/rootVIII/git_clones' target='_blank'> git_clones</a> by James</h3> <h4>created by <a title='Axel Schneider' href='http://goodoldsongs.jimdo.com' target='_blank'>Axel Schneider</a> with PyQt5</h3> <br> <span style='color: #555753; font-size: 9pt;'>©2019 Axel Schneider, James</strong></span></p> """ self.infobox(title, message) ### error messagebox def errorBox(self, message): mwin = QMessageBox.warning(self, "Error", message) ### messagebox def infobox(self, title, message): QMessageBox.about(self, title, message).show() ### set statusbar text def msg(self, message): self.statusbar.showMessage(message) def msgBox(self, message): msg = QMessageBox.warning(self, "Information", message) ### begin from git_clones ### def http_get(self): if version_info[0] != 2: req = urlopen(self.url) return req.read().decode('utf-8') req = Request(self.url) request = urlopen(req) return request.read() def get_repo_data(self): try: response = self.http_get() except Exception as e: s = str(e) self.errorBox(s) print("Unable to make request to %s's Github page" % self.username) exit(1) else: pattern = r"<a\s?href\W+%s/(.*)\"\s+" % self.username for line in findall(pattern, response): yield line.split('\"')[0] def get_repositories(self): return set([repo for repo in self.get_repo_data()])
class MainWindow(QMainWindow, metaclass=QSingleton): new_session = pyqtSignal() save_session = pyqtSignal(str) open_session = pyqtSignal(str) def __init__(self): super().__init__() self.setMinimumSize(500, 400) self.setCentralWidget(QWidget()) self.centralWidget().setLayout(QVBoxLayout()) self.centralWidget().layout().setContentsMargins(5, 5, 5, 5) self._cue_add_menu = {} self.layout = None # Status Bar self.statusBar = QStatusBar(self) self.setStatusBar(self.statusBar) MainActionsHandler.action_done.connect(self._action_done) MainActionsHandler.action_undone.connect(self._action_undone) MainActionsHandler.action_redone.connect(self._action_redone) # Menubar self.menubar = QMenuBar(self) self.menubar.setGeometry(QtCore.QRect(0, 0, 0, 25)) self.menubar.setContextMenuPolicy(QtCore.Qt.PreventContextMenu) self.menuFile = QMenu(self.menubar) self.menuEdit = QMenu(self.menubar) self.menuLayout = QMenu(self.menubar) self.menuTools = QMenu(self.menubar) self.menuAbout = QMenu(self.menubar) self.menubar.addMenu(self.menuFile) self.menubar.addMenu(self.menuEdit) self.menubar.addMenu(self.menuLayout) self.menubar.addMenu(self.menuTools) self.menubar.addMenu(self.menuAbout) self.setMenuBar(self.menubar) # menuFile self.newSessionAction = QAction(self) self.newSessionAction.triggered.connect(self._new_session) self.openSessionAction = QAction(self) self.openSessionAction.triggered.connect(self._load_from_file) self.saveSessionAction = QAction(self) self.saveSessionAction.triggered.connect(self._save) self.saveSessionWithName = QAction(self) self.saveSessionWithName.triggered.connect(self._save_with_name) self.editPreferences = QAction(self) self.editPreferences.triggered.connect(self._show_preferences) self.fullScreenAction = QAction(self) self.fullScreenAction.triggered.connect(self._fullscreen) self.fullScreenAction.setCheckable(True) self.exitAction = QAction(self) self.exitAction.triggered.connect(self._exit) self.menuFile.addAction(self.newSessionAction) self.menuFile.addAction(self.openSessionAction) self.menuFile.addSeparator() self.menuFile.addAction(self.saveSessionAction) self.menuFile.addAction(self.saveSessionWithName) self.menuFile.addSeparator() self.menuFile.addAction(self.editPreferences) self.menuFile.addSeparator() self.menuFile.addAction(self.fullScreenAction) self.menuFile.addSeparator() self.menuFile.addAction(self.exitAction) # menuEdit self.actionUndo = QAction(self) self.actionUndo.triggered.connect(MainActionsHandler.undo_action) self.actionRedo = QAction(self) self.actionRedo.triggered.connect(MainActionsHandler.redo_action) self.multiEdit = QAction(self) self.selectAll = QAction(self) self.selectAllMedia = QAction(self) self.deselectAll = QAction(self) self.invertSelection = QAction(self) self.cueSeparator = self.menuEdit.addSeparator() self.menuEdit.addAction(self.actionUndo) self.menuEdit.addAction(self.actionRedo) self.menuEdit.addSeparator() self.menuEdit.addAction(self.selectAll) self.menuEdit.addAction(self.selectAllMedia) self.menuEdit.addAction(self.deselectAll) self.menuEdit.addAction(self.invertSelection) self.menuEdit.addSeparator() self.menuEdit.addAction(self.multiEdit) # menuAbout self.actionAbout = QAction(self) self.actionAbout.triggered.connect(about.About(self).show) self.actionAbout_Qt = QAction(self) self.actionAbout_Qt.triggered.connect(qApp.aboutQt) self.menuAbout.addAction(self.actionAbout) self.menuAbout.addSeparator() self.menuAbout.addAction(self.actionAbout_Qt) # Set component text self.retranslateUi() # The save file name self.filename = '' def retranslateUi(self): self.setWindowTitle('Linux Show Player') # menuFile self.menuFile.setTitle(translate('MainWindow', '&File')) self.newSessionAction.setText(translate('MainWindow', 'New session')) self.newSessionAction.setShortcut(QKeySequence.New) self.openSessionAction.setText(translate('MainWindow', 'Open')) self.openSessionAction.setShortcut(QKeySequence.Open) self.saveSessionAction.setText(translate('MainWindow', 'Save session')) self.saveSessionAction.setShortcut(QKeySequence.Save) self.editPreferences.setText(translate('MainWindow', 'Preferences')) self.editPreferences.setShortcut(QKeySequence.Preferences) self.saveSessionWithName.setText(translate('MainWindow', 'Save as')) self.saveSessionWithName.setShortcut(QKeySequence.SaveAs) self.fullScreenAction.setText(translate('MainWindow', 'Full Screen')) self.fullScreenAction.setShortcut(QKeySequence.FullScreen) self.exitAction.setText(translate('MainWindow', 'Exit')) # menuEdit self.menuEdit.setTitle(translate('MainWindow', '&Edit')) self.actionUndo.setText(translate('MainWindow', 'Undo')) self.actionUndo.setShortcut(QKeySequence.Undo) self.actionRedo.setText(translate('MainWindow', 'Redo')) self.actionRedo.setShortcut(QKeySequence.Redo) self.selectAll.setText(translate('MainWindow', 'Select all')) self.selectAllMedia.setText( translate('MainWindow', 'Select all media cues')) self.selectAll.setShortcut(QKeySequence.SelectAll) self.deselectAll.setText(translate('MainWindow', 'Deselect all')) self.deselectAll.setShortcut(translate('MainWindow', 'CTRL+SHIFT+A')) self.invertSelection.setText( translate('MainWindow', 'Invert selection')) self.invertSelection.setShortcut(translate('MainWindow', 'CTRL+I')) self.multiEdit.setText(translate('MainWindow', 'Edit selected')) self.multiEdit.setShortcut(translate('MainWindow', 'CTRL+SHIFT+E')) # menuLayout self.menuLayout.setTitle(translate('MainWindow', '&Layout')) # menuTools self.menuTools.setTitle(translate('MainWindow', '&Tools')) self.multiEdit.setText(translate('MainWindow', 'Edit selection')) # menuAbout self.menuAbout.setTitle(translate('MainWindow', '&About')) self.actionAbout.setText(translate('MainWindow', 'About')) self.actionAbout_Qt.setText(translate('MainWindow', 'About Qt')) def set_layout(self, layout): if self.layout is not None: self.layout.hide() self.centralWidget().layout().removeWidget(self.layout) self.multiEdit.triggered.disconnect() self.selectAll.triggered.disconnect() self.selectAllMedia.triggered.disconnect() self.deselectAll.triggered.disconnect() self.invertSelection.triggered.disconnect() self.layout = layout self.centralWidget().layout().addWidget(self.layout) self.layout.show() self.multiEdit.triggered.connect(self.layout.edit_selected_cues) self.selectAll.triggered.connect(lambda: self.layout.select_all()) self.selectAllMedia.triggered.connect( lambda: self.layout.select_all(MediaCue)) self.deselectAll.triggered.connect(lambda: self.layout.deselect_all()) self.invertSelection.triggered.connect(self.layout.invert_selection) def closeEvent(self, event): self._exit() event.ignore() def register_cue_menu_action(self, name, function, category='', shortcut=''): '''Register a new-cue choice for the edit-menu param name: The name for the MenuAction param function: The function that add the new cue(s) param category: The optional menu where insert the MenuAction param shortcut: An optional shortcut for the MenuAction ''' action = QAction(self) action.setText(translate('MainWindow', name)) action.triggered.connect(function) if shortcut != '': action.setShortcut(translate('MainWindow', shortcut)) if category != '': if category not in self._cue_add_menu: menu = QMenu(category, self) self._cue_add_menu[category] = menu self.menuEdit.insertMenu(self.cueSeparator, menu) self._cue_add_menu[category].addAction(action) else: self.menuEdit.insertAction(self.cueSeparator, action) def update_window_title(self): saved = MainActionsHandler.is_saved() if not saved and not self.windowTitle()[0] == '*': self.setWindowTitle('*' + self.windowTitle()) elif saved and self.windowTitle()[0] == '*': self.setWindowTitle(self.windowTitle()[1:]) def _action_done(self, action): self.statusBar.showMessage(action.log()) self.update_window_title() def _action_undone(self, action): self.statusBar.showMessage( translate('MainWindow', 'Undone: ') + action.log()) self.update_window_title() def _action_redone(self, action): self.statusBar.showMessage( translate('MainWindow', 'Redone: ') + action.log()) self.update_window_title() def _save(self): if self.filename == '': self._save_with_name() else: self.save_session.emit(self.filename) def _save_with_name(self): filename, _ = QFileDialog.getSaveFileName(parent=self, filter='*.lsp', directory=os.getenv('HOME')) if filename != '': if not filename.endswith('.lsp'): filename += '.lsp' self.filename = filename self._save() def _show_preferences(self): prefUi = AppSettings(configuration.config_to_dict(), parent=self) prefUi.exec_() if prefUi.result() == QDialog.Accepted: configuration.update_config_from_dict(prefUi.get_configuraton()) def _load_from_file(self): if self._check_saved(): path, _ = QFileDialog.getOpenFileName(self, filter='*.lsp', directory=os.getenv('HOME')) if os.path.exists(path): self.open_session.emit(path) self.filename = path def _new_session(self): if self._check_saved(): self.new_session.emit() def _check_saved(self): if not MainActionsHandler.is_saved(): msgBox = QMessageBox(self) msgBox.setIcon(QMessageBox.Warning) msgBox.setWindowTitle(translate('MainWindow', 'Close session')) msgBox.setText( translate('MainWindow', 'The current session is not saved.')) msgBox.setInformativeText( translate('MainWindow', 'Discard the changes?')) msgBox.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) msgBox.setDefaultButton(QMessageBox.Save) result = msgBox.exec_() if result == QMessageBox.Cancel: return False elif result == QMessageBox.Save: self._save() return True def _fullscreen(self, enable): if enable: self.showFullScreen() else: self.showMaximized() def _exit(self): if self._check_saved(): qApp.quit()
class MainWindow(QMainWindow, metaclass=QSingleton): new_session = QtCore.pyqtSignal() save_session = QtCore.pyqtSignal(str) open_session = QtCore.pyqtSignal(str) def __init__(self): super().__init__() self.setMinimumSize(400, 300) self._cue_add_menus = {} self.layout = None # Define the layout and the main gui's elements self.centralwidget = QWidget(self) self.setCentralWidget(self.centralwidget) self.gridLayout = QGridLayout(self.centralwidget) self.gridLayout.setContentsMargins(2, 5, 2, 0) # Status Bar self.statusBar = QStatusBar(self) self.setStatusBar(self.statusBar) ActionsHandler().action_done.connect(self._action_done) ActionsHandler().action_undone.connect(self._action_undone) ActionsHandler().action_redone.connect(self._action_redone) # Menubar self.menubar = QMenuBar(self) self.menubar.setGeometry(QtCore.QRect(0, 0, 0, 25)) self.menubar.setContextMenuPolicy(QtCore.Qt.PreventContextMenu) self.menuFile = QMenu(self.menubar) self.menuEdit = QMenu(self.menubar) self.menuLayout = QMenu(self.menubar) self.menuTools = QMenu(self.menubar) self.menuAbout = QMenu(self.menubar) self.menubar.addMenu(self.menuFile) self.menubar.addMenu(self.menuEdit) self.menubar.addMenu(self.menuLayout) self.menubar.addMenu(self.menuTools) self.menubar.addMenu(self.menuAbout) self.setMenuBar(self.menubar) # menuFile self.newSessionAction = QAction(self, triggered=self._startup) self.openSessionAction = QAction(self, triggered=self._load_from_file) self.saveSessionAction = QAction(self, triggered=self.save) self.saveSessionWithName = QAction(self, triggered=self.save_with_name) self.editPreferences = QAction(self, triggered=self.show_preferences) self.fullScreenAction = QAction(self, triggered=self._fullscreen) self.fullScreenAction.setCheckable(True) self.exitAction = QAction(self, triggered=self.exit) self.menuFile.addAction(self.newSessionAction) self.menuFile.addAction(self.openSessionAction) self.menuFile.addSeparator() self.menuFile.addAction(self.saveSessionAction) self.menuFile.addAction(self.saveSessionWithName) self.menuFile.addSeparator() self.menuFile.addAction(self.editPreferences) self.menuFile.addSeparator() self.menuFile.addAction(self.fullScreenAction) self.menuFile.addSeparator() self.menuFile.addAction(self.exitAction) # menuEdit self.actionUndo = QAction(self) self.actionUndo.triggered.connect( lambda: ActionsHandler().undo_action()) self.actionRedo = QAction(self) self.actionRedo.triggered.connect( lambda: ActionsHandler().redo_action()) self.multiEdit = QAction(self) self.selectAll = QAction(self) self.deselectAll = QAction(self) self.invertSelection = QAction(self) self.cueSeparator = self.menuEdit.addSeparator() self.menuEdit.addAction(self.actionUndo) self.menuEdit.addAction(self.actionRedo) self.menuEdit.addSeparator() self.menuEdit.addAction(self.selectAll) self.menuEdit.addAction(self.deselectAll) self.menuEdit.addAction(self.invertSelection) self.menuEdit.addSeparator() self.menuEdit.addAction(self.multiEdit) # menuAbout self.actionAbout = QAction(self) self.actionAbout.triggered.connect(about.About(self).show) self.actionAbout_Qt = QAction(self) self.actionAbout_Qt.triggered.connect(qApp.aboutQt) self.menuAbout.addAction(self.actionAbout) self.menuAbout.addSeparator() self.menuAbout.addAction(self.actionAbout_Qt) # Set component text self.retranslateUi() # The save file name self.file = '' def retranslateUi(self): self.setWindowTitle('Linux Show Player') # menuFile self.menuFile.setTitle("&File") self.newSessionAction.setText("New session") self.newSessionAction.setShortcut("CTRL+N") self.openSessionAction.setText("Open") self.openSessionAction.setShortcut("CTRL+O") self.saveSessionAction.setText("Save session") self.saveSessionAction.setShortcut("CTRL+S") self.editPreferences.setText("Preferences") self.editPreferences.setShortcut("CTRL+P") self.saveSessionWithName.setText("Save with name") self.saveSessionWithName.setShortcut('CTRL+SHIFT+S') self.fullScreenAction.setText('Toggle fullscreen') self.fullScreenAction.setShortcut('F11') self.exitAction.setText("Exit") # menuEdit self.menuEdit.setTitle("&Edit") self.actionUndo.setText('Undo') self.actionUndo.setShortcut('CTRL+Z') self.actionRedo.setText('Redo') self.actionRedo.setShortcut('CTRL+Y') self.selectAll.setText("Select all") self.selectAll.setShortcut("CTRL+A") self.deselectAll.setText("Deselect all") self.deselectAll.setShortcut("CTRL+SHIFT+A") self.invertSelection.setText("Invert selection") self.invertSelection.setShortcut("CTRL+I") self.multiEdit.setText("Edit selected media") self.multiEdit.setShortcut("CTRL+SHIFT+E") # menuLayout self.menuLayout.setTitle("&Layout") # menuTools self.menuTools.setTitle("&Tools") self.multiEdit.setText("Edit selected media") # menuAbout self.menuAbout.setTitle("&About") self.actionAbout.setText("About") self.actionAbout_Qt.setText("About Qt") def set_layout(self, layout): if self.layout is not None: self.layout.hide() self.gridLayout.removeWidget(self.layout) self.multiEdit.triggered.disconnect() self.selectAll.triggered.disconnect() self.deselectAll.triggered.disconnect() self.invertSelection.triggered.disconnect() self.layout = layout self.multiEdit.triggered.connect(self.layout.edit_selected_cues) self.selectAll.triggered.connect(self.layout.select_all) self.deselectAll.triggered.connect(self.layout.deselect_all) self.invertSelection.triggered.connect(self.layout.invert_selection) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.layout.setSizePolicy(sizePolicy) self.gridLayout.addWidget(self.layout, 0, 0) self.layout.show() def save(self): if self.file == '': self.save_with_name() else: self.save_session.emit(self.file) def save_with_name(self): self.file, _ = QFileDialog.getSaveFileName(parent=self, filter='*.lsp', directory=os.getenv('HOME')) if self.file != '': if not self.file.endswith('.lsp'): self.file += '.lsp' self.save() def show_preferences(self): prefUi = AppSettings(configuration.config_to_dict(), parent=self) prefUi.exec_() if(prefUi.result() == QDialog.Accepted): configuration.update_config_from_dict(prefUi.get_configuraton()) def exit(self): confirm = QMessageBox.Yes if not ActionsHandler().is_saved(): confirm = QMessageBox.question(self, 'Exit', 'The current session is not saved. ' 'Exit anyway?') if confirm == QMessageBox.Yes: qApp.quit() def closeEvent(self, event): self.exit() event.ignore() def register_cue_options_ui(self, name, options_ui, category='', shortcut=''): ''' Register a new-cue choice for the edit-menu @param name: The name for the MenuAction @param options_ui: A method that provide the options for the new cue(s) (e.g. show a file-dialog) @param category: The optional menu where insert the MenuAction @param shortcut: An optional shortcut for the MenuAction ''' action = QAction(self) action.setText(name) action.triggered.connect(lambda: self._add_cues(options_ui())) if shortcut != '': action.setShortcut(shortcut) if category != '': if category not in self._cue_add_menus: menu = QMenu(category, self) self._cue_add_menus[category] = menu self.menuEdit.insertMenu(self.cueSeparator, menu) self._cue_add_menus[category].addAction(action) else: self.menuEdit.insertAction(self.cueSeparator, action) def update_window_title(self): saved = ActionsHandler().is_saved() if not saved and not self.windowTitle()[0] == '*': self.setWindowTitle('*' + self.windowTitle()) elif saved and self.windowTitle()[0] == '*': self.setWindowTitle(self.windowTitle()[1:]) def _action_done(self, action): self.statusBar.showMessage(action.log()) self.update_window_title() def _action_undone(self, action): self.statusBar.showMessage('Undone' + action.log()) self.update_window_title() def _action_redone(self, action): self.statusBar.showMessage('Redone' + action.log()) self.update_window_title() def _add_cues(self, options_list): for options in options_list: try: cue = CueFactory.create_cue(options) self.layout.add_cue(cue) except Exception as e: message = ' '.join([str(i) for i in e.args]) QMessageBox.critical(None, 'Error', message) def _load_from_file(self): if self._new_session_confirm(): path = QFileDialog.getOpenFileName(parent=self, filter='*.lsp', directory=os.getenv('HOME'))[0] if os.path.exists(path): self.open_session.emit(path) self.file = path return True return False def _new_session_confirm(self): confirm = QMessageBox.question(self, 'New session', 'The current session will be lost. ' 'Continue?') return confirm == QMessageBox.Yes def _startup(self): if self._new_session_confirm(): self.new_session.emit() def _fullscreen(self, enable): if enable: self.showFullScreen() else: self.showMaximized()