class ViewExpensesScreen(QWidget, ListenerNode): def __init__(self, listeners_pool, *args, **kwargs): super(ViewExpensesScreen, self).__init__(*args, **kwargs) self.listeners_pool = listeners_pool ListenerNode.__init__(self, 'view-expenses-screen', self.listeners_pool) self.classified_expenses_table = None self.layout = QVBoxLayout() self.setLayout(self.layout) self.filter_widget = FilterWidget('classified', listeners_pool) self.layout.addWidget(self.filter_widget) self.add_table('expenses_raw') self.send_event('sum-text', 'show_records_no') def add_table(self, table_type): if self.classified_expenses_table != None: self.layout.removeWidget(self.classified_expenses_table) self.classified_expenses_table = ClassifiedExpensesTable(self.listeners_pool, table_type) self.classified_expenses_table.refresh_rows() self.layout.addWidget(self.classified_expenses_table)
class DownloadPage(QWidget): def __init__(self, parent): super(DownloadPage, self).__init__() self.setMinimumSize(500, 300) self.parent = parent self.nbDownload = 0 self.layoutMain = QVBoxLayout(self) self.scroll = QScrollArea(self) self.scroll.setWidgetResizable(True) self.title = QLabel("Téléchargements") self.title.setAlignment(Qt.AlignHCenter) self.layoutMain.addWidget(self.title) self.layoutMain.addWidget(self.scroll) self.container = QWidget() self.scroll.setWidget(self.container) self.layout = QVBoxLayout(self.container) self.label = QLabel("Pas de téléchargement") self.label.setAlignment(Qt.AlignHCenter) self.layout.addWidget(self.label) def downloadrequested(self, download): if download: if download.state() == QWebEngineDownloadItem.DownloadRequested: path = QFileDialog.getSaveFileName(self, "Sauver comme", download.path()) if path == "": return else: download.setPath(path[0]) download.accept() self.add( DownloadWidget( download, self.parent.parent.browserWidget.url().toString(), self.parent.parent)) self.show() else: QMessageBox.warning(self, "ERREUR", "Le téléchargement n'a pas été demandé.") else: QMessageBox.warning(self, "ERREUR", "Le téléchargement est nul.") def add(self, downloadwidget): downloadwidget.downloadSignal.removeClicked.connect(self.remove) self.layout.addWidget(downloadwidget) self.layout.setAlignment(downloadwidget, Qt.AlignTop) self.nbDownload += 1 if self.nbDownload >= 0: self.label.hide() def remove(self): downloadwidget = self.sender().parent self.layout.removeWidget(downloadwidget) downloadwidget.deleteLater() self.nbDownload -= 1 if self.nbDownload <= 0: self.label.show()
class ArrayRequirementEditor: def __init__(self, parent: QWidget, parent_layout: QVBoxLayout, resource_database: ResourceDatabase, requirement: Union[RequirementOr, RequirementAnd]): self._editors = [] self.resource_database = resource_database self._array_type = type(requirement) self.group_box = QGroupBox(parent) self.group_box.setStyleSheet("QGroupBox { margin-top: 2px; }") parent_layout.addWidget(self.group_box) self.item_layout = QVBoxLayout(self.group_box) self.item_layout.setContentsMargins(8, 2, 2, 6) self.item_layout.setAlignment(Qt.AlignTop) self.new_item_button = QPushButton(self.group_box) self.new_item_button.setMaximumWidth(75) self.new_item_button.setText("New Row") self.new_item_button.clicked.connect(self.new_item) for item in requirement.items: self._create_item(item) self.item_layout.addWidget(self.new_item_button) def _create_item(self, item: Requirement): def on_remove(): self._editors.remove(nested_editor) nested_editor.deleteLater() nested_editor = RequirementEditor(self.group_box, self.item_layout, self.resource_database, on_remove=on_remove) nested_editor.create_specialized_editor(item) self._editors.append(nested_editor) def new_item(self): self._create_item( _create_default_resource_requirement(self.resource_database)) self.item_layout.removeWidget(self.new_item_button) self.item_layout.addWidget(self.new_item_button) def deleteLater(self): self.group_box.deleteLater() for editor in self._editors: editor.deleteLater() self.new_item_button.deleteLater() @property def current_requirement(self) -> Union[RequirementOr, RequirementAnd]: return self._array_type( [editor.current_requirement for editor in self._editors])
class plotMainWidget(QWidget): def __init__(self, controller): super(plotMainWidget, self).__init__() print("plotMainWidget") self.dc = controller self.plot = None self.filter_groupBox = QGroupBox("Filters") self.filter_msg_comboBox = QComboBox() self.filter_msg_label = QLabel("Message:") self.filter_msg_label.setBuddy(self.filter_msg_comboBox) self.filter_msg_comboBox.addItems(plot_msg) self.filter_msg_button = QPushButton("Show") self.filter_msg_button.clicked.connect(self.filterButtonClicked) layout = QGridLayout() # layout.setColumnMinimumWidth(9,100) # layout.setColumnMinimumWidth(1,30) layout.addWidget(self.filter_msg_label, 0, 0) layout.addWidget(self.filter_msg_comboBox, 0, 2, 0, 8) layout.addWidget(self.filter_msg_button, 0, 10) self.filter_groupBox.setLayout(layout) self.plot_groupBox = QGroupBox("Chart") mainLayout = QGridLayout() mainLayout.addWidget(self.filter_groupBox, 0, 0) mainLayout.addWidget(self.plot_groupBox, 1, 0, 9, 0) self.setLayout(mainLayout) def filterButtonClicked(self): msg = self.filter_msg_comboBox.currentText() data_set = self.dc.getDataSet(msg) time_axis = [] val_axis = [] for i in data_set: time_axis.append(i[3]) val_axis.append(i[4]) self.plot = MyMplCanvas(time_axis, val_axis) self.curr_plot_layout = QVBoxLayout() self.curr_plot_layout.addWidget(self.plot) self.plot_groupBox.setLayout(self.curr_plot_layout) def cleanPlot(self): if (self.plot): print("clean") self.curr_plot_layout.removeWidget(self.plot)
class _NotificationWidget(QWidget): def __init__(self, parent: QWidget = None): time = datetime.now() currentTime = str(time.hour) + ":" + str(time.minute) + "_" self.LOG_TAG = currentTime + self.__class__.__name__ + ": " super().__init__(parent) self.setWindowFlags(Qt.FramelessWindowHint | Qt.Tool) self.nMessages = 0 self.mainLayout = QVBoxLayout(self) def updatePosition(self) -> None: parentOrigin = self.parentWidget().pos() parentSize = self.parentWidget().size() # Move in bottom right corner self.move(parentOrigin.x() + parentSize.width() - self.width(), parentOrigin.y() + parentSize.height() - self.height()) def setNotify(self, title, message, icon): m = _Message(title, message, icon, self) self.mainLayout.addWidget(m) m.buttonClose.clicked.connect(self.onClicked) self.nMessages += 1 if not self.isVisible(): self.show() m.show() self.adjustSize() self.updatePosition() def showEvent(self, event: QtGui.QShowEvent) -> None: if self.nMessages > 0: super().showEvent(event) @Slot() def onClicked(self): self.mainLayout.removeWidget(self.sender().parent()) self.sender().parent().deleteLater() self.nMessages -= 1 self.adjustSize() self.updatePosition() if self.nMessages == 0: self.hide()
def testDeleteMultipleInheritance(self): app = QApplication(sys.argv) class DerivedLabel(QLabel, QObject): def __del__(self): global is_alive is_alive = False global is_alive child = DerivedLabel('Hello') is_alive = True parent = QVBoxLayout() parent.addWidget(child) parent.removeWidget(child) child.deleteLater() self.assertTrue(is_alive) del child self.assertTrue(is_alive) QTimer.singleShot(100, app.quit) app.exec_() self.assertFalse(is_alive)
class HackerNewsWidget(QWidget): def __init__(self): QWidget.__init__(self) self.widgets = [] self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(0) self.setLayout(self.layout) OverviewSignal.changed.connect(self.render) self.render() def render(self, url=''): spider = HackerNewsSpider() spider.crawl(url) for widget in self.widgets: self.layout.removeWidget(widget) widget.setParent(None) for item in spider.contents: child_widget = HackerNewsItemWidget(self, item) self.widgets.append(child_widget) self.layout.addWidget(child_widget) def set_active_item(self, id): for child in self.widgets: if child.item['id'] == id: child.setStyleSheet(""" HackerNewsItemWidget { border-left: 3px solid #ff6600; } HackerNewsItemWidget #title { color: #fff; } """) else: child.setStyleSheet('')
class SubtableWidget(QWidget): def __init__(self, subtable, parent=None): super().__init__(parent) self.subtable = subtable self.subtable.setSelectionMode(QAbstractItemView.SingleSelection) self.subtable.setSelectionBehavior(QAbstractItemView.SelectRows) self.subtable.clicked.connect(self.row_selected) self.selected_row = 0 self.package = QVBoxLayout() self.toolBar = QToolBar() self.toolBar.setMovable(True) sub_up = QAction( QIcon("view/images/toolbar/baseline_expand_less_black_48dp.png"), "Up", self.subtable) sub_up.setStatusTip("Move one up") sub_up.triggered.connect(self.sub_up) sub_down = QAction( QIcon("view/images/toolbar/baseline_expand_more_black_48dp.png"), "Down", self.subtable) sub_down.setStatusTip("Move one down") sub_down.triggered.connect(self.sub_down) sub_first = QAction( QIcon("view/images/toolbar/baseline_first_page_black_48dp.png"), "Jump to first", self.subtable) sub_first.setStatusTip("Jump to first") sub_first.triggered.connect(self.sub_first) sub_last = QAction( QIcon("view/images/toolbar/baseline_last_page_black_48dp.png"), "Jump to last", self.subtable) sub_last.setStatusTip("Jump to last") sub_last.triggered.connect(self.sub_last) self.toolBar.addAction(QIcon("view/images/toolbar/list_48px.png"), "Manage Data") self.toolBar.addAction(QIcon("view/images/toolbar/add_new_40px.png"), "Add Data") self.toolBar.addAction(sub_first) self.toolBar.addAction(sub_up) self.toolBar.addAction(sub_down) self.toolBar.addAction(sub_last) self.toolBar.addAction( QIcon("view/images/toolbar/close_window_26px.png"), "Close") self.manageData2 = ManageData(self.subtable) self.addData2 = AddData(self.subtable) self.label = QLabel() self.label.setText("Work with data, choose state.") self.stacked_layout_2 = QVBoxLayout() self.stacked_layout_2.addStretch(0) self.toolBar.actionTriggered.connect(self.sub_toolbar_actions) self.package.addWidget(self.toolBar) self.package.addLayout(self.stacked_layout_2) self.package.addWidget(self.subtable) self.setLayout(self.package) def sub_toolbar_actions(self, action): if action.iconText() == "Manage Data": if self.stacked_layout_2.indexOf( self.addData2) == -1 and self.stacked_layout_2.indexOf( self.manageData2 ) == -1 and self.stacked_layout_2.indexOf( self.label) == -1: self.stacked_layout_2.addWidget(self.manageData2) self.manageData2.setVisible(True) return if self.stacked_layout_2.indexOf(self.addData2) != -1: self.stacked_layout_2.removeWidget(self.addData2) self.addData2.setVisible(False) self.stacked_layout_2.addWidget(self.manageData2) self.manageData2.setVisible(True) return if self.stacked_layout_2.indexOf(self.label) != -1: self.stacked_layout_2.removeWidget(self.label) self.label.setVisible(False) self.stacked_layout_2.addWidget(self.manageData2) self.manageData2.setVisible(True) return return elif action.iconText() == "Add Data": if self.stacked_layout_2.indexOf( self.addData2) == -1 and self.stacked_layout_2.indexOf( self.manageData2 ) == -1 and self.stacked_layout_2.indexOf( self.label) == -1: self.stacked_layout_2.addWidget(self.addData2) self.addData2.setVisible(True) return if self.stacked_layout_2.indexOf(self.manageData2) != -1: self.stacked_layout_2.removeWidget(self.manageData2) self.manageData2.setVisible(False) self.stacked_layout_2.addWidget(self.addData2) self.addData2.setVisible(True) return if self.stacked_layout_2.indexOf(self.label) != -1: self.stacked_layout_2.removeWidget(self.label) self.label.setVisible(False) self.stacked_layout_2.addWidget(self.addData2) self.addData2.setVisible(True) return return elif action.iconText() == "Close": if self.stacked_layout_2.indexOf( self.addData2) == -1 and self.stacked_layout_2.indexOf( self.manageData2 ) == -1 and self.stacked_layout_2.indexOf( self.label) == -1: self.stacked_layout_2.addWidget(self.label) self.label.setVisible(True) return if self.stacked_layout_2.indexOf(self.addData2) != -1: self.stacked_layout_2.removeWidget(self.addData2) self.addData2.setVisible(False) self.stacked_layout_2.addWidget(self.label) self.label.setVisible(True) return if self.stacked_layout_2.indexOf(self.manageData2) != -1: self.stacked_layout_2.removeWidget(self.manageData2) self.manageData2.setVisible(False) self.stacked_layout_2.addWidget(self.label) self.label.setVisible(True) return return def row_selected(self, index): self.selected_row = index.row() def sub_up(self): if self.selected_row != 0: self.selected_row -= 1 self.subtable.selectRow(self.selected_row) def sub_down(self): if self.selected_row < len(self.subtable.model().displayed_d) - 1: self.selected_row += 1 self.subtable.selectRow(self.selected_row) def sub_first(self): self.selected_row = 0 self.subtable.selectRow(self.selected_row) def sub_last(self): self.selected_row = len(self.subtable.model().displayed_d) - 1 self.subtable.selectRow(self.selected_row)
class ProcessListWidget(QScrollArea): action_requested = Signal(str, str) process_state_changed = Signal(str, str) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.process_data = set() self.process_widget_map = {} # type: Dict[str, ProcessWidget] self.main_widget = QWidget() self.process_layout = QVBoxLayout() self.process_layout.setContentsMargins(2, 2, 2, 2) self.main_widget.setLayout(self.process_layout) self.lbl_default = QLabel(text="No processes found") self.process_layout.addWidget(self.lbl_default) self.process_layout.addStretch() # Configure ScrollArea self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setWidgetResizable(True) self.setWidget(self.main_widget) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) def on_action_completed(self, response: ActionResponse): logger.info("Action completed: %s", response) self.process_widget_map[response.uid].on_action_completed( response.action) def update_single_process_state(self, event: StateChangedEvent): self.process_widget_map[event.uid].update_state( event.state, event.exit_code) def update_process_data(self, updated_process_data: Set[ProcessData]): potentially_updated = set() for process_data in updated_process_data: if process_data in self.process_data: potentially_updated.add(process_data) new_processes = updated_process_data - self.process_data unknown_processes = self.process_data - updated_process_data print(potentially_updated, new_processes, unknown_processes) # TODO(mark): update process data sets with new data for known_process in potentially_updated: widget = self.process_widget_map[known_process.uid] widget.on_update_process_data(known_process) for new_process in new_processes: widget = ProcessWidget(new_process) self.process_widget_map[new_process.uid] = widget widget.actionRequested.connect(self.action_requested) widget.process_state_changed.connect(self.process_state_changed) self.process_layout.insertWidget(0, widget) # TODO(mark): unknown processes for process in unknown_processes: widget = self.process_widget_map[process.uid] logger.info("Removing widget: %s", process.uid) self.process_layout.removeWidget(widget) del self.process_widget_map[process.uid] widget.deleteLater() self.process_data = new_processes | potentially_updated self.lbl_default.setVisible(len(self.process_data) == 0) return new_processes, unknown_processes
class MainPage(QMainWindow): activePackageWidgets = None def __init__(self): QMainWindow.__init__(self, MaxPlus.GetQMaxMainWindow()) self.resize(800, 600) self.setWindowTitle("Max Tools Updater") self.mainWidget = QWidget(self) self.central_layout = QVBoxLayout() menu_bar = QMenuBar() settingAct = QAction("&Settings", self) settingAct.setStatusTip("Open setting window") settingAct.connect(SIGNAL("triggered()"), self, SLOT("open()")) menu_bar.addAction(settingAct) self.mainWidget.setLayout(self.central_layout) self.central_layout.addWidget(menu_bar) self.tabs = QTabWidget() self.setCentralWidget(self.mainWidget) self.activePackageWidgets = list() def show(self, bringOnTop=None): self.loadPackagesTab() if bringOnTop: self.bringPackageOnTop(bringOnTop) QMainWindow.show(self) def closeEvent(self, event): for packageWidget in self.activePackageWidgets: packageWidget.closeQWebEngine() def open(self): self.settings_window = SettingsPage() self.settings_window.show() def loadPackagesTab(self): for i in range(self.tabs.count()): self.tabs.widget(i) self.tabs.removeTab(i) packagesConfigurationList = configuration.PackageConfiguration.readUserPackages( ) if not packagesConfigurationList: self.togglePackagesFoundDialog(True) else: self.togglePackagesFoundDialog(False) self.central_layout.addWidget(self.tabs) for i in range(len(packagesConfigurationList)): packageConfig = packagesConfigurationList[i] package_page = ptw.PackageTabView(packageConfig) self.activePackageWidgets.append(package_page) if package_page.isValid: self.tabs.addTab(package_page, packageConfig.package_name) else: logging.info("package" + packageConfig.package_name + "is not valid") def bringPackageOnTop(self, packageConfig): for i in range(self.tabs.count()): tab = self.tabs.widget(i) if tab.packageConfig.package_name == packageConfig.package_name: self.tabs.setCurrentWidget(tab) def togglePackagesFoundDialog(self, enabled): if enabled: no_packages_lbl = QLabel( "Ops...No packages found, please add a package from Settings Menu", self) no_packages_lbl.setAlignment(Qt.AlignHCenter) self.central_layout.addWidget(no_packages_lbl) no_packages_lbl.setObjectName("No_Package") else: no_packages_lbl = self.central_layout.findChild( QLabel, "No_Package") self.central_layout.removeWidget(no_packages_lbl)
class ViewWidget(QWidget): exercise_name_label = None exercise_name_line = None scroll_area = None base_widget = None exercises_widget = None return_button = None add_button = None def __init__(self): QWidget.__init__(self) self.file = "" self.setup_widget() def setup_widget(self): self.exercise_name_label = QLabel("Exercise name:", self) self.exercise_name_label.move(5, 5) self.exercise_name_label.resize(125, 25) self.add_button = QPushButton("Add", self) self.add_button.resize(75, 25) self.add_button.clicked.connect(self.add_line) self.exercise_name_line = QLineEdit(self) self.exercise_name_line.move(135, 5) self.exercise_name_line.resize(125, 25) self.scroll_area = QScrollArea(self) self.base_widget = QWidget(self) self.scroll_area.setWidget(self.base_widget) self.exercises_widget = QVBoxLayout() self.exercises_widget.setAlignment(Qt.AlignTop) self.base_widget.setLayout(self.exercises_widget) self.return_button = QPushButton("Return wo save", self) def resizeEvent(self, event): self.scroll_area.move(5, 35) self.scroll_area.resize(self.width() - 165, self.height() - 40) self.add_button.move(self.width() - 160 - 75, 5) self.return_button.move(self.width() - 155, 5) self.return_button.resize(150, 40) self.base_widget.resize(self.scroll_area.width() - 25, self.exercises_widget.count() * 25) def clear_widget(self): while self.exercises_widget.count() > 0: self.exercises_widget.takeAt(0) def open_exercise_file(self, file: str): self.file = file with open(self.file, "r") as json_file: json_data = json.load(json_file) name = json_data['name'] for data in json_data['exercise']: movement = data['name'] description = data['description'] time = data['time'] widget = PanelWidget() widget.set_data(movement, description, time) widget.remove_signal.connect(self.remove_panel_item) widget.move_down_signal.connect(self.move_widget_down) widget.move_up_signal.connect(self.move_widget_up) self.exercises_widget.addWidget(widget) json_file.close() self.base_widget.resize(self.scroll_area.width() - 25, self.exercises_widget.count() * 25) self.exercise_name_line.setText(name) @Slot() def add_line(self): widget = PanelWidget() self.exercises_widget.addWidget(widget) self.base_widget.resize(self.scroll_area.width() - 25, self.exercises_widget.count() * 25) @Slot(QWidget) def move_widget_down(self, widget: QWidget): ind = self.exercises_widget.indexOf(widget) self.exercises_widget.removeWidget(widget) self.exercises_widget.insertWidget((ind + 1), widget) @Slot(QWidget) def move_widget_up(self, widget: QWidget): ind = self.exercises_widget.indexOf(widget) self.exercises_widget.removeWidget(widget) self.exercises_widget.insertWidget((ind - 1), widget) @Slot(QWidget) def remove_panel_item(self, widget: QWidget): self.exercises_widget.removeWidget(widget) self.base_widget.resize(self.scroll_area.width() - 25, self.exercises_widget.count() * 25)
class FilelistWidget(QWidget): def __init__(self, parent=None): super(FilelistWidget, self).__init__(parent) self.setup_settings() self.setup_ui() def setup_settings(self): """Initialize widgets params. """ self.target_dir = './' self.re_pattern = '/*\.(jpg|jpeg|png|gif|bmp)' self.target_files_path = [] self.selected_idx = 0 def setup_ui(self): """Initialize widgets. """ # self.select_button = QPushButton("Open dir") # self.select_button.clicked.connect(self.select_dir) self.list_w = self.setup_list_ui() self.filelabel_list = [] self.filelist_layout = QVBoxLayout() # self.filelist_layout.addWidget(self.select_button) self.filelist_layout.addWidget(self.list_w) self.setLayout(self.filelist_layout) def setup_list_ui(self): self.filelabel_list = [] scroll = QScrollArea() scroll.setWidgetResizable(True) list_w = QWidget() vbox = QVBoxLayout() if self.target_files_path: for i, p in enumerate(self.target_files_path): label = FileLabelWidget(p, i) vbox.addWidget(label) self.filelabel_list.append(label) else: label = QLabel('Please select Directory!') vbox.addWidget(label) vbox.setAlignment(QtCore.Qt.AlignTop) list_w.setLayout(vbox) scroll.setWidget(list_w) return scroll def select_dir(self): dir_path = QFileDialog.getExistingDirectory( self, 'Select Directory', os.path.expanduser(self.target_dir)) if dir_path: self.target_dir = dir_path self.load_files() self.init_selected_idx() def load_files(self): self.target_files_path = path_list(self.target_dir, path_key='f', use_re=True, re_pattern=self.re_pattern) self.filelist_layout.removeWidget(self.list_w) self.list_w.deleteLater() self.list_w = self.setup_list_ui() self.filelist_layout.addWidget(self.list_w) def get_filepath(self, id): if self.target_files_path: return self.target_files_path[id] else: return None def get_selected_path(self): return self.get_filepath(self.selected_idx) def init_selected_idx(self): self.selected_idx = 0 def select_filepath(self, idx=None): if idx is None: if self.selected_idx != len(self.target_files_path) - 1: self.selected_idx += 1 return self.get_selected_path() else: return self.get_selected_path() else: self.selected_idx = idx return self.get_selected_path() def select_filepath_back(self, idx=None): if idx is None: if self.selected_idx != 0: self.selected_idx -= 1 return self.get_selected_path() else: return self.get_selected_path() else: self.selected_idx = idx return self.get_selected_path()
class NotificationsList(QWidget): READ_BACKGROUND_COLOR = "white" UNREAD_BACKGROUND_COLOR = "#eeeeee" WIDGET_BACKGROUND_COLOR = "darkGray" def __init__(self, dp, *args, **kwargs): QWidget.__init__(self, *args, **kwargs) self._dp = dp self._items = [] self._main_layout = QVBoxLayout(self) self._main_layout.setSpacing(2) self._main_layout.setContentsMargins(0, 0, 0, 0) self._main_layout.addStretch() self.setStyleSheet('background-color: {};'.format( self.READ_BACKGROUND_COLOR)) def show_notifications(self, notifications): items_count = len(self._items) for i, notification in enumerate(notifications): if i < items_count: self._update_n_list_item_widget(notification, self._items[i]) else: self._create_n_list_item_widget(notification) for i in range(items_count - 1, len(notifications) - 1, -1): self._main_layout.removeWidget(self._items[i]) self._items.pop() self.setStyleSheet('background-color: {};'.format( self.WIDGET_BACKGROUND_COLOR)) def loading_needed(self, limit): items_len = len(self._items) if items_len < limit: return True for widget in self._items[-limit:]: if not widget.visibleRegion().isEmpty(): return True return False def _create_n_list_item_widget(self, notification): widget = QWidget(parent=self) # widget.setFixedWidth(self.width()) widget.notification = notification main_layout = QVBoxLayout(widget) main_layout.setSpacing(2) text_label = QLabel(widget) widget.text_label = text_label text_label.setWordWrap(True) text_label.setFont(QFont('Noto Sans', 10 * self._dp)) text_label.setAlignment(Qt.AlignTop | Qt.AlignLeft) text_label.setText(notification.get_text()) main_layout.addWidget(text_label) time_label = QLabel(widget) widget.time_label = time_label time_label.setFont(QFont('Noto Sans', 8 * self._dp)) time_label.setAlignment(Qt.AlignTop | Qt.AlignRight) time_label.setText(notification.get_datetime()) main_layout.addWidget(time_label) self._set_background_color(widget, notification) def clicked(_): widget.notification.read() self._set_background_color(widget, widget.notification) widget.mouseReleaseEvent = clicked widget.text_label.mouseReleaseEvent = clicked widget.time_label.mouseReleaseEvent = clicked self._main_layout.insertWidget(len(self._items), widget) self._items.append(widget) def _update_n_list_item_widget(self, notification, widget): widget.notification = notification widget.text_label.setText(notification.get_text()) widget.time_label.setText(notification.get_datetime()) self._set_background_color(widget, notification) def _set_background_color(self, widget, notification): background_color = self.READ_BACKGROUND_COLOR \ if notification.is_read \ else self.UNREAD_BACKGROUND_COLOR widget.setStyleSheet('background-color: {};'.format(background_color))
class DBWorkspace(QWidget): def __init__(self, db, table, parent=None): super().__init__(parent) self.main_layout = QVBoxLayout() self.tab_widget = None self.handler = None self.db = db self.table = table self.table_model = None self.create_tab_widget() self.main_table = DBTableView(self.tab_widget) self.main_table.setSelectionMode(QAbstractItemView.SingleSelection) self.main_table.setSelectionBehavior(QAbstractItemView.SelectRows) self.init_table() self.main_table.clicked.connect(self.row_selected) self.package = QVBoxLayout() self.package.addStretch(1) self.toolBar = QToolBar() self.toolBar.setMovable(True) self.up = QAction( QIcon("view/images/toolbar/baseline_expand_less_black_48dp.png"), "Up", self.main_table) self.up.setStatusTip("Move one up") self.up.triggered.connect(self.jump_up) self.down = QAction( QIcon("view/images/toolbar/baseline_expand_more_black_48dp.png"), "Down", self.main_table) self.down.setStatusTip("Move one down") self.down.triggered.connect(self.jump_down) self.first = QAction( QIcon("view/images/toolbar/baseline_first_page_black_48dp.png"), "Jump to first", self.main_table) self.first.setStatusTip("Jump to first") self.first.triggered.connect(self.jump_to_first) self.last = QAction( QIcon("view/images/toolbar/baseline_last_page_black_48dp.png"), "Jump to last", self.main_table) self.last.setStatusTip("Jump to last") self.last.triggered.connect(self.jump_to_last) self.toolBar.addAction(QIcon("view/images/toolbar/list_48px.png"), "Manage Data") self.toolBar.addAction(QIcon("view/images/toolbar/add_new_40px.png"), "Add Data") self.toolBar.addAction(self.first) self.toolBar.addAction(self.up) self.toolBar.addAction(self.down) self.toolBar.addAction(self.last) self.toolBar.addAction( QIcon("view/images/toolbar/close_window_26px.png"), "Close") self.manageData = DBManageData(self.main_table) self.addData = DBAddData(self.main_table) self.stacked_layout = QVBoxLayout() self.label = QLabel() self.label.setText("Work with data, choose state.") self.toolBar.actionTriggered.connect(self.toolbar_actions) self.package.addWidget(self.toolBar) self.package.addLayout(self.stacked_layout) self.package.addWidget(self.main_table) self.main_layout.addLayout(self.package) self.selected_row = 0 self.main_layout.addStretch(2) self.setLayout(self.main_layout) def toolbar_actions(self, action): if action.iconText() == "Manage Data": if self.stacked_layout.indexOf( self.addData) == -1 and self.stacked_layout.indexOf( self.manageData) == -1 and self.stacked_layout.indexOf( self.label) == -1: self.stacked_layout.addWidget(self.manageData) self.manageData.setVisible(True) return if self.stacked_layout.indexOf(self.addData) != -1: self.stacked_layout.removeWidget(self.addData) self.addData.setVisible(False) self.stacked_layout.addWidget(self.manageData) self.manageData.setVisible(True) return if self.stacked_layout.indexOf(self.label) != -1: self.stacked_layout.removeWidget(self.label) self.label.setVisible(False) self.stacked_layout.addWidget(self.manageData) self.manageData.setVisible(True) return return elif action.iconText() == "Add Data": if self.stacked_layout.indexOf( self.addData) == -1 and self.stacked_layout.indexOf( self.manageData) == -1 and self.stacked_layout.indexOf( self.label) == -1: self.stacked_layout.addWidget(self.addData) self.addData.setVisible(True) return if self.stacked_layout.indexOf(self.manageData) != -1: self.stacked_layout.removeWidget(self.manageData) self.manageData.setVisible(False) self.stacked_layout.addWidget(self.addData) self.addData.setVisible(True) return if self.stacked_layout.indexOf(self.label) != -1: self.stacked_layout.removeWidget(self.label) self.label.setVisible(False) self.stacked_layout.addWidget(self.addData) self.addData.setVisible(True) return return elif action.iconText() == "Close": if self.stacked_layout.indexOf( self.addData) == -1 and self.stacked_layout.indexOf( self.manageData) == -1 and self.stacked_layout.indexOf( self.label) == -1: self.stacked_layout.addWidget(self.label) self.label.setVisible(True) return if self.stacked_layout.indexOf(self.addData) != -1: self.stacked_layout.removeWidget(self.addData) self.addData.setVisible(False) self.stacked_layout.addWidget(self.label) self.label.setVisible(True) return if self.stacked_layout.indexOf(self.manageData) != -1: self.stacked_layout.removeWidget(self.manageData) self.manageData.setVisible(False) self.stacked_layout.addWidget(self.label) self.label.setVisible(True) return return def row_selected(self, index): if index.column() == len(self.main_table.model().columns): model = self.main_table.model() selected_data = model.get_element(index) self.selected_row = index.row() def create_tab_widget(self): self.tab_widget = QTabWidget() self.tab_widget.setTabsClosable(True) self.tab_widget.tabCloseRequested.connect(self.delete_tab) def delete_tab(self, index): self.tab_widget.removeTab(index) def init_table(self): self.handler = DBHandler(self.db, self.table, self) self.table_model = DBTableModel(self.handler) self.main_table.setModel(self.table_model) """ Table navigation jumps """ def jump_up(self): if self.selected_row != 0: self.selected_row -= 1 self.main_table.selectRow(self.selected_row) def jump_down(self): if self.selected_row < len(self.main_table.model().displayed_d) - 1: self.selected_row += 1 self.main_table.selectRow(self.selected_row) def jump_to_first(self): self.selected_row = 0 self.main_table.selectRow(self.selected_row) def jump_to_last(self): self.selected_row = len(self.main_table.model().displayed_d) - 1 self.main_table.selectRow(self.selected_row) def sub_up(self): if self.selected_row != 0: self.selected_row -= 1 self.subtable.selectRow(self.selected_row) def sub_down(self): if self.selected_row < len(self.subtable.model().displayed_d) - 1: self.selected_row += 1 self.subtable.selectRow(self.selected_row) def sub_first(self): self.selected_row = 0 self.subtable.selectRow(self.selected_row) def sub_last(self): self.selected_row = len(self.subtable.model().displayed_d) - 1 self.subtable.selectRow(self.selected_row)
class DebugModulesWidget(QWidget, DockContextHandler): def __init__(self, parent, name, data): if not type(data) == binaryninja.binaryview.BinaryView: raise Exception('expected widget data to be a BinaryView') self.bv = data QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self.table = QTableView(self) self.model = DebugModulesListModel(self.table, data) self.table.setModel(self.model) self.item_delegate = DebugModulesItemDelegate(self) self.table.setItemDelegate(self.item_delegate) # self.table.setSortingEnabled(True) self.table.setSelectionBehavior( QAbstractItemView.SelectionBehavior.SelectRows) self.table.setSelectionMode(QAbstractItemView.ExtendedSelection) self.table.verticalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) self.table.verticalHeader().setVisible(False) self.table.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.resizeColumnsToContents() self.table.resizeRowsToContents() for i in range(len(self.model.columns)): self.table.setColumnWidth( i, self.item_delegate.sizeHint( self.table.viewOptions(), self.model.index(-1, i, QModelIndex())).width()) update_layout = QHBoxLayout() update_layout.setContentsMargins(0, 0, 0, 0) update_label = QLabel("Data is Stale") update_button = QPushButton("Refresh") update_button.clicked.connect(lambda: self.refresh()) update_layout.addWidget(update_label) update_layout.addStretch(1) update_layout.addWidget(update_button) self.update_box = QWidget() self.update_box.setLayout(update_layout) self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(0) self.layout.addWidget(self.table) self.setLayout(self.layout) def notifyOffsetChanged(self, offset): pass def refresh(self): debug_state = binjaplug.get_state(self.bv) debug_state.ui.update_modules() def notifyModulesChanged(self, new_modules): self.model.update_rows(new_modules) self.table.resizeColumnsToContents() self.layout.removeWidget(self.update_box) self.update_box.setVisible(False) def mark_dirty(self): self.layout.addWidget(self.update_box) self.update_box.setVisible(True) def contextMenuEvent(self, event): self.m_contextMenuManager.show(self.m_menu, self.actionHandler) def shouldBeVisible(self, view_frame): if view_frame is None: return False else: return True
class SemiAutoSignal(): def __init__(self, widget, main_widget, config, delete_backtest_tree_item, add_option_underlying, add_option_group, add_option_contract, no_support): self.parent = main_widget self.config = config self.mdi_area = self.parent.mdi_area self.root = self.parent.root self.group_box_widgets = [] backtest = widget self.backtest = backtest self.add_option_underlying = add_option_underlying self.add_option_group = add_option_group self.add_option_contract = add_option_contract self.no_support = no_support self.delete_backtest_tree_item = delete_backtest_tree_item self.group_box = backtest.findChild(QGroupBox, "backtest_box") self.group_box_layout = QVBoxLayout() self.group_box.setLayout(self.group_box_layout) self.backtest_tree = backtest.findChild(QTreeWidget, "backtest_tree") self.backtest_tree.setContextMenuPolicy(Qt.CustomContextMenu) self.backtest_tree.topLevelItem(0).setExpanded(True) add_option_underlying.triggered.connect(self.onAddOptionUnderlying) add_option_group.triggered.connect(self.onAddOptionGroup) add_option_contract.triggered.connect(self.onAddOptionContract) self.backtest_tree.itemDoubleClicked.connect( self.onBackTestTreeDoubleClicked) self.backtest_tree.customContextMenuRequested.connect( lambda event: self.onBackTestTreeRightClicked()) delete_backtest_tree_item.triggered.connect( self.onDeleteBackTestTreeItem) self.loadBacktestTree() def loadBacktestTree(self): options = self.config.get("options", {}) underlyings = options.get("underlyings", []) for i in range(1): item = self.backtest_tree.topLevelItem(i) item.setExpanded(True) for j in range(item.childCount()): child_item = item.child(j) child_item.setExpanded(True) whatsthis = child_item.whatsThis(0) if whatsthis == "option": for underlying in underlyings: current_item = child_item node = QTreeWidgetItem(current_item) node.setText(0, underlying["name"]) node.setCheckState(0, Qt.Unchecked) node.setWhatsThis(0, "option_underlying") node.setExpanded(True) data = underlying.get("id", {}).get("data", pd.DataFrame()) if not data.empty: id_dict = underlying.get("id", {}) name = id_dict["list"][id_dict["value"]] childSubWindow = { "title": "%s的当日合约", "type": "option_contract_table", "table_name": "%date%", "where": "", "select": id, "hidden_columns": [], "index_column": [], "childSubWindow": {}, } hidden_columns = [ 'total_turnover', 'limit_up', 'limit_down', 'settlement', 'prev_settlement', 'discount_rate', 'acc_net_value', 'unit_net_value', 'date', 'open_interest', 'iopv', 'num_trades' ] GridView(self.parent, name, data, id=name, hidden_columns=hidden_columns, index_column='date', childSubWindow=childSubWindow, type="option_underlying") current_item = node groups = underlying.get("groups", []) for group in groups: node = QTreeWidgetItem(current_item) node.setText(0, group["name"]) node.setCheckState(0, Qt.Unchecked) node.setIcon(0, QtGui.QIcon("../icon/group.png")) node.setWhatsThis(0, "option_group") node.setExpanded(True) current_item = node contracts = group.get("contracts") for contract in contracts: node = QTreeWidgetItem(current_item) node.setText(0, contract["name"]) node.setCheckState(0, Qt.Unchecked) node.setWhatsThis(0, "option_contract") node.setExpanded(True) current_item = node def onBackTestTreeDoubleClicked(self, item, column): self.setting_show(item, column) def onBackTestTreeRightClicked(self): menu = QMenu(self.backtest_tree) if self.backtest_tree.currentItem().whatsThis(0) == "option": # menu.addAction(self.add_option_underlying) else: whats_this = self.backtest_tree.currentItem().whatsThis(0) if whats_this == "option_underlying": menu.addAction(self.add_option_group) # menu.addAction(self.add_option_contract) menu.addAction(self.delete_backtest_tree_item) elif whats_this == "option_group": menu.addAction(self.add_option_contract) menu.addAction(self.delete_backtest_tree_item) elif whats_this == "option_contract": menu.addAction(self.delete_backtest_tree_item) else: menu.addAction(self.no_support) menu.popup(QtGui.QCursor.pos()) def onDeleteBackTestTreeItem(self): current_item = self.backtest_tree.currentItem() parent_item = current_item.parent() grand_parent_item = parent_item.parent() whats_this = current_item.whatsThis(0) parent_whats_this = parent_item.whatsThis(0) parent_item_text = parent_item.text(0) current_item_text = current_item.text(0) index = parent_item.indexOfChild(current_item) if whats_this == "option_group": for underlying in self.config["options"]["underlyings"]: if underlying.get("name") == parent_item_text: groups = underlying.get("groups") for group in groups: if group.get("name") == current_item_text: groups.remove(group) elif whats_this == "option_contract": #两种情况需要处理 if parent_whats_this == "option_underlying": for underlying in self.config["options"]["underlyings"]: if underlying.get("name") == parent_item_text: contracts = underlying.get("contracts") for contract in contracts: if contract.get("name") == current_item_text: contracts.remove(contract) elif parent_whats_this == "option_group": for underlying in self.config["options"]["underlyings"]: if underlying.get("name") == grand_parent_item.text(0): groups = underlying.get("groups") for group in groups: if group.get("name") == parent_item_text: contracts = group.get("contracts") for contract in contracts: if contract.get( "name") == current_item_text: contracts.remove(contract) elif whats_this == "option_underlying": underlyings = self.config["options"]["underlyings"] for underlying in underlyings: if underlying.get("name") == current_item_text: underlyings.remove(underlying) parent_item.takeChild(index) return def setting_show(self, item, column): while self.group_box_widgets: for i in self.group_box_widgets: i.hide() self.group_box_layout.removeWidget(i) self.group_box_widgets.remove(i) self.current_node = {} text = item.text(column) whats_this = item.whatsThis(column) if whats_this == "option": bt_type = "backtest_option" title = "期权设置" load_file = "backtest_option.ui" current_node = self.config["options"] self.current_node = current_node elif whats_this == "option_underlying": title = "标的 %s 的设置" % text load_file = "backtest_option_underlying.ui" bt_type = "backtest_option_underlying" current_node = [ i for i in self.config["options"]["underlyings"] if i["name"] == text ][0] self.current_node = current_node elif whats_this == "option_group": title = "期权组 %s 的设置" % text load_file = "backtest_option_group.ui" bt_type = "backtest_option_group" parent_item = item.parent() parent_item_text = parent_item.text(0) underlying_node = [ i for i in self.config["options"]["underlyings"] if i["name"] == parent_item_text ][0] current_node = [ i for i in underlying_node["groups"] if i["name"] == text ][0] self.current_node = current_node elif whats_this == "option_contract": title = "期权合约 %s 的设置" % text load_file = "backtest_option_contract.ui" bt_type = "backtest_option_contract" parent_item = item.parent() parent_item_text = parent_item.text(0) parent_item_whats_this = parent_item.whatsThis(column) if parent_item_whats_this == "option_group": grand_parent_item = parent_item.parent() grand_parent_item_text = grand_parent_item.text(0) underlying_node = \ [i for i in self.config["options"]["underlyings"] if i["name"] == grand_parent_item_text][0] group_node = [ i for i in underlying_node["groups"] if i["name"] == parent_item_text ][0] current_node = [ i for i in group_node["contracts"] if i["name"] == text ][0] self.current_node = current_node elif parent_item_whats_this == "option_underlying": underlying_node = [ i for i in self.config["options"]["underlyings"] if i["name"] == parent_item_text ][0] current_node = [ i for i in underlying_node["contracts"] if i["name"] == text ][0] self.current_node = current_node # elif whats_this == "strategy": # title = "策略基本设置" # load_file = "strategy.ui" # bt_type = "backtest_strategy" else: return loader = QUiLoader() setting_widget = loader.load(load_file) self.group_box.setTitle(title) self.group_box_layout.addWidget(setting_widget) self.group_box_widgets.append(setting_widget) # 连接各组件信号和展示数据 if whats_this == "option": ratio = setting_widget.findChild(QSpinBox, "ratio") ratio.setValue(self.current_node["ratio"]["value"]) ratio.valueChanged.connect( lambda event: self.onRatioChanged(event)) elif whats_this == "option_underlying": ratio = setting_widget.findChild(QSpinBox, "ratio") ratio.setValue(self.current_node["ratio"]["value"]) setting_widget.findChild(QSpinBox, "ratio").valueChanged.connect( lambda event: self.onRatioChanged(event)) underlying_list = setting_widget.findChild(QComboBox, "underlying_list") underlying_list.addItems(self.current_node["id"]["list"]) underlying_list.currentIndexChanged.connect( lambda event: self.onUnderlyingListChanged(event)) # underlying_list.setCurrentIndex(0) signal_list = setting_widget.findChild(QComboBox, "signal_list") # signal_list.setCurrentIndex(current_node["signal"]["value"]) ids = self.current_node["id"]["list"] if ids == []: self.parent.messageBox("没有数据") return _sub_window = self.parent.getSubWindowByAttribute("btId", ids[0]) if _sub_window is None: self.parent.messageBox("没有找到标的") return underlying_list.setCurrentIndex(self.current_node["id"]["value"]) columns = _sub_window.btData.columns signal_column = [i for i in columns if i.startswith("signal")] self.current_node["signal"]["list"] = signal_column signal_list.addItems(signal_column) signal_list.setCurrentIndex(self.current_node["signal"]["value"]) signal_list.currentIndexChanged.connect( lambda event: self.onSignalChanged(event)) side = setting_widget.findChild(QComboBox, "side") side.setCurrentIndex(self.current_node["option_side"]["value"]) side.currentIndexChanged.connect( lambda event: self.onOptionSideChanged(event)) volume = setting_widget.findChild(QSpinBox, "volume") volume.setValue(self.current_node["volume"]["value"]) volume.valueChanged.connect( lambda event: self.onVolumeChanged(event)) elif whats_this == "option_group": ratio = setting_widget.findChild(QSpinBox, "ratio") ratio.setValue(self.current_node["ratio"]["value"]) setting_widget.findChild(QSpinBox, "ratio").valueChanged.connect( lambda event: self.onRatioChanged(event)) elif whats_this == "option_contract": contract_type = setting_widget.findChild(QComboBox, "contract_type") contract_type.setCurrentIndex( self.current_node["option_type"]["value"]) contract_type.currentIndexChanged.connect( lambda event: self.onOptionContractTypeChanged(event)) option_side = setting_widget.findChild(QComboBox, "option_side") option_side.setCurrentIndex( self.current_node["option_side"]["value"]) option_side.currentIndexChanged.connect( lambda event: self.onOptionSideChanged(event)) close_strategy = setting_widget.findChild(QComboBox, "close_strategy") close_strategy.setCurrentIndex( self.current_node["close_method"]["value"]) close_strategy.currentIndexChanged.connect( lambda event: self.onCloseMethodChanged(event)) change_feq = setting_widget.findChild(QComboBox, "change_feq") change_feq.setCurrentIndex( self.current_node["change_feq"]["value"]) change_feq.currentIndexChanged.connect( lambda event: self.onChangeFeqChanged(event)) move_condition = setting_widget.findChild(QComboBox, "move_condition") move_condition.setCurrentIndex( self.current_node["change_condition"]["value"]) move_condition.currentIndexChanged.connect( lambda event: self.onChangeConditionChanged(event)) interval = setting_widget.findChild(QComboBox, "interval") interval.setCurrentIndex( self.current_node["month_interval"]["value"]) interval.currentIndexChanged.connect( lambda event: self.onMonthIntervalChanged(event)) strike_interval = setting_widget.findChild(QComboBox, "strike_interval") strike_interval.setCurrentIndex( self.current_node["strike_interval"]["value"]) strike_interval.currentIndexChanged.connect( lambda event: self.onStrikeIntervalChanged(event)) smart_match = setting_widget.findChild(QComboBox, "smart_match") smart_match.setCurrentIndex( self.current_node["smart_selection"]["value"]) smart_match.currentIndexChanged.connect( lambda event: self.onSmartSelectionChanged(event)) volume = setting_widget.findChild(QSpinBox, "volume") volume.setValue(self.current_node["volume"]["value"]) volume.valueChanged.connect( lambda event: self.onVolumeChanged(event)) deposit_ratio = setting_widget.findChild(QDoubleSpinBox, "deposit_ratio") deposit_ratio.setValue( self.current_node["deposit_coefficient"]["value"]) deposit_ratio.valueChanged.connect( lambda event: self.onDepositCoefficient(event)) delta = setting_widget.findChild(QDoubleSpinBox, "delta") delta.setValue(self.current_node["delta"]["value"]) delta.valueChanged.connect( lambda event: self.onDeltaChanged(event)) gamma = setting_widget.findChild(QDoubleSpinBox, "gamma") gamma.setValue(self.current_node["gamma"]["value"]) gamma.valueChanged.connect( lambda event: self.onGammaChanged(event)) theta = setting_widget.findChild(QDoubleSpinBox, "theta") theta.setValue(self.current_node["theta"]["value"]) theta.valueChanged.connect( lambda event: self.onThetaChanged(event)) vega = setting_widget.findChild(QDoubleSpinBox, "vega") vega.setValue(self.current_node["vega"]["value"]) vega.valueChanged.connect(lambda event: self.onVegaChanged(event)) rho = setting_widget.findChild(QDoubleSpinBox, "rho") rho.setValue(self.current_node["rho"]["value"]) rho.valueChanged.connect(lambda event: self.onRhoChanged(event)) ivix = setting_widget.findChild(QDoubleSpinBox, "ivix") ivix.setValue(self.current_node["ivix"]["value"]) ivix.valueChanged.connect(lambda event: self.onIvixChanged(event)) # elif whats_this == "strategy": # account_folder = os.path.normpath(os.path.join(ROOT, "accounts")) # account_files = [os.path.splitext(i)[0] for i in os.listdir(account_folder) if # os.path.splitext(i)[-1] == ".bt"] # account_list = sub_window_widget.findChild(QComboBox, "account") # account_list.addItems(account_files) # account_list.currentTextChanged.connect(lambda event:self.onBackTestRunAccountChanged(event)) # # open_type_list = sub_window_widget.findChild(QComboBox, "open_type") # open_type_list.currentIndexChanged.connect(lambda event: self.onBackTestOpenTypeChanged(event)) # # table_view = sub_window_widget.findChild(QTableWidget) # self.initBacktestAccountTable(table_view, account_files[0]) def onOptionContractTypeChanged(self, index): current_node = self.current_node current_node["option_type"]["value"] = index def onOptionSideChanged(self, index): current_node = self.current_node current_node["option_side"]["value"] = index def onCloseMethodChanged(self, index): current_node = self.current_node current_node["close_method"]["value"] = index def onChangeFeqChanged(self, index): current_node = self.current_node current_node["change_feq"]["value"] = index def onChangeConditionChanged(self, index): current_node = self.current_node current_node["change_condition"]["value"] = index def onMonthIntervalChanged(self, index): current_node = self.current_node current_node["month_interval"]["value"] = index def onStrikeIntervalChanged(self, index): current_node = self.current_node current_node["strike_interval"]["value"] = index def onSmartSelectionChanged(self, index): current_node = self.current_node current_node["smart_selection"]["value"] = index def onDepositCoefficient(self, value): current_node = self.current_node current_node["deposit_coefficient"]["value"] = value def onDeltaChanged(self, value): current_node = self.current_node current_node["delta"]["value"] = value def onGammaChanged(self, value): current_node = self.current_node current_node["gamma"]["value"] = value def onThetaChanged(self, value): current_node = self.current_node current_node["theta"]["value"] = value def onVegaChanged(self, value): current_node = self.current_node current_node["vega"]["value"] = value def onRhoChanged(self, value): current_node = self.current_node current_node["rho"]["value"] = value def onIvixChanged(self, value): current_node = self.current_node current_node["ivix"]["value"] = value def onRatioChanged(self, value): current_node = self.current_node current_node["ratio"]["value"] = value def onUnderlyingListChanged(self, index): current_node = self.current_node current_node["id"]["value"] = index text = current_node["id"]["list"][index] signal_list = self.mdi_area.currentSubWindow().findChild( QComboBox, "signal_list") signal_list.clear() sub_window = self.parent.getSubWindowByAttribute("btId", text) data = sub_window.btData signal_list.addItems( [i for i in data.columns if i.startswith("signal")]) def onVolumeChanged(self, value): current_node = self.current_node current_node["volume"]["value"] = value def onSignalChanged(self, index): current_node = self.current_node current_node["signal"]["value"] = index def onAddOptionUnderlying(self): text, ok = QInputDialog.getText(self.backtest, "请输入期权标的名称", "名称", QLineEdit.Normal) if ok and text: node = QTreeWidgetItem(self.backtest_tree.currentItem()) node.setText(0, text) node.setCheckState(0, Qt.Unchecked) node.setWhatsThis(0, "option_underlying") self.backtest_tree.expandItem(self.backtest_tree.currentItem()) ids = [ i.btId for i in self.mdi_area.subWindowList() if hasattr(i, "btType") and i.btType in ["option_underlying", "excel", "csv"] ] group_dict = { "name": text, "enable": 0, "ratio": { "type": "int", "value": 0, }, "id": { "type": "list", "value": 0, "list": ids, "data": getattr( self.parent.getSubWindowByAttribute("btId", ids[0]), "btData") }, "signal": { "type": "list", "value": 0, "list": [] }, "option_side": { "type": "list", "value": 0, "list": [u"买入"] }, "volume": { "type": "int", "value": 0, }, "groups": [], "contracts": [], } self.config["options"]["underlyings"].append(group_dict) def onAddOptionGroup(self): text, ok = QInputDialog.getText(self.backtest, "请输入期权组名称", "名称", QLineEdit.Normal) current_item = self.backtest_tree.currentItem() # parent_item = current_item.parent() current_item_text = current_item.text(0) # parent_item_text = parent_item.text(0) if ok and text: node = QTreeWidgetItem(current_item) node.setText(0, text) node.setCheckState(0, Qt.Unchecked) node.setWhatsThis(0, "option_group") node.setIcon(0, QtGui.QIcon("../icon/group.png")) self.backtest_tree.expandItem(self.backtest_tree.currentItem()) group_dict = { "name": text, "enable": 1, "contracts": [], "signal": { "type": "list", "value": 0, "list": [] }, "ratio": { "type": "float", "value": 0, }, } for underlying in self.config["options"]["underlyings"]: if underlying.get("name") == current_item_text: underlying["groups"].append(group_dict) def onAddOptionContract(self): text, ok = QInputDialog.getText(self.backtest, "请输入期权合约名称", "名称", QLineEdit.Normal) current_item = self.backtest_tree.currentItem() current_item_whats_this = current_item.whatsThis(0) current_item_text = current_item.text(0) parent_item = current_item.parent() parent_whats_this = parent_item.whatsThis(0) parent_item_text = parent_item.text(0) if ok and text: node = QTreeWidgetItem(current_item) node.setText(0, text) node.setCheckState(0, Qt.Unchecked) node.setWhatsThis(0, "option_contract") node.setIcon(0, QtGui.QIcon("../icon/contract.png")) self.backtest_tree.expandItem(self.backtest_tree.currentItem()) filter_dict = { "name": text, "enable": 1, "open_status": False, "ids": [], "option_type": { "type": "list", "value": 0, "list": setting.OPTION_TYPE, }, "option_side": { "type": "list", "value": 0, "list": setting.OPTION_SIDE, }, "close_method": { "type": "list", "value": 0, "list": setting.OPTION_CLOSE_METHOD, }, "change_feq": { "type": "list", "value": 0, "list": setting.OPTION_CHANGE_FEQ, }, "change_condition": { "type": "list", "value": 0, "list": setting.OPTION_CHANGE_CONDITION, }, "month_interval": { "type": "list", "value": 0, "list": [ setting.OPTION_INTERVAL[i] for i in range(len(setting.OPTION_INTERVAL)) if i != 2 ], }, "strike_interval": { "type": "list", "value": 0, "list": setting.OPTION_STRIKE_INTERVAL, }, "smart_selection": { "type": "list", "value": 1, "list": setting.OPTION_SMART_SELECTION, }, "type": "option", "volume": { "type": "int", "value": 0 }, "deposit_coefficient": { "type": "int", "value": 1, }, "delta": { "type": "int", "value": 0, }, "gamma": { "type": "int", "value": 0, }, "theta": { "type": "int", "value": 0, }, "vega": { "type": "int", "value": 0, }, "rho": { "type": "int", "value": 0, }, "ivix": { "type": "float", "value": 0 } } for underlying in self.config["options"]["underlyings"]: underlying_name = underlying.get("name") if current_item_whats_this == "option_group": if underlying_name == parent_item_text: groups = underlying.get("groups") for group in groups: if group.get("name") == current_item_text: group["contracts"].append(filter_dict) elif current_item_whats_this == "option_underlying": if underlying_name == current_item_text: underlying.get("contracts").append(filter_dict)
class Window(QWidget): def __init__(self): # call the constructor of the parent (QWidget) super().__init__() # check if it the first time for user to plot self.firstTime = False # set title and geometry for the window self.setWindowTitle("Function Plotter") self.setGeometry(500, 400, 400, 200) # give orange background to the window palette = self.palette() palette.setColor(QPalette.Window, QColor(150, 150, 150)) self.setPalette(palette) self.setAutoFillBackground(True) # set minimum width and height for the window self.setMinimumHeight(200) self.setMinimumWidth(400) self.setMaximumHeight(200) self.setMaximumWidth(400) # set icon for the application at run time and center the application window with the primary screen self.setIcon() self.center() # setup the grid layout design and components self.createGridLayout() self.vbox = QVBoxLayout() self.vbox.addWidget(self.groupBox) self.vbox.setAlignment(Qt.AlignCenter | Qt.AlignTop) self.setLayout(self.vbox) # set icon for the application def setIcon(self): appIcon = QIcon("icon.png") self.setWindowIcon(appIcon) # reading the data from text input and apply check tests def readData(self): # read the equation and check if there is an actual input equation = self.equationInput.text() if equation == '': self.aboutBox("Empty section", "Please enter an equation") return # remove spaces from the equation and check if the equation has valid variable name equation = removeSpaces(equation) varName, _ = getVariableName(equation) check, error = checkVarName(equation, varName) if not check: self.aboutBox("Wrong equation", error) return # check min and max value if it's a real number and the text input isn't empty maxValue = self.maxInput.text() if maxValue == '': self.aboutBox("Empty section", "Please enter maximum value") return try: maxValue = float(maxValue) except ValueError: self.aboutBox( "Wrong range", "Invalid value for maximum, please enter float or integer value" ) return minValue = self.minInput.text() if minValue == '': self.aboutBox("Empty section", "Please enter minimum value") return try: minValue = float(minValue) except ValueError: self.aboutBox( "Wrong range", "Invalid value for minimum, please enter float or integer value" ) return # the max value should be greater than min value if minValue >= maxValue: self.aboutBox("Wrong range", "Your maximum value should be greater than minimum") return # process the equation by trying to solve it with max value and check if there is error with operatos, operands or parentheses ops = trimTerms(equation, varName) temp_ops = replaceVar(ops, varName, str(maxValue)) testVal, error = functionCalculator(temp_ops) if error != None: self.aboutBox("Evaluation error", error) return # function to evaluate f(x) array and return f(x) and x lists to be plotted fx, x = self.evaluateFunction(ops, maxValue, minValue, varName) # plot the graph self.plotGraph(fx, x, varName) def plotGraph(self, fx, x, varName): # remove the old figure if user request another equation if self.firstTime: self.fig.clear() self.vbox.removeWidget(self.toolbar) self.vbox.removeWidget(self.canvas) # set first time to be True, to remove the old figures self.firstTime = True # set the figure and toolbar and add it to the window self.fig = Figure(figsize=(7, 5), dpi=65, facecolor=(1, 1, 1), edgecolor=(0, 0, 0)) self.canvas = FigureCanvas(self.fig) self.toolbar = NavigationToolbar(self.canvas, self) self.vbox.addWidget(self.toolbar) self.vbox.addWidget(self.canvas) # set new geometry to the window to fit the graph self.resize(400, 500) self.setMinimumHeight(500) self.setMaximumHeight(500) # plot the graph and set the labels self.ax = self.fig.add_subplot(111) self.ax.plot(x, fx) if varName == '': varName = 'x' self.ax.set_xlabel(varName) self.ax.set_ylabel('f(' + varName + ')') # QMessageBox which shows any error for the user def aboutBox(self, title, error): QMessageBox.about(self, title, error) def evaluateFunction(self, ops, maxVal, minVal, varName): # make array with start = minVal, end, maxVal and step for 0.25 for some accuracy x = np.arange(minVal, maxVal, 0.25) fx = [] # loop over each number(i) and evaluate f(i) then add it to f(x) list for number in x: temp_ops = replaceVar(ops, varName, number) val, _ = functionCalculator(temp_ops) fx.append(val) return fx, x # to center the application window at the beginning def center(self): qRect = self.frameGeometry() centerPoint = QtGui.QGuiApplication.primaryScreen().availableGeometry( ).center() qRect.moveCenter(centerPoint) self.move(qRect.topLeft()) def createGridLayout(self): # make group box with headline then add the gridlayout to it self.groupBox = QGroupBox("Please fill next sections") self.groupBox.setFont(QFont("Helvetica", 12)) self.groupBox.setMaximumWidth(400) self.groupBox.setMaximumHeight(200) # create gridlayout with spacing between columns and rows gridLayout = QGridLayout() gridLayout.setSpacing(10) # set equation text input self.equationInput = QLineEdit() self.equationInput.setMaximumHeight(30) #self.equationInput.setMaximumWidth(175) self.equationInput.setPlaceholderText("Enter your equation") gridLayout.addWidget(self.equationInput, 0, 0, 1, 0) # set max value text input self.maxInput = QLineEdit() self.maxInput.setMaximumHeight(30) self.maxInput.setMaximumWidth(175) self.maxInput.setPlaceholderText("Enter maximum value") gridLayout.addWidget(self.maxInput, 1, 0) # set min value text input self.minInput = QLineEdit() self.minInput.setMaximumHeight(30) self.minInput.setMaximumWidth(175) self.minInput.setPlaceholderText("Enter minimum value") gridLayout.addWidget(self.minInput, 1, 1) # set Plot push button with green color and an icon plotButton = QPushButton("Plot") plotButton.setStyleSheet("background-color: green") plotButton.setIcon(QIcon("curve.png")) plotButton.setMaximumHeight(30) plotButton.setMaximumWidth(75) # when button is clicked, call readData and then will plot the function plotButton.clicked.connect(self.readData) gridLayout.addWidget(plotButton, 2, 0) # add gridlayout to the group box self.setLayout(gridLayout) self.groupBox.setLayout(gridLayout)
class MainWidget(QWidget): def __init__(self): QWidget.__init__(self) self.lyt = QVBoxLayout() self.setLayout(self.lyt) #list of host & services self.table_main = QWidget() self.table_main_lyt = QVBoxLayout(self.table_main) self.info_table = QWidget() self.table_main_lyt.addWidget(self.info_table) self.lyt.addWidget(self.table_main) self.init_refresh() self.refresh() def init_refresh(self): self.refrsh_opt = QWidget() self.refrsh_opt_lyt = QHBoxLayout() self.refrsh_opt.setLayout(self.refrsh_opt_lyt) self.refrsh_btn = QPushButton() self.refrsh_btn.setIcon(self.style().standardIcon( QStyle.SP_BrowserReload)) self.refrsh_btn.clicked.connect(self.refresh) self.test1_btn = QPushButton() self.test1_btn.setIcon(self.style().standardIcon( QStyle.SP_BrowserReload)) self.test1_btn.clicked.connect(self.test1) self.refrsh_opt_lyt.addWidget(self.refrsh_btn) self.refrsh_opt_lyt.addWidget(self.test1_btn) self.lyt.addWidget(self.refrsh_opt) def test1(self): print("test") def refresh(self): print("Signal: refresh") self.netinfo = get_host_summary() self.table_main_lyt.removeWidget(self.info_table) self.info_table = QWidget() self.info_table_lyt = QGridLayout(self.info_table) self.table_main_lyt.addWidget(self.info_table) row = 0 col = 0 for iHeadline in ("Interface", "Mac", "Ip", "Hostname"): self.info_table_lyt.addWidget(QLabel("<b>" + iHeadline + "</b>"), row, col) col += 1 for iServiceName, iService in SERVICES.items(): self.info_table_lyt.addWidget( QLabel("<b>" + iServiceName + "</b>"), row, col) col += 1 row += 1 col = 0 for iHost in self.netinfo: self.info_table_lyt.addWidget(QLabel(str(iHost["dev"])), row, col) col += 1 self.info_table_lyt.addWidget(QLabel(str(iHost["mac"])), row, col) col += 1 self.info_table_lyt.addWidget(QLabel(str(iHost["ip"])), row, col) col += 1 if "hostname" in iHost: self.info_table_lyt.addWidget(QLabel(str(iHost["hostname"])), row, col) else: self.info_table_lyt.addWidget(QLabel(""), row, col) for iServiceName, iService in SERVICES.items(): col += 1 service_info = iHost["services"][iServiceName] if len(service_info) < 1: self.info_table_lyt.addWidget(QLabel("x"), row, col) continue widget = iService["display"].display(service_info) self.info_table_lyt.addWidget(widget, row, col) row += 1 col = 0
class FileSystemWidget(QWidget, DirectoryObserver): """ Widget for listing directory contents and download files from the RDP client. """ # fileDownloadRequested(file, targetPath, dialog) fileDownloadRequested = Signal(File, str, FileDownloadDialog) def __init__(self, root: Directory, parent: QObject = None): """ :param root: root of all directories. Directories in root will be displayed with drive icons. :param parent: parent object. """ super().__init__(parent) self.root = root self.breadcrumbLabel = QLabel() self.titleLabel = QLabel() self.titleLabel.setStyleSheet("font-weight: bold") self.titleSeparator: QFrame = QFrame() self.titleSeparator.setFrameShape(QFrame.HLine) self.listWidget = QListWidget() self.listWidget.setSortingEnabled(True) self.listWidget.setContextMenuPolicy(Qt.CustomContextMenu) self.listWidget.customContextMenuRequested.connect(self.onCustomContextMenu) self.verticalLayout = QVBoxLayout() self.verticalLayout.addWidget(self.breadcrumbLabel) self.verticalLayout.addWidget(self.listWidget) self.setLayout(self.verticalLayout) self.listWidget.itemDoubleClicked.connect(self.onItemDoubleClicked) self.currentPath: Path = Path("/") self.currentDirectory: Directory = root self.listCurrentDirectory() self.currentDirectory.addObserver(self) def setWindowTitle(self, title: str): """ Set the window title. When the title is not blank, a title label and a separator is displayed. :param title: the new title. """ previousTitle = self.windowTitle() super().setWindowTitle(title) self.titleLabel.setText(title) if previousTitle == "" and title != "": self.verticalLayout.insertWidget(0, self.titleLabel) self.verticalLayout.insertWidget(1, self.titleSeparator) elif title == "" and previousTitle != "": self.verticalLayout.removeWidget(self.titleLabel) self.verticalLayout.removeWidget(self.titleSeparator) # noinspection PyTypeChecker self.titleLabel.setParent(None) # noinspection PyTypeChecker self.titleSeparator.setParent(None) def onItemDoubleClicked(self, item: FileSystemItem): """ Handle double-clicks on items in the list. When the item is a directory, the current path changes and the contents of the directory are listed. Files are ignored. :param item: the item that was clicked. """ if not item.isDirectory() and not item.isDrive(): return if item.text() == "..": self.currentPath = self.currentPath.parent else: self.currentPath = self.currentPath / item.text() self.listCurrentDirectory() def listCurrentDirectory(self): """ Refresh the list widget with the current directory's contents. """ node = self.root for part in self.currentPath.parts[1 :]: node = next(d for d in node.directories if d.name == part) self.listWidget.clear() self.breadcrumbLabel.setText(f"Location: {str(self.currentPath)}") if node != self.root: self.listWidget.addItem(FileSystemItem("..", FileSystemItemType.Directory)) for directory in node.directories: self.listWidget.addItem(FileSystemItem(directory.name, directory.type)) for file in node.files: self.listWidget.addItem(FileSystemItem(file.name, file.type)) if node is not self.currentDirectory: self.currentDirectory.removeObserver(self) node.addObserver(self) self.currentDirectory = node node.list() def onDirectoryChanged(self): """ Refresh the directory view when the directory has changed. """ self.listCurrentDirectory() def currentItemText(self) -> str: try: return self.listWidget.selectedItems()[0].text() except IndexError: return "" def selectedFile(self) -> Optional[File]: text = self.currentItemText() if text == "": return None if text == "..": return self.currentDirectory.parent for sequence in [self.currentDirectory.files, self.currentDirectory.directories]: for file in sequence: if text == file.name: return file return None def canDownloadSelectedItem(self) -> bool: return self.selectedFile().type == FileSystemItemType.File def onCustomContextMenu(self, localPosition: QPoint): """ Show a custom context menu with a "Download file" action when a file is right-clicked. :param localPosition: position where the user clicked. """ selectedFile = self.selectedFile() if selectedFile is None: return globalPosition = self.listWidget.mapToGlobal(localPosition) downloadAction = QAction("Download file") downloadAction.setEnabled(selectedFile.type in [FileSystemItemType.File]) downloadAction.triggered.connect(self.downloadFile) itemMenu = QMenu() itemMenu.addAction(downloadAction) itemMenu.exec_(globalPosition) def downloadFile(self): file = self.selectedFile() if file.type != FileSystemItemType.File: return filePath = file.getFullPath() targetPath, _ = QFileDialog.getSaveFileName(self, f"Download file {filePath}", file.name) if targetPath != "": dialog = FileDownloadDialog(filePath, targetPath, self) dialog.show() self.fileDownloadRequested.emit(file, targetPath, dialog)
class DataDisplay(QWidget): def __init__(self, state, transactionList, monthCode, prevCode=None): QWidget.__init__(self) self.allTransactions = [] self.state = state self.addListeners() self.loadNewMonth(transactionList, monthCode, prevCode) def addListeners(self): self.state.addSubscriber(Events.transaction_drop_event, self.dropEvent) self.state.addSubscriber(Events.remove_category, self.removeCategory) self.state.addSubscriber(Events.update_category_total, self.updateConfigCategoryTotal) self.state.addSubscriber(Events.update_category_title, self.updateConfigCategoryName) self.state.addSubscriber(Events.add_category, self.addCategory) self.state.addSubscriber(Events.remove_all_categories, self.removeAllCategories) def onDestroy(self): self.state.removeSubscriber(Events.transaction_drop_event, self.dropEvent) self.state.removeSubscriber(Events.remove_category, self.removeCategory) self.state.removeSubscriber(Events.update_category_total, self.updateConfigCategoryTotal) self.state.removeSubscriber(Events.update_category_title, self.updateConfigCategoryName) self.state.removeSubscriber(Events.add_category, self.addCategory) self.state.removeSubscriber(Events.remove_all_categories, self.removeAllCategories) def addCategory(self, data): cfg = self.state.getConfig() if not data['title'] in cfg['months'][self.month]: amt = int(data['amt']) cfg['months'][self.month][data['title']] = { 'transactionList': [], 'total': amt } self.state.setConfig(cfg) idx = -1 if data['title'] == 'Income': idx = 0 else: for i, section in enumerate(self.sectionState): if int(section['total']) < amt: idx = i break self.sectionState.insert(idx, { 'name': data['title'], 'total': amt }) self.contentWrapperLayout.insertWidget( idx, Category(data['title'], amt, [], self.state)) self.updateTotalAmt() def loadNewMonth(self, transactionList, monthCode, prevCode=None, disableCredit=False): self.allTransactions = transactionList self.month = monthCode self.constructCategories(transactionList, monthCode, prevCode) self.updateTotalAmt() def constructCategories(self, transactionList, monthCode, prevCode): config = self.state.getConfig() if monthCode not in config['months']: if not config['months']: config['months'][monthCode] = {} else: prevCode = prevCode if prevCode else max( list(config['months'].keys())) # config option? config['months'][monthCode] = deepcopy( config['months'][prevCode]) formattedSections = { 'uncategorized': { 'tList': [], 'total': 0 }, 'income': { 'tList': [], 'total': 0 } } for transaction in transactionList: foundCategory = False if transaction.isCredit: formattedSections['income']['tList'].append(transaction) formattedSections['income']['total'] += transaction.amt else: for category in list(config['months'][monthCode].keys()): transactionList = config['months'][monthCode][category][ 'transactionList'] if not category in formattedSections.keys(): formattedSections[category] = {'tList': [], 'total': 0} if transaction.name in transactionList: foundCategory = True formattedSections[category]['tList'].append( transaction) formattedSections[category]['total'] += transaction.amt if not foundCategory: formattedSections['uncategorized']['tList'].append( transaction) formattedSections['uncategorized'][ 'total'] += transaction.amt def sortSection(x, y): if x == 'Income': return 1 if x == 'uncategorized': return -1 if formattedSections[x]['total'] < formattedSections[y]['total']: return -1 return 1 categoryKeys = sorted(list(formattedSections.keys()), key=cmp_to_key(sortSection), reverse=True) sectionsUI = [] self.sectionState = [] incomeCategory = None for category in categoryKeys: if category == 'income': if formattedSections['income']['total'] > 0: self.sectionState.append({ 'name': 'Income', 'total': formattedSections['income']['total'] }) incomeCategory = { 'title': 'Income', 'amt': formattedSections['income']['total'] } elif category == 'uncategorized': self.sectionState.append({ 'name': 'Uncategorized', 'total': '0' }) sectionsUI.append( Category('Uncategorized', 0, formattedSections['uncategorized']['tList'], self.state)) else: catTotal = config['months'][monthCode][category]['total'] self.sectionState.append({'name': category, 'total': catTotal}) sectionsUI.append( Category(category, catTotal, formattedSections[category]['tList'], self.state)) self.contentWrapperLayout = QVBoxLayout() for sectionLayout in sectionsUI: self.contentWrapperLayout.addWidget(sectionLayout) self.setLayout(self.contentWrapperLayout) self.state.setConfig(config) if incomeCategory: self.addCategory(incomeCategory) incomeCategoryWidget = self.getCategoryWidget('Income') incomeCategoryWidget.addTransactions( formattedSections['income']['tList']) def updateConfigCategoryTotal(self, name, amt): cfg = self.state.getConfig() cfg['months'][self.month][name]['total'] = amt self.state.setConfig(cfg) self.updateTotalAmt() def updateConfigCategoryName(self, name, newTitle): cfg = self.state.getConfig() cfg['months'][self.month][newTitle] = cfg['months'][self.month].pop( name) self.state.setConfig(cfg) def dropEvent(self, transactionTitle, destCategoryTitle): cfg = self.state.getConfig() sourceCat = self.getCategoryFromTransaction(cfg, transactionTitle) if not len(sourceCat) or sourceCat[0] != destCategoryTitle: transactionsToAdd = [] if len(sourceCat): oldList = cfg['months'][self.month][ sourceCat[0]]['transactionList'] newList = list(filter((transactionTitle).__ne__, oldList)) cfg['months'][self.month][ sourceCat[0]]['transactionList'] = newList transactionsToAdd += self.removeTransactionsFromCategory( transactionTitle, sourceCat[0]) else: transactionsToAdd += self.removeTransactionsFromCategory( transactionTitle, 'Uncategorized') if destCategoryTitle != 'Uncategorized': cfg['months'][self.month][destCategoryTitle][ 'transactionList'].append(transactionTitle) self.state.setConfig(cfg) categoryToAddTo = self.getCategoryWidget(destCategoryTitle) categoryToAddTo.addTransactions(transactionsToAdd) def removeTransactionsFromCategory(self, transactionTitle, title): i = 0 transactionsRemoved = [] curWidget = self.getCategoryWidget(title) j = 0 while j < len(curWidget.transactions): widgetTransaction = curWidget.transactions[j] if widgetTransaction.name == transactionTitle: transactionsRemoved.append(widgetTransaction) curWidget.removeTransaction(widgetTransaction) else: j += 1 return transactionsRemoved def getCategoryWidget(self, categoryName): i = 0 curWidget = self.contentWrapperLayout.itemAt(i) while (curWidget): if curWidget.widget().name == categoryName: return curWidget.widget() i += 1 curWidget = self.contentWrapperLayout.itemAt(i) def getCategoryFromTransaction(self, cfg, title): category = list( filter( lambda x: title in cfg['months'][self.month][x][ 'transactionList'], cfg['months'][self.month].keys())) return category def removeCategory(self, title, transactionList): cfg = self.state.getConfig() amt = cfg['months'][self.month][title]['total'] del cfg['months'][self.month][title] self.state.setConfig(cfg) i = 0 curWidget = self.contentWrapperLayout.itemAt(i) while (curWidget): if curWidget.widget().name == title: curWidget.widget().deleteLater() self.contentWrapperLayout.removeWidget(curWidget.widget()) self.sectionState.remove({'name': title, 'total': amt}) elif curWidget.widget().name == 'Uncategorized': curWidget.widget().addTransactions(transactionList) i += 1 else: i += 1 curWidget = self.contentWrapperLayout.itemAt(i) self.updateTotalAmt() def removeAllCategories(self): cfg = self.state.getConfig() allCategories = cfg['months'][self.month].keys() for category in allCategories: categoryTransactions = self.getCategoryWidget( category).getTransactions() self.removeCategory(category, categoryTransactions) def getTotalAmt(self): totalAmt = 0 for transaction in self.allTransactions: # totalAmt += (-1 * transaction.amt) if transaction.isCredit else transaction.amt totalAmt += 0 if transaction.isCredit else transaction.amt return round(totalAmt, 2) def sumCategories(self): cfg = self.state.getConfig() sum = 0 categories = list(cfg['months'][self.month].keys()) for category in categories: categoryTotal = cfg['months'][self.month][category]['total'] # sum += categoryTotal if category != 'Income' else -categoryTotal sum += categoryTotal if category != 'Income' else 0 return sum def updateTotalAmt(self): categorySum = self.sumCategories() transactionSum = self.getTotalAmt() self.state.next(Events.update_total, transactionSum, categorySum)
class ImageToPdfWidget(QWidget): def __init__(self, status_link): super(ImageToPdfWidget, self).__init__() LABEL_WIDTH = 80 self.last_selected_items = [] self.options_mode = 0 self.update_status_combobox = False layout = QHBoxLayout() self.status_bar = status_link self.list_view = QListWidget() self.list_view.setSelectionMode(QAbstractItemView.ExtendedSelection) self.list_view.setAlternatingRowColors(True) self.list_view.itemClicked.connect(self.click_item_signal) self.list_view.itemEntered.connect(self.click_item_signal) self.list_view.itemSelectionChanged.connect( self.change_selection_signal) controls_layout = QVBoxLayout() controls_layout.setAlignment(Qt.AlignTop) select_zone = SelectWidget(self.click_move_up, self.click_move_down, self.click_invert, self.click_delete) # options zone ------------------------------------- options_zone = QGroupBox("Options") self.options_zone_layout = QVBoxLayout() self.options_mode_combobox = QComboBox() self._add_items_to_mode_combobox(self.options_mode_combobox) options_mode_label = QLabel("Mode") options_mode_label.setMaximumWidth(LABEL_WIDTH) options_mode_layout = QHBoxLayout() options_mode_layout.addWidget(options_mode_label) options_mode_layout.addWidget(self.options_mode_combobox) self.options_zone_layout.addLayout(options_mode_layout) self.option_source_widget = OptionsFromSourceWidget( label_width=LABEL_WIDTH, status_bar=self.status_bar) self.options_a_widget = OptionsAWidget(label_width=LABEL_WIDTH, status_bar=self.status_bar) self.options_mode_combobox.currentIndexChanged.connect( self.change_options_mode_signal) self.change_options_mode_signal(self.options_mode) options_zone.setLayout(self.options_zone_layout) # Add files button and final structures --------------------------- add_file_button = QPushButton("Add Files") add_file_button.clicked.connect(self.click_add_files) controls_layout.addWidget(select_zone) controls_layout.addWidget(options_zone) controls_layout.addWidget(add_file_button) # image preview --------------------------------------------------- image_prev_layout = QVBoxLayout() image_prev_layout.setContentsMargins(0, 0, 4, 0) self.IMG_PREVIEW_WIDTH = 256 self.img_label = QLabel() self.img_label.setAlignment(Qt.AlignCenter) self.select_text = "Click item to preview" self.last_created_pix_path = "" self.img_label.setText(self.select_text) image_prev_layout.addWidget(self.img_label) # slider for the preview scale self.img_scale_slider = QSlider() self.img_scale_slider.setMinimum(6) self.img_scale_slider.setMaximum(2048) self.img_scale_slider.setValue(self.IMG_PREVIEW_WIDTH) self.img_scale_slider.setOrientation(Qt.Horizontal) self.img_scale_slider.valueChanged.connect( self.change_scale_slider_signal) image_prev_layout.addWidget(self.img_scale_slider) self._update_preview() layout.addLayout(image_prev_layout) layout.addWidget(self.list_view) layout.addLayout(controls_layout) self.setLayout(layout) self.update_status_combobox = True def _pillow_to_pixmap(self, img): if img.mode == "RGB": r, g, b = img.split() img = Image.merge("RGB", (b, g, r)) elif img.mode == "RGBA": r, g, b, a = img.split() img = Image.merge("RGBA", (b, g, r, a)) elif img.mode == "L": img = img.convert("RGBA") img2 = img.convert("RGBA") data = img2.tobytes("raw", "RGBA") qim = QImage(data, img.size[0], img.size[1], QImage.Format_ARGB32) pixmap = QPixmap.fromImage(qim) return pixmap def _update_preview(self): self.img_label.setMinimumWidth(self.IMG_PREVIEW_WIDTH) self.img_label.setMaximumWidth( max(self.IMG_PREVIEW_WIDTH, self.img_scale_slider.width())) if len(self.last_created_pix_path) > 0: img = Image.open(self.last_created_pix_path) img_pix = self._pillow_to_pixmap(img) img_pix = img_pix.scaled( QSize(self.IMG_PREVIEW_WIDTH, self.IMG_PREVIEW_WIDTH), Qt.KeepAspectRatio) self.img_label.setPixmap(img_pix) def _set_preview(self, img_path): if img_path is None: self.last_created_pix_path = "" self.img_label.setText(self.select_text) else: if img_path != self.last_created_pix_path: self.last_created_pix_path = img_path self._update_preview() def _add_items_to_mode_combobox(self, combobox): combobox.addItem("From Source") combobox.addItem("A4") # combobox.addItem("A5") # combobox.addItem("A6") # combobox.addItem("Letter") def _get_filtered_string(self, string): to_return_array = [] for s in string: if s.isdigit(): to_return_array.append(s) return "".join(to_return_array) def get_images_to_save(self): path_array = [] for i in range(self.list_view.count()): path_array.append(self.list_view.item(i).get_data()) return path_array def get_image_parameters(self): # return as dictionary if self.options_mode == 0: return { "mode": 0, "pixels": self.option_source_widget.get_pixel_value(), "margin": self.option_source_widget.get_margin_value(), "background": self.option_source_widget.get_background_value() } else: return { "mode": self.options_mode, "align": self.options_a_widget.get_align_value(), "margin": self.options_a_widget.get_margin_value(), "background": self.options_a_widget.get_background_value() } def add_items(self, array): added_names = [] for a in array: new_name = os.path.basename(a) new_item = ImageListItem(new_name, a) added_names.append(new_name) self.list_view.addItem(new_item) self.status_bar.showMessage("Add items: " + ", ".join(added_names)) def change_scale_slider_signal(self, value): self.IMG_PREVIEW_WIDTH = value self._update_preview() self.status_bar.showMessage("Set preview scale to " + str(value)) def click_item_signal(self, item): pass # self._set_preview(item.get_data()) # self.status_bar.showMessage("Select " + str(item.text())) def _get_first_new_index(self, current, last): for v in current: if v not in last: return v return current[0] def change_selection_signal(self): if len(self.list_view.selectedItems()) == 0: self._set_preview(None) # nothing selected else: selected_indexes = [ self.list_view.indexFromItem(sel).row() for sel in self.list_view.selectedItems() ] item = self.list_view.item( self._get_first_new_index(selected_indexes, self.last_selected_items)) self._set_preview(item.get_data()) self.status_bar.showMessage("Select " + str(item.text())) self.last_selected_items = selected_indexes def change_options_mode_signal(self, index): self.options_mode = index if self.options_mode == 0: self.options_zone_layout.removeWidget(self.options_a_widget) self.options_a_widget.setParent(None) self.options_zone_layout.addWidget(self.option_source_widget) else: self.options_zone_layout.removeWidget(self.option_source_widget) self.option_source_widget.setParent(None) self.options_zone_layout.addWidget(self.options_a_widget) if self.update_status_combobox: self.status_bar.showMessage( "Set combine mode to \"" + self.options_mode_combobox.itemText(index) + "\"") def resizeEvent(self, size): # self._update_preview() pass def click_move_up(self): selected = self.list_view.selectedItems() selected_indexes = [ self.list_view.indexFromItem(sel).row() for sel in selected ] selected_indexes.sort() if len(selected_indexes) > 0 and selected_indexes[0] > 0: for index in selected_indexes: prev_item = self.list_view.takeItem(index - 1) self.list_view.insertItem(index, prev_item) self.status_bar.showMessage("Move " + str(len(selected_indexes)) + " items") else: self.status_bar.showMessage("Nothing to move") def click_move_down(self): selected = self.list_view.selectedItems() selected_indexes = [ self.list_view.indexFromItem(sel).row() for sel in selected ] selected_indexes.sort() sel_count = len(selected_indexes) if len(selected_indexes) > 0 and selected_indexes[ sel_count - 1] < self.list_view.count() - 1: for i_index in range(sel_count): next_item = self.list_view.takeItem( selected_indexes[sel_count - i_index - 1] + 1) self.list_view.insertItem( selected_indexes[sel_count - i_index - 1], next_item) self.status_bar.showMessage("Move " + str(len(selected_indexes)) + " items") else: self.status_bar.showMessage("Nothing to move") def click_invert(self): selected = self.list_view.selectedItems() selected_indexes = [] for sel in selected: selected_indexes.append(self.list_view.indexFromItem(sel).row()) total_indexes = [i for i in range(self.list_view.count())] new_indexes = [] for i in total_indexes: if i not in selected_indexes: new_indexes.append(i) self.list_view.clearSelection() for i in new_indexes: self.list_view.item(i).setSelected(True) self.status_bar.showMessage("Invert selection: " + str(new_indexes)) def click_delete(self): selected = self.list_view.selectedItems() delete_names = [] for s in selected: s_index = self.list_view.indexFromItem(s).row() del_item = self.list_view.takeItem(s_index) delete_names.append(del_item.text()) if len(delete_names) == 0: self.status_bar.showMessage("Nothing to delete") else: self.status_bar.showMessage("Delete items: " + ", ".join(delete_names)) def click_add_files(self): files_dialog = QFileDialog() files_dialog.setNameFilter("Images (*.jpg *.jpeg *.bmp *.png *.tiff)") files_dialog.setFileMode(QFileDialog.ExistingFiles) if files_dialog.exec_(): files = files_dialog.selectedFiles() self.add_items(files)
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self, parent=None) self.settings = QSettings(ORGANIZATION_STR) self.toolbar = self.createToolBar() self.widget = QWidget(self) self.layout = QVBoxLayout(self.widget) self.layout.setContentsMargins(1, 1, 1, 1) self.currentWidget = None self.editor = QTextEdit() self.editor.setAcceptRichText(False) font = QFontDatabase.systemFont(QFontDatabase.FixedFont) fs = int(self.settings.value("fontSize", 13)) font.setPointSize(fs) self.editor.setFont(font) self.preview = MarkdownRenderer() self.layout.addWidget(self.toolbar) self.widget.setLayout(self.layout) self.showWidget(self.editor) self.addToolBar(self.toolbar) self.setCentralWidget(self.widget) self.setWindowTitle(BASIC_TITLE) self.nbManager = NotebookManager() self.currentNotebook = None self.currentNote = None self.dirty = False self.editor.document().modificationChanged.connect(self.editorModified) self.updateUI() if len(self.nbManager.notebooks()) > 0: self.switchNotebook(self.nbManager.notebooks()[0].name) self.createTrayIcon() self.readConfig() def closeEvent(self, event): self.nbManager.writeConfig() self.writeConfig() QMainWindow.closeEvent(self, event) def showWidget(self, w): if self.currentWidget is not None: self.currentWidget.hide() self.layout.removeWidget(self.currentWidget) self.layout.addWidget(w) #self.layout.update() self.currentWidget = w self.currentWidget.show() def createToolBar(self): toolbar = QToolBar() act = toolbar.addAction(QIcon.fromTheme("document-new"), "Create a new note", self.newNote) act.setShortcut(QKeySequence.New) toolbar.addAction(QIcon.fromTheme("folder-new"), "Create a new notebook", self.newNotebook) toolbar.addSeparator() act = toolbar.addAction(QIcon.fromTheme("document-save"), "Save changes to current note", self.saveNote) act.setShortcut(QKeySequence.Save) toolbar.addAction(QIcon.fromTheme("document-send"), "Export current note") toolbar.addSeparator() toolbar.addAction(QIcon.fromTheme("format-text-bold"), "Bold") toolbar.addAction(QIcon.fromTheme("format-text-italic"), "Italic") toolbar.addAction(QIcon.fromTheme("format-text-underline"), "Underline") self.headingsCombo = QComboBox() self.headingsCombo.addItem("H1") self.headingsCombo.addItem("H2") self.headingsCombo.addItem("H3") self.headingsCombo.addItem("H4") self.headingsCombo.addItem("H5") self.headingsCombo.addItem("H6") toolbar.addWidget(self.headingsCombo) toolbar.addSeparator() toolbar.addAction(QIcon.fromTheme("format-list-unordered"), "Insert bulleted list") toolbar.addAction(QIcon.fromTheme("format-list-ordered"), "Insert numbered list") toolbar.addAction(QIcon.fromTheme("insert-link"), "Inserts a link") toolbar.addSeparator() self.editableAction = toolbar.addAction( QIcon.fromTheme("edit"), "Toggle edit or markdown visualizer") self.editableAction.setCheckable(True) self.editableAction.setChecked(True) self.editableAction.setShortcut(QKeySequence("Ctrl+E")) QObject.connect(self.editableAction, SIGNAL('triggered(bool)'), self.editTriggered) toolbar.addAction(QIcon.fromTheme("system-search"), "Search") self.notebooksCombo = QComboBox() self.notebooksCombo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.notebooksCombo.addItem(QIcon.fromTheme("folder"), "Create new notebook") self.notesCombo = QComboBox() self.notesCombo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) QObject.connect(self.notebooksCombo, SIGNAL("activated(QString)"), self.switchNotebook) QObject.connect(self.notesCombo, SIGNAL("activated(QString)"), self.switchNote) self.spacer = QWidget() self.spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) toolbar.addWidget(self.spacer) toolbar.addWidget(self.notebooksCombo) toolbar.addWidget(self.notesCombo) return toolbar def createTrayIcon(self): path = os.path.join( pathlib.Path(__file__).parent.absolute(), "icons/notes.svg") icon = QIcon(QPixmap(path)) self.trayIcon = QSystemTrayIcon(icon, self) self.trayMenu = None QObject.connect(self.trayIcon, SIGNAL("activated(QSystemTrayIcon::ActivationReason)"), self.trayIconActivated) self.populateTrayMenu() self.trayIcon.show() def trayIconActivated(self, reason): if reason != QSystemTrayIcon.Trigger: return if self.isVisible(): self.savedGeometry = self.saveGeometry() self.hide() else: self.show() self.activateWindow() self.restoreGeometry(self.savedGeometry) def populateTrayMenu(self): del self.trayMenu self.trayMenu = QMenu() self.trayMenu.addAction(QIcon.fromTheme("folder-new"), "Create a new notebook", self.newNotebook) self.trayMenu.addSeparator() for notebook in self.nbManager.notebooks(): nbMenu = self.trayMenu.addMenu(QIcon.fromTheme("folder"), notebook.name) nbMenu.addAction(QIcon.fromTheme("document-new"), "Create a new note", self.newNote) nbMenu.addSeparator() for note in notebook.notes(): nbMenu.addAction(QIcon.fromTheme("text-x-generic"), note.name) self.trayMenu.addSeparator() self.trayMenu.addAction(QIcon.fromTheme("application-exit"), "&Quit", QApplication.instance().quit) self.trayIcon.setContextMenu(self.trayMenu) def editTriggered(self, checked): if checked: self.showWidget(self.editor) else: self.preview.displayMarkdown(self.editor.toPlainText()) self.showWidget(self.preview) def readConfig(self): if self.settings.contains("geometry"): geometry = self.settings.value("geometry") self.restoreGeometry(geometry) def writeConfig(self): geometry = self.saveGeometry() self.settings.setValue("geometry", geometry) def updateUI(self): self.notebooksCombo.clear() for notebook in self.nbManager.notebooks(): self.notebooksCombo.addItem(QIcon.fromTheme("folder"), notebook.name) if self.currentNotebook is not None: self.notesCombo.clear() for note in self.currentNotebook.notes(): self.notesCombo.addItem(QIcon.fromTheme("text-x-generic"), note.name) if self.currentNotebook is not None and self.currentNote is not None: title = BASIC_TITLE + " - {}/{}".format(self.currentNotebook.name, self.currentNote.name) if self.dirty: title += " (Modified)" else: title = BASIC_TITLE self.setWindowTitle(title) def switchNotebook(self, notebookName): self.currentNotebook = self.nbManager.notebook(notebookName) self.updateUI() # If notebook not empty, switch to first note. if len(self.currentNotebook.notes()) > 0: self.switchNote(self.currentNotebook.notes()[0].name) # If not, request creation of a new note else: self.newNote() self.notebooksCombo.setCurrentText(notebookName) def switchNote(self, noteName): self.currentNote = self.currentNotebook.note(noteName) self.editor.setPlainText(self.currentNote.contents) self.preview.displayMarkdown(self.currentNote.contents) self.updateUI() self.notesCombo.setCurrentText(noteName) def newNotebook(self): name, ok = QInputDialog.getText( self, "Notebook name", "How would you like your notebook to be named?") if ok: storagePath = QDir.homePath() + "/.config/wikinotebook/" + name nb = self.nbManager.createNewNotebook(name, storagePath) self.switchNotebook(nb.name) def newNote(self): if self.currentNotebook is None: return name, ok = QInputDialog.getText( self, "Note name", "How would you like your note to be named?") if ok: note = self.currentNotebook.createNewNote(name) self.switchNote(note.name) def saveNote(self): self.currentNote.contents = self.editor.toPlainText() self.currentNote.save() self.dirty = False self.editor.document().setModified(False) self.updateUI() def editorModified(self, changed): self.dirty = changed self.updateUI()