class MultipleTextEntry(Dialog): def __init__(self, parent, title, values): Dialog.__init__(self, parent, title=title, style=DEFAULT_DIALOG_STYLE | RESIZE_BORDER) self.values = None sizer = GridBagSizer(5, 5) row = 0 self.labels = [] self.txt_ctrls = [] for value in values: label = StaticText(self, label=value) self.labels.append(label) sizer.Add(label, pos=(row, 0), flag=ALIGN_RIGHT) txtctrl = TextCtrl(self) self.txt_ctrls.append(txtctrl) sizer.Add(txtctrl, pos=(row, 1), flag=FLAG_ALL_AND_EXPAND) row += 1 self.btn_cancel = Button(self, label=u'Cancel') self.btn_cancel.Bind(EVT_BUTTON, self.__on_btn) sizer.Add(self.btn_cancel, pos=(row, 0), flag=FLAG_ALL_AND_EXPAND) self.btn_ok = Button(self, label=u'OK') self.btn_ok.Bind(EVT_BUTTON, self.__on_btn) sizer.Add(self.btn_ok, pos=(row, 1), flag=FLAG_ALL_AND_EXPAND) sizer.AddGrowableCol(1) self.SetSizerAndFit(sizer) self.SetSize(400, self.GetSizeTuple()[1]) def __on_btn(self, evt): errors = [] obj = evt.GetEventObject() if obj == self.btn_ok: self.values = {} for txt_ctrl in self.txt_ctrls: label_ctrl = self.labels[self.txt_ctrls.index(txt_ctrl)] label = label_ctrl.GetLabel() value = txt_ctrl.GetValue() self.values[label] = value if len(value) == 0: errors.append(u"Variable '%s' has empty value '%s'" % (label, value)) return_code = ID_OK else: self.values = None return_code = ID_CANCEL if len(errors) > 0: show_dialog(self, LINESEP.join(errors), 'Bad entered data') else: self.EndModal(return_code)
def __init__(self, ch: int, channel_label: wx.StaticText, waveform_choice: wx.Choice, trigger_choice: wx.Choice, continuous_toggle: wx.ToggleButton, trigger_button: wx.Button, stop_button: wx.Button, trigger_out_check: wx.CheckBox, status_text: wx.TextCtrl, mf): self.ch = ch self.mf = mf self.channel_label = channel_label self.channel_name = channel_label.GetLabel() self.waveform_choice = waveform_choice self.waveform_choice.Bind(wx.EVT_CHOICE, self.on_waveform_choice) self.trigger_choice = trigger_choice self.trigger_choice.Bind(wx.EVT_CHOICE, self.on_trigger_source) self.continuous_toggle = continuous_toggle self.continuous_toggle.Bind(wx.EVT_TOGGLEBUTTON, self.on_toggle) self.trigger_button = trigger_button trigger_button.Bind(wx.EVT_BUTTON, lambda _: mf.device.trigger_channel(ch)) self.stop_button = stop_button self.stop_button.Bind( wx.EVT_BUTTON, lambda evt: mf.device.set_enable( ch, stop_button.GetLabel() == 'Enable')) self.trigger_out_check = trigger_out_check self.status_text = status_text self.waveform = 'Waveform 1' self.trigger = 0 self.continuous = 0 self._enabled = False self.output = False self.warnings = [] self.modified = False
def button(element, instance: wx.Button): props = element['props'] set_basic_props(instance, props) instance.Unbind(wx.EVT_BUTTON) if props.get('on_click'): instance.Bind(wx.EVT_BUTTON, props['on_click']) return instance
def __init__(self, message: str, label: str = None, url: str = None, **kwargs) -> None: super(HyperlinkDialog, self).__init__(parent=None, **kwargs) pane = self.GetContentsPane() text_ctrl = StaticText(pane, label=message) text_ctrl.SetFocus() text_ctrl.SetSizerProps(align="center") if url is not None: if label is None: label = url hyperlink = HyperlinkCtrl(pane, label=label, url=url) hyperlink.Bind(EVT_HYPERLINK, self.on_hyperlink) button_ok = Button(pane, label="OK") button_ok.Bind(EVT_BUTTON, self.on_ok) button_ok.SetSizerProps(align="center", border=(["top"], 10)) self.SetIcon( Icon(ArtProvider.GetBitmap(ART_INFORMATION, ART_MESSAGE_BOX))) self.Fit() self.Centre()
class DialogWithText(Dialog): def __init__(self, parent, title, text=None): Dialog.__init__(self, parent, title=title, style=DEFAULT_DIALOG_STYLE | RESIZE_BORDER) self.SetTitle(title) self.SetSize(600, 400) sizer = BoxSizer(VERTICAL) self.txt_ctrl = TextCtrl(self, style=TE_MULTILINE | TE_READONLY | HSCROLL) if text: self.txt_ctrl.SetValue(text) sizer.Add(self.txt_ctrl, 1, flag=FLAG_ALL_AND_EXPAND) self.btn_ok = Button(self, label=u'OK') self.btn_ok.Bind(EVT_BUTTON, self.__close) sizer.Add(self.btn_ok, flag=CENTER) self.SetSizer(sizer) def __close(self, evt): self.EndModal(ID_OK) self.Hide()
def __init__(self, parent, id, title): # zavolání konstruktoru předka (kompatibilní s Pythonem 2.x) super(MainFrame, self).__init__(parent, id, title, size=(320, 240)) # vytvoření panelu panel = Panel(self, ID_ANY) # vytvoření tlačítka s jeho vložením do panelu x = y = 20 button = Button(panel, ID_ANY, "Press me", (x, y)) button.Bind(EVT_BUTTON, onButtonPress) # zobrazení hlavního okna aplikace self.Show(True)
class FieldsTableAndTestFilesTabs(Panel): TAB_INDEX_FOR_TABLE = 0 TAB_INDEX_FOR_PO_CLASS_FILE = 1 def __init__(self, parent, editor_tab): Panel.__init__(self, parent) self.__editor_tab = editor_tab self.__cur_po_class = None sizer = GridBagSizer(5, 5) full_span = (1, 4) row = 0 inner_sizer = BoxSizer(HORIZONTAL) self.btn_open_test_file = Button(self, label=u'Open test file') self.btn_open_test_file.Bind(EVT_BUTTON, self.__on_open_test_file) inner_sizer.Add(self.btn_open_test_file) self.btn_create_test_file = Button(self, label=u'Create test file') self.btn_create_test_file.Bind(EVT_BUTTON, self.__on_create_test_file) inner_sizer.Add(self.btn_create_test_file) self.btn_save_test_file = Button(self, label=u'Save current file') self.btn_save_test_file.Bind(EVT_BUTTON, self.__on_save_test_file) inner_sizer.Add(self.btn_save_test_file) inner_sizer.AddStretchSpacer(1) self.btn_create_test = Button(self, label=u'Create new method/test case') self.btn_create_test.Bind(EVT_BUTTON, self.__create_method_or_test) inner_sizer.Add(self.btn_create_test) sizer.Add(inner_sizer, pos=(row, 0), span=full_span, flag=FLAG_ALL_AND_EXPAND) row += 1 self.tabs = Tabs(self, [(Table, "Fields' table")]) self.table = self.tabs.GetPage(0) self.table.Bind(EVT_GRID_SELECT_CELL, self.__on_cell_click) self.table.Bind(EVT_GRID_CELL_RIGHT_CLICK, self.__on_cell_click) sizer.Add(self.tabs, pos=(row, 0), span=full_span, flag=FLAG_ALL_AND_EXPAND) sizer.AddGrowableCol(1, 1) sizer.AddGrowableRow(1, 1) self.SetSizer(sizer) def load_po_class(self, po_class): self.__cur_po_class = po_class self.__set_pageobject_class(self.__cur_po_class) file_name = os.path.basename(self.__cur_po_class.file_path) more_than_1_tab = self.tabs.GetPageCount() > 1 if more_than_1_tab: py_file_ui = self.tabs.GetPage(self.TAB_INDEX_FOR_PO_CLASS_FILE) py_file_ui.load_file(self.__cur_po_class.file_path) else: py_file_ui = PyFileUI(self.tabs, self.__cur_po_class.file_path, True) self.tabs.AddPage(py_file_ui, os.path.basename(self.__cur_po_class.file_path)) if not more_than_1_tab and self.tabs.GetSelection( ) != self.TAB_INDEX_FOR_PO_CLASS_FILE: self.tabs.SetSelection(self.TAB_INDEX_FOR_PO_CLASS_FILE) self.tabs.set_tabs_text(file_name, self.TAB_INDEX_FOR_PO_CLASS_FILE) def get_current_po_class(self): return self.__cur_po_class def clear_table(self): self.table.ClearGrid() def get_current_pageobject_class(self): return self.__cur_po_class def __set_pageobject_class(self, po_class): self.__cur_po_class = po_class self.table.load_data(po_class.fields) def __create_method_or_test(self, evt): count = self.tabs.GetPageCount() if count > 1: page = self.tabs.GetPage(self.tabs.GetSelection()) if type(page) == PyFileUI: self.__create_method(page) elif type(page) == TestFileUI: self.__create_test(page) else: show_dialog( self, u'Selected tab is not supported' + LINESEP + u'Please selected test file or page object class', 'Bad selected tab') else: show_dialog( self, u'Test file was not created.' + LINESEP + 'Please create a test file.', u'Test file was not created') def __create_method(self, page): modal = TextEntryDialog(self, u'Enter method name', u'Create method') if modal.ShowModal() == ID_OK: method_name = modal.GetValue() if StringUtils.is_method_name_correct(method_name): page.create_method(method_name) else: show_dialog_bad_name(self, method_name, 'search', 'login', 'fill_data') def __create_test(self, page): modal = TextEntryDialog(self, u'Enter test case name', u'Create new test case') if modal.ShowModal() == ID_OK: test_case_name = modal.GetValue() if StringUtils.is_test_case_name_correct(test_case_name): page.create_new_test_case(test_case_name) else: show_dialog_bad_name(self, test_case_name, 'test_search') def __on_save_test_file(self, evt): count = self.tabs.GetPageCount() if count > 1: page = self.tabs.GetPage(self.tabs.GetSelection()) page.save_file() else: show_dialog(self, u'Please create/open test file.', u'Nothing to save') def __open_or_create_test_file(self, style): if self.__cur_po_class: folder = self.GetTopLevelParent().get_root_folder() if not folder: folder = os.path.dirname(self.__cur_po_class.file_path) elif RootFolder.TESTS_FOLDER in os.listdir(folder): folder = os.path.join(folder, RootFolder.TESTS_FOLDER) dialog = FileDialog(self, defaultDir=folder, style=style, wildcard='*.py') if dialog.ShowModal() == ID_OK: test_file = dialog.GetPath() load_file = style == FD_OPEN filename = os.path.basename(test_file) if StringUtils.is_test_file_name_correct(test_file): test_file_ui = TestFileUI(self.tabs, test_file, self.__cur_po_class, load_file) self.tabs.AddPage(test_file_ui, filename) self.tabs.SetSelection(self.tabs.GetPageCount() - 1) if style == FD_SAVE: test_file_ui.set_file_was_changed() else: show_dialog_bad_name(self, filename, 'my_first_test.py') else: show_dialog(self, u'Please select class file.', u'Class file was not opened') def __on_open_test_file(self, evt): self.__open_or_create_test_file(FD_OPEN) def __on_create_test_file(self, evt): self.__open_or_create_test_file(FD_SAVE) def __on_cell_click(self, evt): self.table.selected_row = evt.GetRow() field = self.table.get_selected_data() if field: self.__editor_tab.image_panel.draw_selected_field(field, True) if evt.GetEventType( ) == EVT_GRID_CELL_RIGHT_CLICK.typeId and field: self.__editor_tab.show_content_menu() evt.Skip()
class EditDialog(Dialog): __hosts = None __window = None def __init__(self, parent, dpi=(1, 1)): Dialog.__init__(self, parent, id=ID_ANY, title=u"编辑/添加Hosts", pos=Point(600, 600), size=Size(394 * dpi[0], 210 * dpi[1]), style=DEFAULT_DIALOG_STYLE | FRAME_FLOAT_ON_PARENT) self.__window = parent self.SetSizeHints(DefaultSize, DefaultSize) font = Font(10, FONTFAMILY_DEFAULT, FONTSTYLE_NORMAL, FONTWEIGHT_NORMAL, False, EmptyString) inputSize = Size(260 * dpi[0], -1) self.SetFont(font) fgSizer3 = FlexGridSizer(0, 2, 0, 0) fgSizer3.SetFlexibleDirection(BOTH) fgSizer3.SetNonFlexibleGrowMode(FLEX_GROWMODE_SPECIFIED) self.localRadio = RadioButton(self, ID_ANY, u"本地Hosts", DefaultPosition, DefaultSize, 0) self.localRadio.SetFont(font) fgSizer3.Add(self.localRadio, 0, ALL, 5) self.localRadio.Bind(EVT_RADIOBUTTON, self.OnRadioChange) self.onlineRadio = RadioButton(self, ID_ANY, u"在线Hosts", DefaultPosition, DefaultSize, 0) fgSizer3.Add(self.onlineRadio, 0, ALL, 5) self.onlineRadio.Bind(EVT_RADIOBUTTON, self.OnRadioChange) self.m_staticText4 = StaticText(self, ID_ANY, u"名称", DefaultPosition, DefaultSize, 0) self.m_staticText4.Wrap(-1) fgSizer3.Add(self.m_staticText4, 0, ALL, 5) self.nameInput = TextCtrl(self, ID_ANY, EmptyString, DefaultPosition, inputSize, 0) fgSizer3.Add(self.nameInput, 0, ALL, 5) self.m_staticText5 = StaticText(self, ID_ANY, u"地址", DefaultPosition, DefaultSize, 0) self.m_staticText5.Wrap(-1) fgSizer3.Add(self.m_staticText5, 0, ALL, 5) self.urlInput = TextCtrl(self, ID_ANY, u"http://", DefaultPosition, inputSize, 0) fgSizer3.Add(self.urlInput, 0, ALL, 5) self.m_staticText3 = StaticText(self, ID_ANY, u"图标", DefaultPosition, DefaultSize, 0) self.m_staticText3.Wrap(-1) fgSizer3.Add(self.m_staticText3, 0, ALL, 5) self.iconComboBox = ComboBox(self, ID_ANY, u"请选择图标", DefaultPosition, inputSize, list(GetIcons().keys()), 0) self.iconComboBox.SetFont(font) fgSizer3.Add(self.iconComboBox, 0, ALL, 5) self.cancelButton = Button(self, ID_ANY, u"取消", DefaultPosition, DefaultSize, 0) fgSizer3.Add(self.cancelButton, 0, ALL, 5) self.saveButton = Button(self, ID_ANY, u"保存", DefaultPosition, DefaultSize, 0) fgSizer3.Add(self.saveButton, 0, ALL, 5) self.SetSizer(fgSizer3) self.Layout() self.Centre(BOTH) self.cancelButton.Bind(EVT_BUTTON, self.OnButtonClicked) self.saveButton.Bind(EVT_BUTTON, self.OnButtonClicked) self.Bind(EVT_CLOSE, self.OnClose) def __del__(self): pass def OnClose(self, event): self.SetHosts(None) event.Skip() def SetHosts(self, hosts): self.__hosts = hosts if hosts: if hosts["url"] and len(hosts["url"] > 0): self.onlineRadio.SetValue(hosts["url"]) self.localRadio.SetValue(not hosts["url"]) self.nameInput.SetValue(hosts["name"]) self.urlInput.SetValue(hosts["url"] or "") self.iconComboBox.SetValue(hosts["icon"]) self.onlineRadio.Enable(False) self.localRadio.Enable(False) else: self.onlineRadio.Enable(False) self.localRadio.Enable(True) self.localRadio.SetValue(True) self.urlInput.SetValue("") self.iconComboBox.SetValue("logo") self.nameInput.SetValue("") def OnButtonClicked(self, event): if event.GetId() == self.cancelButton.GetId(): self.Close() return name = self.nameInput.GetValue() url = self.urlInput.GetValue() isOnline = self.onlineRadio.GetValue() if not isOnline: url = None if not name or len(name) < 1: MessageBox("请输入Hosts名称", "提示", ICON_WARNING) elif isOnline and (not url or len(url) < 1): MessageBox("请输入在线Hosts地址", "提示", ICON_WARNING) else: if not self.iconComboBox.GetValue(): self.iconComboBox.SetValue("logo") if self.__hosts: self.__hosts["name"] = name self.__hosts["url"] = url self.__hosts["lastUpdateTime"] = Now() self.__hosts["icon"] = self.iconComboBox.GetValue() hostsId = self.__hosts['id'] else: hostsId = 0x1994 + len(Settings.settings["hosts"]) Settings.settings["hosts"].append( hostsDict(hostsId, name, url=url, lastUpdateTime=Now(), content="# Created by mHosts v%s, %s\n" % (Settings.version(), Now()), icon=self.iconComboBox.GetValue())) Settings.Save() self.__window.InitHostsTree(select=hostsId) self.Close() def OnRadioChange(self, event): self.urlInput.Enable(event.GetId() == self.onlineRadio.GetId())
class TestRunnerTab(Panel): def __init__(self, *args, **kwargs): Panel.__init__(self, *args, **kwargs) sizer = GridBagSizer(5, 5) row = 0 col = 0 self.cb_html_output = CheckBox(self, label=u'Report in HTML') self.cb_html_output.Bind(EVT_CHECKBOX, self.__on_check) sizer.Add(self.cb_html_output, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 self.txt_html_report = TextCtrl(self, style=TE_READONLY) self.txt_html_report.Disable() sizer.Add(self.txt_html_report, pos=(row, col), span=(1, 3), flag=FLAG_ALL_AND_EXPAND) col += 3 self.btn_select_html = Button(self, label=u'Select HTML file') self.btn_select_html.Disable() self.btn_select_html.Bind(EVT_BUTTON, self.__on_select_file) sizer.Add(self.btn_select_html, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) row += 1 col = 0 self.cb_xml_output = CheckBox(self, label=u'Report in XML') self.cb_xml_output.Bind(EVT_CHECKBOX, self.__on_check) sizer.Add(self.cb_xml_output, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 self.txt_xml_report = TextCtrl(self, style=TE_READONLY) self.txt_xml_report.Disable() sizer.Add(self.txt_xml_report, pos=(row, col), span=(1, 3), flag=FLAG_ALL_AND_EXPAND) col += 3 self.btn_select_xml = Button(self, label=u'Select XML file') self.btn_select_xml.Disable() self.btn_select_xml.Bind(EVT_BUTTON, self.__on_select_file) sizer.Add(self.btn_select_xml, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) row += 1 col = 0 self.cb_options = CheckBox(self, label=u'Additional options') self.cb_options.Bind(EVT_CHECKBOX, self.__on_check) sizer.Add(self.cb_options, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 self.txt_options = TextCtrl(self) self.txt_options.Disable() sizer.Add(self.txt_options, pos=(row, col), span=(1, 3), flag=FLAG_ALL_AND_EXPAND) col += 3 self.btn_nose_help = Button(self, label=u'Show help') self.btn_nose_help.Bind(EVT_BUTTON, self.__on_show_help) sizer.Add(self.btn_nose_help, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) row += 1 col = 0 self.btn_load_tests_from_files = Button(self, label=u'Load tests from files') self.btn_load_tests_from_files.Bind(EVT_BUTTON, self.__load_tests_from_files) sizer.Add(self.btn_load_tests_from_files, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 self.btn_load_tests_from_dir = Button( self, label=u'Load tests from directory') self.btn_load_tests_from_dir.Bind(EVT_BUTTON, self.__load_tests_from_directory) sizer.Add(self.btn_load_tests_from_dir, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 dummy_label = StaticText(self) sizer.Add(dummy_label, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 self.cb_browser = Choice(self, choices=Browser.get_supported_browsers()) self.cb_browser.Select(0) sizer.Add(self.cb_browser, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 self.btn_run = Button(self, label=u'Run test cases') self.btn_run.Bind(EVT_BUTTON, self.__run_tests) sizer.Add(self.btn_run, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) row += 1 col = 0 window = SplitterWindow(self, style=SP_3D | SP_LIVE_UPDATE) self.tree_ctrl = CustomTreeCtrl( window, style=TR_SINGLE | TR_HAS_BUTTONS | TR_AUTO_CHECK_CHILD | TR_AUTO_CHECK_PARENT | TR_AUTO_TOGGLE_CHILD) self.tree_ctrl.SetBackgroundColour(self.GetBackgroundColour()) self.tree_ctrl.SetForegroundColour(self.GetForegroundColour()) self.tree_ctrl.Bind(EVT_TREE_ITEM_CHECKED, self.__on_tree_check) self.txt_ctrl = TextCtrl(window, style=TE_MULTILINE | TE_READONLY | HSCROLL | VSCROLL) font_size = self.txt_ctrl.GetFont().GetPointSize() self.txt_ctrl.SetFont( Font(font_size, FONTFAMILY_TELETYPE, NORMAL, NORMAL)) window.SplitVertically(self.tree_ctrl, self.txt_ctrl) sizer.Add(window, pos=(row, col), span=(1, 5), flag=FLAG_ALL_AND_EXPAND) sizer.AddGrowableCol(2, 1) sizer.AddGrowableRow(row, 1) self.SetSizerAndFit(sizer) def __on_show_help(self, evt): text = check_output(['nosetests', '--help']) DialogWithText(self, u'Help for nosetests', text).ShowModal() def __on_select_file(self, evt): folder = self.__get_safe_path_from_root_folder(RootFolder.REPORTS) obj = evt.GetEventObject() txt_ctrl = None if obj == self.btn_select_html: wildcard = u'*.html' txt_ctrl = self.txt_html_report elif obj == self.btn_select_xml: wildcard = u'*.xml' txt_ctrl = self.txt_xml_report else: wildcard = u'*.*' dialog = FileDialog(self, defaultDir=folder, style=FD_SAVE | FD_OVERWRITE_PROMPT, wildcard=wildcard) if dialog.ShowModal() == ID_OK and txt_ctrl: txt_ctrl.SetValue(dialog.GetPath()) def __on_check(self, evt): cb_obj = evt.GetEventObject() checkboxes_and_txt_ctrls = { self.cb_html_output: self.txt_html_report, self.cb_options: self.txt_options, self.cb_xml_output: self.txt_xml_report } checkboxes_and_btns = { self.cb_html_output: self.btn_select_html, self.cb_xml_output: self.btn_select_xml } txt_ctrl = checkboxes_and_txt_ctrls[cb_obj] btn = checkboxes_and_btns.get(cb_obj) if txt_ctrl.IsEnabled(): txt_ctrl.Disable() if btn: btn.Disable() else: txt_ctrl.Enable() if btn: btn.Enable() def __on_tree_check(self, evt): # styles doesn't work: TR_AUTO_CHECK_CHILD | TR_AUTO_CHECK_PARENT | TR_AUTO_TOGGLE_CHILD # TODO: fix if all children are check then one child is uncheck - parent is checked item = evt.GetItem() checked = item.IsChecked() parent = item.GetParent() def all_children_are_checked(_parent): states = [child.IsChecked() for child in _parent.GetChildren()] uniq_states = list(set(states)) return len(uniq_states) == 1 and uniq_states[0] is True self.tree_ctrl.AutoCheckChild(item, checked) if parent: self.tree_ctrl.AutoCheckParent(item, all_children_are_checked(parent)) def __get_safe_path_from_root_folder(self, subfolder=None): folder = self.GetTopLevelParent().get_root_folder() if subfolder and folder: path_for_subfolder = os.path.join(folder, subfolder) if os.path.exists(path_for_subfolder): return path_for_subfolder return folder if folder else '.' def __load_tests_to_tree(self, file_paths=None, dir_path=None): if file_paths: python_files = file_paths elif dir_path: python_files = [f for f in get_list_of_files(dir_path, True)] else: python_files = [] python_files = [ f for f in python_files if 'test' in os.path.basename(f) and os.path.splitext(f)[-1] == '.py' ] if len(python_files) > 0: syspath = list(os.sys.path) try: root_folder = self.__get_safe_path_from_root_folder() if root_folder not in os.sys.path: os.sys.path.append(root_folder) checkbox_type = 1 self.tree_ctrl.DeleteAllItems() root = self.tree_ctrl.AddRoot('All test cases', checkbox_type) for python_file in python_files: top_item = self.tree_ctrl.AppendItem( root, os.path.abspath(python_file), checkbox_type) parsed_classes = ParsedClass.get_parsed_classes( python_file) for parsed_class in parsed_classes: item = self.tree_ctrl.AppendItem( top_item, parsed_class.name, checkbox_type) test_methods = [ k for k in parsed_class.methods.keys() if k.startswith('test_') ] for tc_name in test_methods: self.tree_ctrl.AppendItem(item, tc_name, checkbox_type) self.tree_ctrl.ExpandAll() except Exception: show_error_dialog(self, traceback.format_exc(), 'Cannot add test cases') finally: os.sys.path = syspath def __load_tests_from_directory(self, evt): folder = self.__get_safe_path_from_root_folder(RootFolder.TESTS_FOLDER) if folder: dialog = DirDialog(self, defaultPath=folder, style=DD_DIR_MUST_EXIST) if dialog.ShowModal() == ID_OK: self.__load_tests_to_tree(dir_path=dialog.GetPath()) else: show_dialog_path_doesnt_exist(self, folder) def __load_tests_from_files(self, evt): folder = self.__get_safe_path_from_root_folder(RootFolder.TESTS_FOLDER) if folder: dialog = FileDialog(self, defaultDir=folder, style=FD_OPEN | FD_FILE_MUST_EXIST | FD_MULTIPLE, wildcard=u'*.py') if dialog.ShowModal() == ID_OK: self.__load_tests_to_tree(file_paths=dialog.GetPaths()) else: show_dialog_path_doesnt_exist(self, folder) def __get_nose_command(self): root = self.tree_ctrl.GetRootItem() tests = [] for _file in root.GetChildren(): for _class in _file.GetChildren(): for test_case in _class.GetChildren(): if test_case.IsChecked(): # TODO: fix for files that contain spaces tests.append(u'%s:%s.%s' % (_file.GetText(), _class.GetText(), test_case.GetText())) args = [ '--with-path="%s"' % self.__get_safe_path_from_root_folder(), '--logging-level=INFO' ] use_html_report = (self.cb_html_output.IsChecked() and len(self.txt_html_report.GetValue()) > 0) if use_html_report: report_path = self.txt_html_report.GetValue() args.append('--with-html --html-file="%s"' % report_path) use_xml_report = (self.cb_xml_output.IsChecked() and len(self.txt_xml_report.GetValue()) > 0) if use_xml_report: report_path = self.txt_xml_report.GetValue() args.append('--with-xunit --xunit-file="%s"' % report_path) use_options = (self.cb_options.IsChecked() and len(self.txt_options.GetValue()) > 0) if use_options: report_path = self.txt_options.GetValue() args.append(report_path) nose_cmd = [u'nosetests'] + args + tests return nose_cmd def __run_tests(self, evt): # TODO: do not run if root folder is not selected self.txt_ctrl.Clear() dialog = InfiniteProgressBarDialog( self, u'Running test cases', u'Running selected test cases... Please wait...') def wrap_func(): stdout = os.sys.stdout stderr = os.sys.stderr redirected = RedirectText(self.txt_ctrl) os.sys.stdout = redirected os.sys.stderr = redirected try: nose_cmd = self.__get_nose_command() browser_name = self.cb_browser.GetStringSelection() Browser.DEFAULT_BROWSER = browser_name report_folder = self.__get_safe_path_from_root_folder( RootFolder.REPORTS) BaseTest.FAILED_SCREENSHOT_FOLDER = report_folder easy_selenium_cmd = u" ".join(nose_cmd).replace( "nosetests", "easy_selenium_cli.py -b " + browser_name) print(u"Executing command:\n%s" % easy_selenium_cmd) print(u"Nose output:") run(argv=nose_cmd[1:]) finally: dialog.close_event.set() os.sys.stdout = stdout os.sys.stderr = stderr run_in_separate_thread(wrap_func) dialog.ShowModal()
class EditorTab(Panel): def __init__(self, parent): Panel.__init__(self, parent) sizer = GridBagSizer(5, 5) self.SetSizer(sizer) self.__cur_po_class = None self.__create_widgets() def __create_widgets(self): sizer = self.GetSizer() # Next row inner_sizer = BoxSizer(HORIZONTAL) label = StaticText(self, label=u'Class path:') inner_sizer.Add(label, flag=ALL) self.cb_class_path = ComboBox(self, style=CB_READONLY) self.cb_class_path.Bind(EVT_COMBOBOX, self.__on_load_po_class) inner_sizer.Add(self.cb_class_path, 1, flag=FLAG_ALL_AND_EXPAND) self.btn_reload = Button(self, label=u'Reload') self.btn_reload.Bind(EVT_BUTTON, self.__on_load_po_class) inner_sizer.Add(self.btn_reload, flag=ALL) self.btn_open_class = Button(self, label=u'Open class') self.btn_open_class.Bind(EVT_BUTTON, self.__open_class) inner_sizer.Add(self.btn_open_class, flag=ALL) row = 0 sizer.Add(inner_sizer, pos=(row, 0), flag=FLAG_ALL_AND_EXPAND) # Next row row += 1 splitter = SplitterWindow(self, style=SP_3D | SP_LIVE_UPDATE) self.image_panel = ImageWithElements(splitter) self.image_panel.static_bitmap.Bind(EVT_MOTION, self.__on_mouse_move) self.image_panel.static_bitmap.Bind(EVT_RIGHT_DOWN, self.__on_right_click) self.table_and_test_file_tabs = FieldsTableAndTestFilesTabs(splitter, self) splitter.SplitHorizontally(self.image_panel, self.table_and_test_file_tabs) sizer.Add(splitter, pos=(row, 0), flag=FLAG_ALL_AND_EXPAND) sizer.AddGrowableRow(row, 1) sizer.AddGrowableCol(0, 1) def __get_parsed_classes(self, field): classes = ParsedPageObjectClass.get_parsed_classes(self.__cur_po_class.file_path) if len(classes) > 0 and len(classes[0].methods) == 0: classes = [] classes += [ParsedModule.get_parsed_module(tools)] if field: classes += ParsedMouseClass.get_parsed_classes() classes += ParsedBrowserClass.get_parsed_classes() return classes def show_content_menu(self, field): tabs = self.table_and_test_file_tabs.tabs count = tabs.GetPageCount() if count > 1: selected_tab = tabs.GetPage(tabs.GetSelection()) if type(selected_tab) in (TestFileUI, PyFileUI): file_path = selected_tab.get_file_path() txt_ctrl_ui = tabs.GetPage(tabs.GetSelection()) parsed_classes = self.__get_parsed_classes(field) context_menu = FieldContextMenu(field, parsed_classes, file_path, txt_ctrl_ui) self.PopupMenu(context_menu) context_menu.Destroy() else: show_dialog(self, u'Please select tab with test file.', u'Tab with test file was not selected') else: show_dialog(self, u'Please create/open test file.', u'Test file was not created/opened') def __on_load_po_class(self, evt): path = self.cb_class_path.GetValue() if len(path) > 0: self.__load_po_class(path) def __on_right_click(self, evt): field = self.__get_current_field(evt) self.show_content_menu(field) def __on_mouse_move(self, evt): if self.__cur_po_class: ImageAndTableHelper.select_field_on_mouse_move( evt, self.__cur_po_class.fields, self.image_panel, self.table_and_test_file_tabs.table ) def __get_current_field(self, evt): return self.image_panel.get_field(evt.GetPosition()) def __open_class(self, evt): folder = self.GetTopLevelParent().get_root_folder() if folder: if RootFolder.PO_FOLDER in os.listdir(folder): folder = os.path.join(folder, RootFolder.PO_FOLDER) dialog = FileDialog(self, defaultDir=folder, wildcard=u'*.py') if dialog.ShowModal() == ID_OK: self.__load_po_class(dialog.GetPath()) else: show_dialog_path_doesnt_exist(self, folder) def __load_po_class(self, path): self.table_and_test_file_tabs.table.clear_table() if not os.path.exists(path): show_dialog_path_doesnt_exist(self, path) if not is_correct_python_file(path): show_dialog(self, u'File name is incorrect: %s' % path, u'Bad file name') else: folder = os.path.dirname(path) files = [os.path.join(folder, p) for p in os.listdir(folder) if is_correct_python_file(p)] self.cb_class_path.Clear() self.cb_class_path.AppendItems(files) self.cb_class_path.Select(files.index(path)) try: self.__cur_po_class = PageObjectClass.parse_string_to_po_class(read_file(path)) area = self.__cur_po_class.area self.image_panel.set_po_fields(self.__cur_po_class.fields) self.image_panel.load_image(self.__cur_po_class.img_path, area) self.cb_class_path.SetValue(self.__cur_po_class.file_path) self.table_and_test_file_tabs.load_po_class(self.__cur_po_class) except Exception: self.__cur_po_class = None show_error_dialog(self, traceback.format_exc(), u'Failed to open file %s' % path)
class GeneratorTab(Panel): def __init__(self, parent): Panel.__init__(self, parent) self.main_frame = self.GetTopLevelParent() self.__create_widgets() def __create_widgets(self): sizer = GridBagSizer(5, 5) row = 0 col = 0 # first row label = StaticText(self, label=u'Selected area:') sizer.Add(label, pos=(row, col)) col += 1 self.txt_selected_area = TextCtrl(self, value=u'(0, 0, 0, 0)') sizer.Add(self.txt_selected_area, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 label = StaticText(self, label=u'Class name:') sizer.Add(label, pos=(row, col)) col += 1 self.txt_class_name = TextCtrl(self) sizer.Add(self.txt_class_name, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 self.bth_reload_img = Button(self, label=u'Reload image') self.bth_reload_img.Bind(EVT_BUTTON, self.__load_img) sizer.Add(self.bth_reload_img, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 self.btn_generate = Button(self, label=u'Generate') self.btn_generate.Bind(EVT_BUTTON, self.generate) sizer.Add(self.btn_generate, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) # second row row += 1 col = 0 self.select_image_panel = SelectableImagePanel(self) self.select_image_panel.static_bitmap.Bind(EVT_MOTION, self._on_mouse_move) sizer.Add(self.select_image_panel, pos=(row, col), span=(1, 6), flag=FLAG_ALL_AND_EXPAND) sizer.AddGrowableCol(1, 1) sizer.AddGrowableRow(row, 1) self.SetSizer(sizer) def __get_root_folder(self): return self.main_frame.get_root_folder() def __load_img(self, evt=None): browser = self.main_frame.get_browser() if browser: img_path = browser.save_screenshot(self.main_frame.get_tmp_dir()) self.select_image_panel.load_image(img_path) w, h = self.select_image_panel.get_image_dimensions() self.txt_selected_area.SetValue(u'(%d, %d, %d, %d)' % (0, 0, w, h)) self.main_frame.set_url(browser.get_current_url()) def _on_mouse_move(self, evt): if self.select_image_panel.was_image_loaded(): SelectableImagePanel.on_mouse_move(self.select_image_panel, evt) selected_area = self.select_image_panel.get_selected_area() self.txt_selected_area.SetValue(repr(selected_area)) def __is_gen_data_correct(self): root_folder = self.__get_root_folder() class_name = self.txt_class_name.GetValue() area = self.txt_selected_area.GetValue() if not self.main_frame.get_browser(): msg = u"Browser is not opened." + LINESEP + "Please open url." caption = u'Browser is not opened' show_dialog(self, msg, caption) return False elif not re.match( '\(\s*[0-9]+\s*,\s*[0-9]+\s*,\s*[0-9]+\s*,\s*[0-9]+\s*\)', area): msg = u"Selected area is not correct: '%s'" % area caption = u'Bad selected area' show_dialog(self, msg, caption) return False elif root_folder is None or not os.path.exists(root_folder): show_dialog_path_doesnt_exist(self, root_folder) return False elif len(class_name) == 0: # if bad class_name msg = u"Unsupported name for class: '%s'" % class_name caption = u'Bad name for class' show_dialog(self, msg, caption) return False return True def __get_frames(self): browser = self.main_frame.get_browser() if browser: frames = [] for e in browser.find_elements((By.CSS_SELECTOR, 'frame, iframe')): name = browser.get_attribute(e, 'name') src = browser.get_attribute(e, 'src') frames.append((name, src)) return frames else: return None def generate(self, evt): if self.__is_gen_data_correct(): folder = self.__get_root_folder() if RootFolder.PO_FOLDER in os.listdir(folder): folder = os.path.join(folder, RootFolder.PO_FOLDER) class_name = self.txt_class_name.GetValue() file_path = os.path.join( folder, get_py_file_name_from_class_name(class_name)) area_as_text = self.txt_selected_area.GetValue() url = self.main_frame.get_url() if os.path.exists(file_path): show_dialog_path_does_exist(self, file_path) elif not StringUtils.is_class_name_correct(class_name): show_dialog_bad_name(self, class_name, 'Header', 'ContextMenu') elif not StringUtils.is_area_correct(area_as_text): show_dialog(self, u'Bad selected area: %s' % area_as_text, u'Bad selected area') elif not StringUtils.is_url_correct(url): show_dialog(self, u'Bad url: %s' % url, u'Bad url') else: dialog = DialogWithText(self, 'Generating page object class...') handler = WxTextCtrlHandler(dialog.txt_ctrl) logger = Logger(log_to_console=False, handler=handler) dialog.Show() area = eval(area_as_text) generator = PageObjectGenerator(self.main_frame.get_browser(), logger) folder_path = self.main_frame.get_tmp_dir() def generate(): dialog.btn_ok.Disable() po_class = generator.get_po_class_for_url( url, class_name, folder_path, area) po_class.save(folder) logger.info(u"Saving class '%s'..." % po_class.name) logger.info(u'Saved file: %s' % po_class.file_path) logger.info(u'Saved file: %s' % po_class.img_path) logger.info(u'DONE') dialog.btn_ok.Enable() thread = Thread(target=generate) thread.setDaemon(True) thread.start()
class MainFrame(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.__browser = None self.__tmp_dir = mkdtemp() self.SetTitle("Easy Selenium UI") self.SetSize((800, 600)) self.__create_widgets() self.Bind(EVT_CLOSE, self.__on_close) def __create_widgets(self): panel = Panel(self) sizer = GridBagSizer(5, 5) row = 0 col = 0 label = StaticText(panel, label=u'Root folder:') sizer.Add(label, pos=(row, col)) col += 1 col_width = 4 self.__txt_root_path = TextCtrl(panel) sizer.Add(self.__txt_root_path, pos=(row, col), span=(1, col_width), flag=FLAG_ALL_AND_EXPAND) col += col_width self.__btn_set_root = Button(panel, label=u'Set root folder') self.__btn_set_root.Bind(EVT_BUTTON, self.__set_root_folder) sizer.Add(self.__btn_set_root, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) row += 1 col = 0 label = StaticText(panel, label=u'Url:') sizer.Add(label, pos=(row, col)) col += 1 self.__txt_url = TextCtrl( panel, value=u'https://www.google.com/') # TODO: remove url sizer.Add(self.__txt_url, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 label = StaticText(panel, label=u'Browser:') sizer.Add(label, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 self.__cb_browser = Choice(panel, choices=Browser.get_supported_browsers()) self.__cb_browser.Select(0) sizer.Add(self.__cb_browser, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 self.bth_open_url = Button(panel, label=u'Open url') self.bth_open_url.Bind(EVT_BUTTON, self.__open_url) sizer.Add(self.bth_open_url, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 self.bth_close_url = Button(panel, label=u'Close browser') self.bth_close_url.Bind(EVT_BUTTON, self.__close_browser) sizer.Add(self.bth_close_url, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) row += 1 col = 0 tabs = Tabs(panel, [(GeneratorTab, "Generator"), (EditorTab, "Editor"), (TestRunnerTab, "Test runner"), (SelectorFinderTab, "Selector finder")]) sizer.Add(tabs, pos=(row, col), span=(1, 6), flag=FLAG_ALL_AND_EXPAND) sizer.AddGrowableCol(1, 1) sizer.AddGrowableRow(2, 1) panel.SetSizer(sizer) self.Layout() def get_root_folder(self): text = self.__txt_root_path.GetValue() if text and len(text) > 0: return text else: return None def __set_root_folder(self, evt): dialog = DirDialog(self) if dialog.ShowModal() == ID_OK: path = dialog.GetPath() RootFolder.prepare_folder(path) self.__txt_root_path.SetValue(path) def __open_url(self, evt): url = self.__txt_url.GetValue() if StringUtils.is_url_correct(url): self.bth_open_url.Disable() name = self.get_browser_initials() try: if self.__browser and self.__browser.get_browser_initials( ) != name: self.__browser.quit() self.__browser = Browser(name) elif not self.__browser: self.__browser = Browser(name) except Exception: show_error_dialog(self, traceback.format_exc(), u'Failed to open browser') self.__browser = None if self.__browser: self.__browser.open(url) # TODO: if generator or selector -> load image self.bth_open_url.Enable() else: show_dialog(self, u'Bad url: %s' % url, u'Bad url') def __close_browser(self, evt): if self.__browser: self.__browser.quit() self.__browser = None def __on_close(self, evt): self.__close_browser(evt) shutil.rmtree(self.__tmp_dir) self.Destroy() def get_url(self): return self.__txt_url.GetValue() def set_url(self, url): self.__txt_url.SetValue(url) def get_browser(self): return self.__browser def get_browser_initials(self): return self.__cb_browser.GetStringSelection() def get_tmp_dir(self): return self.__tmp_dir
class MainDialog(Dialog): """ Main window. Hit a button to profile the system, then another to scan what was plugged in """ def __init__(self): """Constructor""" Dialog.__init__(self, None, title="Bad Cop", size=Size(500, 100)) ico = Icon('logo.ico', BITMAP_TYPE_ICO) self.SetIcon(ico) self.message = StaticText( self, label="Click Profile, then insert device and click Test") self.profile = Button(self, label="Profile") self.test = Button(self, label="Test") self.test.Disable() self.profile.Bind(EVT_BUTTON, self.profileusb) self.test.Bind(EVT_BUTTON, self.testusb) self.Bind(EVT_CLOSE, self.onclose) main_sizer = BoxSizer(VERTICAL) t_sizer = BoxSizer(HORIZONTAL) p_sizer = BoxSizer(HORIZONTAL) t_sizer.Add(self.message, 0, ALL | CENTER, 5) p_sizer.Add(self.profile, 0, ALL | CENTER, 5) p_sizer.Add(self.test, 0, ALL | CENTER, 5) main_sizer.Add(p_sizer, 0, ALL | CENTER, 5) main_sizer.Add(t_sizer, 0, ALL | EXPAND | CENTER, 5) self.SetSizer(main_sizer) def profileusb(self, other): del other dev = find(find_all=True) devices = [] for cfg in dev: devclass = str(cfg.bDeviceClass) product = str(cfg.iProduct) vid = hex(cfg.idVendor) pid = hex(cfg.idProduct) for line in Configuration(find(idVendor=cfg.idVendor)): line = str(line) linestrip = line.strip() linesplit = linestrip.split('\n') linesplit = [x.split(':') for x in linesplit] lines = [] for w in linesplit: lines.append([y.strip(' ') for y in w]) for e in lines: if 'bInterfaceClass' in e[0]: intclass = e[1] devices.append([devclass, product, vid, pid, intclass]) with open('devices.pkl', 'wb') as f: dump(devices, f) self.profile.SetLabel("Done!") self.profile.Disable() self.test.Enable() def testusb(self, other): del other with open('devices.pkl', 'rb') as f: benchmark = load(f) dev = find(find_all=True) devices = [] for cfg in dev: devclass = str(cfg.bDeviceClass) product = str(cfg.iProduct) vid = hex(cfg.idVendor) pid = hex(cfg.idProduct) for line in Configuration(find(idVendor=cfg.idVendor)): line = str(line) linestrip = line.strip() linesplit = linestrip.split('\n') linesplit = [x.split(':') for x in linesplit] lines = [] for w in linesplit: lines.append([y.strip(' ') for y in w]) for e in lines: if 'bInterfaceClass' in e[0]: intclass = e[1] devices.append([devclass, product, vid, pid, intclass]) first_tuple_list = [tuple(lst) for lst in benchmark] secnd_tuple_list = [tuple(lst) for lst in devices] first_set = set(first_tuple_list) secnd_set = set(secnd_tuple_list) output = "" height = 100 first = 0 for devclass, product, vid, pid, usbtype in first_set.symmetric_difference( secnd_set): if usbtype == "0xa CDC Data": devicedesc = "Virtual Data Port (Network)" elif usbtype == "0xe0 Wireless Controller": devicedesc = "Wireless Internet Or Bluetooth" elif usbtype == "0x8 Mass Storage": devicedesc = "Data Storage Device" elif usbtype == "0x9 Hub": devicedesc = "USB Hub" elif usbtype == "0x3 Human Interface Device": devicedesc = "Keyboard, Mouse, or Other Input Device" elif usbtype == "0x2 CDC Communication": devicedesc = "Vitual Communications Port (Network)" else: devicedesc = usbtype + " device " if first == 0: output += "This appears to be a: \n " + devicedesc + " \n" else: output += " " + devicedesc + " \n" height = height + 30 first = 1 self.SetSize((500, height)) self.message.SetLabel(output) def onclose(self, event): del event try: remove('devices.pkl') except: print('file missing') self.Destroy() exit("Application Exited")
class SelectorFinderTab(Panel): def __init__(self, parent): Panel.__init__(self, parent) self.main_frame = self.GetTopLevelParent() self.po_fields = None self.__create_widgets() def __create_widgets(self): sizer = GridBagSizer(5, 5) row = 0 col = 1 self.bth_reload_img = Button(self, label=u'Reload image') self.bth_reload_img.Bind(EVT_BUTTON, self.__load_img) sizer.Add(self.bth_reload_img, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) col += 1 self.bth_reload_selectors = Button(self, label=u'Find selectors') self.bth_reload_selectors.Bind(EVT_BUTTON, self.__find_selectors) sizer.Add(self.bth_reload_selectors, pos=(row, col), flag=FLAG_ALL_AND_EXPAND) # third row row += 1 col = 0 splitter = SplitterWindow(self, style=SP_3D | SP_LIVE_UPDATE) self.image_panel = ImageWithElements(splitter) self.image_panel.static_bitmap.Bind(EVT_MOTION, self.__on_mouse_move) self.table = Table(splitter) self.table.Bind(EVT_GRID_SELECT_CELL, self.__on_cell_select) splitter.SplitHorizontally(self.image_panel, self.table) sizer.Add(splitter, pos=(row, col), span=(1, 3), flag=FLAG_ALL_AND_EXPAND) sizer.AddGrowableCol(0, 1) sizer.AddGrowableRow(row, 1) self.SetSizer(sizer) def __update_table(self): if self.po_fields: self.table.load_data(self.po_fields) def __on_mouse_move(self, evt): ImageAndTableHelper.select_field_on_mouse_move(evt, self.po_fields, self.image_panel, self.table) def __on_cell_select(self, evt): self.table.selected_row = evt.GetRow() self.image_panel.draw_selected_field(self.table.get_selected_data(), True) evt.Skip() def __load_img(self, evt=None): browser = self.main_frame.get_browser() if browser: img_path = browser.save_screenshot(self.main_frame.get_tmp_dir()) self.image_panel.load_image(img_path) self.main_frame.set_url(browser.get_current_url()) def __find_selectors(self, evt): browser = self.main_frame.get_browser() if browser: url = self.main_frame.get_url() if not StringUtils.is_url_correct(url): show_dialog(self, u'Bad url: %s' % url, u'Bad url') else: dialog = DialogWithText(self, 'Finding selectors...') handler = WxTextCtrlHandler(dialog.txt_ctrl) logger = Logger(log_to_console=False, handler=handler) dialog.Show() generator = PageObjectGenerator(browser, logger) def find_selectors(): dialog.btn_ok.Disable() self.po_fields = generator.get_all_po_fields(url, None) logger.info(u'DONE') self.__update_table() dialog.btn_ok.Enable() thread = Thread(target=find_selectors) thread.setDaemon(True) thread.start()
class AssetFrame(wx.Frame): def __init__(self, parent, title="PyAsset", cfgFile="", assetFile=""): self.parent = parent self.frame = self self.assets = AssetList(self) self.bills = BillList() self.cur_asset = Asset(name=assetFile) self.edited = False self.payType = "" self.ref_date = None self.netpay = "" self.payDepositAcct = "" self.cfgFile = copy.deepcopy(cfgFile) super(AssetFrame, self).__init__(parent, title=title) if self.readConfigFile(cfgFile): valid_date_seps = ['/', '-'] for j in range(len(valid_date_seps)): date_sep = valid_date_seps[j] date_fields = self.dateFormat.split(valid_date_seps[j]) if len(date_fields) == 3: break if len(date_fields) == 3: Date.set_global_date_format(self, self.dateFormat) Date.set_global_date_sep(self, date_sep) self.curr_date = Date.set_curr_date(self) self.proj_date = Date.set_proj_date(self, "") Date.set_global_curr_date(self, self.curr_date) Date.set_global_proj_date(self, self.proj_date) Date.set_curr_paydate(self) Date.set_next_paydate(self) self.make_widgets() self.filename = assetFile if self.filename == "": d = wx.FileDialog(self, "Open", "", "", "*.qif", wx.FD_OPEN) if d.ShowModal() == wx.ID_OK: fname = d.GetFilename() dir = d.GetDirectory() self.filename = os.path.join(dir, fname) if self.filename: latest_assets = qif.load_file(self, self.filename) self.process_asset_list(latest_assets) else: error = 'Badly formatted date format sting: %s - Aborting!\n' self.DisplayMsg(error) else: error = cfgFile + ' does not exist / cannot be opened!! - Aborting\n' self.DisplayMsg(error) def clear_all_assets(self): self.assets = AssetList(self) self.redraw_all(-1) def readConfigFile(self, cfgFile): if cfgFile == "": d = wx.FileDialog(self, "", "", "", "*.cfg", wx.FD_OPEN) if d.ShowModal() == wx.ID_OK: fname = d.GetFilename() dir = d.GetDirectory() total_name_in = os.path.join(dir, fname) self.cfgFile = total_name_in else: self.cfgFile = cfgFile try: file = open(self.cfgFile, 'r') lines = file.readlines() self.dateFormat = lines.pop(0).replace('\n', '') Date.set_global_date_format(self, self.dateFormat) self.payType = lines.pop(0).replace('\n', '') in_ref_date = lines.pop(0).replace('\n', '') ref_date = Date.parse_date(self, in_ref_date, self.dateFormat) self.ref_date = ref_date["dt"] self.netpay = lines.pop(0).replace('\n', '') self.payDepositAcct = lines.pop(0).replace('\n', '') file.close() return True except: return False def writeConfigFile(self): if self.cfgFile == "": d = wx.FileDialog(self, "", "", "", "*.cfg", wx.FD_OPEN) if d.ShowModal() == wx.ID_OK: fname = d.GetFilename() dir = d.GetDirectory() total_name_in = os.path.join(dir, fname) self.cfgFile = total_name_in file = open(self.cfgFile, 'w') file.write("%s\n" % self.dateFormat) file.write("%s\n" % self.payType) file.write("%s\n" % self.ref_date) file.write("%s\n" % self.netpay) file.write("%s\n" % self.payDepositAcct) file.close() def DisplayMsg(self, str): d = wx.MessageDialog(self, str, "Error", wx.OK | wx.ICON_INFORMATION) d.ShowModal() d.Destroy() def make_widgets(self): self.menubar = wx.MenuBar() self.SetMenuBar(self.menubar) self.make_filemenu() self.make_editmenu() self.make_helpmenu() self.setup_layout() def make_filemenu(self): self.filemenu = wx.Menu() ID_EXPORT_TEXT = wx.NewId() ID_ARCHIVE = wx.NewId() ID_IMPORT_CSV = wx.NewId() ID_IMPORT_XLSM = wx.NewId() ID_UPDATE_FROM_NET = wx.NewId() ID_PROPERTIES = wx.NewId() self.filemenu.Append(wx.ID_OPEN, "Open\tCtrl-o", "Open a new transction file", wx.ITEM_NORMAL) self.filemenu.Append(wx.ID_SAVE, "Save\tCtrl-s", "Save the current transactions in the same file", wx.ITEM_NORMAL) self.filemenu.Append( wx.ID_SAVEAS, "Save As", "Save the current transactions under a different name", wx.ITEM_NORMAL) self.filemenu.Append(wx.ID_CLOSE, "Close\tCtrl-w", "Close the current file", wx.ITEM_NORMAL) self.filemenu.Append( ID_EXPORT_TEXT, "Export Text", "Export the current transaction register as a text file", wx.ITEM_NORMAL) self.filemenu.Append( ID_ARCHIVE, "Archive", "Archive transactions older than a specified date", wx.ITEM_NORMAL) self.filemenu.AppendSeparator() self.filemenu.Append(ID_IMPORT_CSV, "Import CSV\tCtrl-c", "Import transactions from a CSV file", wx.ITEM_NORMAL) self.filemenu.Append( ID_IMPORT_XLSM, "Import XLSM file\tCtrl-i", "Import transactions from an EXCEL file with Macros", wx.ITEM_NORMAL) self.filemenu.Append(ID_UPDATE_FROM_NET, "Update Accounts from Net\tCtrl-u", "Update accounts using pre-defined iMacros", wx.ITEM_NORMAL) self.filemenu.AppendSeparator() self.filemenu.Append( ID_PROPERTIES, "Properties\tCtrl-p", "Display and/or edit Number and Data/Time display properties, pay frequencies", wx.ITEM_NORMAL) self.filemenu.AppendSeparator() self.filemenu.Append(wx.ID_EXIT, "Quit\tCtrl-q", "Exit PyAsset", wx.ITEM_NORMAL) self.menubar.Append(self.filemenu, "&File") self.Bind(wx.EVT_MENU, self.load_file, None, wx.ID_OPEN) self.Bind(wx.EVT_MENU, self.save_file, None, wx.ID_SAVE) self.Bind(wx.EVT_MENU, self.save_as_file, None, wx.ID_SAVEAS) self.Bind(wx.EVT_MENU, self.close, None, wx.ID_CLOSE) self.Bind(wx.EVT_MENU, self.export_text, None, ID_EXPORT_TEXT) self.Bind(wx.EVT_MENU, self.archive, None, ID_ARCHIVE) self.Bind(wx.EVT_MENU, self.import_CSV_file, None, ID_IMPORT_CSV) self.Bind(wx.EVT_MENU, self.import_XLSM_file, None, ID_IMPORT_XLSM) self.Bind(wx.EVT_MENU, self.update_from_net, None, ID_UPDATE_FROM_NET) self.Bind(wx.EVT_MENU, self.properties, None, ID_PROPERTIES) self.Bind(wx.EVT_MENU, self.quit, None, wx.ID_EXIT) def make_editmenu(self): ID_SORT = wx.NewId() ID_DELETE_ENTRY = wx.NewId() self.editmenu = wx.Menu() self.editmenu.Append(wx.ID_NEW, "New Entry\tCtrl-n", "Create a new asset in the list", wx.ITEM_NORMAL) self.editmenu.Append(ID_DELETE_ENTRY, "Delete Entry", "Delete the current asset", wx.ITEM_NORMAL) self.editmenu.Append(ID_SORT, "Sort Entries", "Sort entries", wx.ITEM_NORMAL) self.menubar.Append(self.editmenu, "&Edit") self.Bind(wx.EVT_MENU, self.newentry, None, wx.ID_NEW) self.Bind(wx.EVT_MENU, self.deleteentry, None, ID_DELETE_ENTRY) self.Bind(wx.EVT_MENU, self.sort, None, ID_SORT) def make_helpmenu(self): ID_HELP = wx.NewId() self.helpmenu = wx.Menu() self.helpmenu.Append(wx.ID_ABOUT, "About", "About PyAsset", wx.ITEM_NORMAL) self.helpmenu.Append(ID_HELP, "Help\tCtrl-h", "PyAsset Help", wx.ITEM_NORMAL) self.menubar.Append(self.helpmenu, "&Help") self.Bind(wx.EVT_MENU, self.about, None, wx.ID_ABOUT) self.Bind(wx.EVT_MENU, self.gethelp, None, ID_HELP) def make_bill_button(self, panel): self.billButton = Button(panel, label="Bills") self.billButton.Bind(wx.EVT_LEFT_DOWN, self.onBillButtonClick) def onBillButtonClick(self, evt): self.DisplayMsg("Bill button clicked!") def make_date_grid(self, panel): self.currDateLabel = wx.StaticText(panel, label="Curr Date") dates = Date(self, self.dateFormat, self.payType, self.ref_date) self.curr_date = dates.get_curr_date() self.currDate = wx.StaticText(panel, label=self.curr_date["str"]) self.projDateLabel = wx.StaticText(panel, label="Proj Date") displayDateFormat = self.dateFormat.replace("%m", "mm").replace( "%d", "dd").replace("%y", "yy").replace("%Y", "yyyy") self.projDateInput = wx.TextCtrl(panel, style=wx.TE_PROCESS_ENTER, value=displayDateFormat) self.currPayDateLabel = wx.StaticText(panel, label="Current Pay Date") self.currPayDate = dates.get_curr_paydate() self.currPayDateOutput = wx.StaticText(panel, label=str(self.currPayDate)) self.nextPayDateLabel = wx.StaticText(panel, label="Next Pay Date") self.nextPayDate = dates.get_next_paydate() self.nextPayDateOutput = wx.StaticText(panel, label=str(self.nextPayDate)) self.projDateInput.Bind(wx.EVT_TEXT_ENTER, self.onProjDateEntered) def update_date_grid_dates(self, oldDateFormat, newDateFormat): if oldDateFormat != newDateFormat: self.curr_date = Date.convertDateFormat(self, self.curr_date, oldDateFormat, newDateFormat) self.currDate.LabelText = self.curr_date["str"] self.currDate.Refresh() try: if oldDateFormat != newDateFormat: self.proj_date = Date.convertDateFormat( self, self.proj_date, oldDateFormat, newDateFormat) if self.proj_date == None: self.projDateInput.LabelText = newDateFormat.replace( "%m", "mm").replace("%d", "dd").replace("%y", "yy").replace("%Y", "yyyy") else: self.projDateInput.LabelText = self.proj_date except: self.projDateInput.LabelText = newDateFormat.replace( "%m", "mm").replace("%d", "dd").replace("%y", "yy").replace("%Y", "yyyy") self.projDateInput.Refresh() if oldDateFormat != newDateFormat: self.currPayDate = Date.convertDateFormat(self, self.currPayDate, oldDateFormat, newDateFormat) self.currPayDateOutput.LabelText = Date.get_curr_paydate(self) self.currPayDateOutput.Refresh() if oldDateFormat != newDateFormat: self.nextPayDate = Date.convertDateFormat(self, self.nextPayDate, oldDateFormat, newDateFormat) self.nextPayDateOutput.LabelText = Date.get_next_paydate(self) self.nextPayDateOutput.Refresh() def onProjDateEntered(self, evt): in_date = evt.String date_format = Date.get_global_date_format(self) returned_date = Date.parse_date(self, in_date, date_format) if returned_date != None: self.proj_date = wx.DateTime.FromDMY(returned_date["day"], returned_date["month"] - 1, returned_date["year"]) self.proj_year = returned_date["year"] self.proj_month = returned_date["month"] self.proj_day = returned_date["day"] print( "Projected date %s, parse: Month: %02d, Day: %02d, Year: %04d" % (self.proj_date.Format(self.dateFormat), self.proj_month, self.proj_day, self.proj_year)) Date.set_proj_date(self, in_date) else: self.proj_date = None self.DisplayMsg("Bad projected date ignored: %s" % (in_date)) def make_asset_grid(self, panel): self.assetGrid = AssetGrid(panel) self.needed_width = self.assetGrid.set_properties(self) def add_transaction_frame(self, row, col): name = self.assets[row].name transactions = self.assets[row].transactions self.trans_frame = TransactionFrame(None, self, -1, row, transactions, name) def get_transaction_frame(self): return self.trans_frame def setup_layout(self): self.panel = wx.Panel(self) self.make_bill_button(self.panel) self.make_date_grid(self.panel) self.make_asset_grid(self.panel) self.date_fgs = wx.FlexGridSizer(1, 9, 5, 5) self.date_fgs.AddMany([(self.billButton), (self.currDateLabel, 1, wx.ALIGN_CENTER), (self.currDate, 1, wx.ALIGN_CENTER), (self.projDateLabel, 1, wx.ALIGN_CENTER), (self.projDateInput, 1, wx.EXPAND), (self.currPayDateLabel, 1, wx.ALIGN_CENTER), (self.currPayDateOutput, 1, wx.ALIGN_CENTER), (self.nextPayDateLabel, 1, wx.ALIGN_CENTER), (self.nextPayDateOutput, 1, wx.ALIGN_CENTER)]) self.asset_fgs = wx.FlexGridSizer(2, 1, 0, 0) self.asset_fgs.Add(self.assetGrid, proportion=1, flag=wx.RESERVE_SPACE_EVEN_IF_HIDDEN | wx.EXPAND) self.mainSizer = wx.BoxSizer(wx.VERTICAL) self.mainSizer.Add(self.date_fgs) self.mainSizer.Add(self.asset_fgs) self.panel.Fit() self.panel.SetSizer(self.mainSizer) self.date_fgs.SetSizeHints(self.panel) self.asset_fgs.SetSizeHints(self.panel) self.Fit() self.Layout() self.Show() def redraw_all(self, index=-1): self.edited = True nassets = len(self.assets) if index == -1: nrows = nassets + 1 if nrows > 0 and (index == None or index == -1): self.assetGrid.DeleteRows(0, nrows) nrows = 0 start_range = 0 end_range = nassets if nrows < nassets: rows_needed = nassets - nrows self.assetGrid.AppendRows(rows_needed) else: start_range = index end_range = start_range + 1 for row in range(start_range, end_range): for col in range(self.assetGrid.getNumLayoutCols()): ret_val = wx.OK if row < 0 or row >= len(self.assets): str = "Warning: skipping redraw on bad cell %d %d!" % (row, col) ret_val = self.DisplayMsg(str) if ret_val != wx.OK: continue # Logic to always display Value (Curr), Value (Proj), Avail(Proj), Amt Over, Cash Limit, Cash Used and Cash Avail for credit cards,store cards, and overdraft asset_type = self.assets[row].get_type() col_name = self.assetGrid.getColName(col) self.assetGrid.setColZeroSuppress(row, col, True) if (asset_type == "store card" or asset_type == "credit card" or asset_type == "overdraft") and ( "Curr" in col_name or "Proj" in col_name or "Amt" in col_name or "Cash" in col_name): self.assetGrid.setColZeroSuppress(row, col, False) cellValue = self.assetGrid.GridCellDefaultRenderer(row, col) cellType = self.assetGrid.getColType(col) if cellType == self.assetGrid.DOLLAR_TYPE: self.assetGrid.GridCellDollarRenderer(row, col) elif cellType == self.assetGrid.RATE_TYPE: self.assetGrid.GridCellPercentRenderer(row, col) elif cellType == self.assetGrid.DATE_TYPE: self.assetGrid.GridCellDateRenderer(row, col) elif cellType == self.assetGrid.DATE_TIME_TYPE: self.assetGrid.GridCellDateTimeRenderer(row, col) elif cellType == self.assetGrid.STRING_TYPE: self.assetGrid.GridCellStringRenderer(row, col) else: self.assetGrid.GridCellErrorRenderer(row, col) if index == -1: self.assetGrid.SetGridCursor(0, 0) # was (nassets-1, 0) self.assetGrid.MakeCellVisible(0, True) # was (nassets-1, 0) elif index > 0: self.assetGrid.SetGridCursor(index, 0) self.assetGrid.MakeCellVisible(index, True) def assetchange(self, evt): row = evt.GetRow() col = evt.GetCol() val = evt.String modified = True colName = self.assetGrid.getColName(col) if colName == "Acct name": self.assets[row].set_name(val) elif colName == "Curr val": self.assets[row].set_value(val) elif colName == "Last pulled": self.assets[row].set_last_pull_date(val) elif colName == "Limit": self.assets[row].set_limit(val) elif colName == "Avail online": self.assets[row].set_avail(val) elif colName == "Rate": self.assets[row].set_rate(val) elif colName == "Payment amt": self.assets[row].set_payment(val) elif colName == "Due date": self.assets[row].set_due_date(val) elif colName == "Sched date": self.assets[row].set_sched_date(val) elif colName == "Min Pmt": self.assets[row].set_min_pay(val) elif colName == "Stmt Bal": self.assets[row].set_stme_bal(val) elif colName == "Amt Over": self.assets[row].set_amt_over(val) elif colName == "Cash Limit": self.assets[row].set_cash_limit(val) elif colName == "Cash Used": self.assets[row].set_cash_used(val) elif colName == "Cash Avail": self.assets[row].set_cash_avail(val) else: print("assetchange: Warning: modifying incorrect cell! row, ", row, " col ", col) modified = False if modified == True: self.edited = True def update_all_Date_Formats(self, oldDateFormat, newDateFormat): self.edited = True self.update_date_grid_dates(oldDateFormat, newDateFormat) #TODO: Add code to update asset_grids and transaction grids JJG 06/10/2020 def load_file(self, assetFile): latest_assets = qif.load_file(self, "") if latest_assets != None: self.process_asset_list(latest_assets) def save_file(self, *args): for cur_asset in self.assets: if cur_asset.filename == "": self.save_as_file() else: self.edited = False self.cur_asset.write_qif() def save_as_file(self, *args): d = wx.FileDialog(self, "Save", "", "", "*.qif", wx.FD_SAVE) if d.ShowModal() == wx.ID_OK: fname = d.GetFilename() dir = d.GetDirectory() self.cur_asset.write_qif(os.path.join(dir, fname)) if self.cur_asset.name: self.SetTitle("PyAsset: %s" % self.cur_asset.name) def close(self, *args): pass # Not sure what to do here yet! JJG 1/17/2022 #self.cur_asset = None #del self.assets #del self.bills #self.assets = AssetList(self) #self.bills = BillList() #self.redraw_all() #self.edited = False #self.SetTitle("PyAsset: Asset") def quit(self, *args): self.close() self.Close() # # @brief Receives data to be written to and its location # # @params[in] date_ # Data of transaction # @params[in] amount_ # Amount of money for transaction # @params[in] memo_ # Description of transaction # @params[in] payee_ # Who transaction was paid to # @params[in] filelocation_ # Location of the Output file # # # https://en.wikipedia.org/wiki/Quicken_Interchange_Format # def write_file(self, date_, amount_, memo_, payee_, filelocation_): outFile = open(filelocation_, "a") # Open file to be appended outFile.write( "!Type:Cash\n") # Header of transaction, Currently all set to cash outFile.write("D") # Date line starts with the capital D outFile.write(date_) outFile.write("\n") outFile.write("T") # Transaction amount starts here outFile.write(amount_) outFile.write("\n") outFile.write("M") # Memo Line outFile.write(memo_) outFile.write("\n") if (payee_ != -1): outFile.write("P") # Payee line outFile.write(payee_) outFile.write("\n") outFile.write( "^\n" ) # The last line of each transaction starts with a Caret to mark the end outFile.close() # # @brief Takes given CSV and parses it to be exported to a QIF # # @params[in] inf_ # File to be read and converted to QIF # @params[in] outf_ # File that the converted data will go # @params[in] deff_ # File with the settings for converting CSV # # def read_csv(self, inf_, outf_, deff_): # will need to receive input csv and def file csvdeff = csv.reader(deff_, delimiter=',') next(csvdeff, None) for settings in csvdeff: date_ = (settings[0]) # convert to amount_ = (settings[2]) # How much was the transaction memo_ = (settings[3]) # discription of the transaction payee_ = (settings[4]) # Where the money is going deli_ = settings[5] # How the csv is separated header_ = (settings[6]) # Set if there is a header to skip csvIn = csv.reader( inf_, delimiter=deli_) # create csv object using the given separator if header_ >= 1: # If there is a header skip the fist line next(csvIn, None) # skip header for row in csvIn: self.write_file(row[date_], row[amount_], row[memo_], row[payee_], outf_) # export each row as a qif entry inf_.close() deff_.close() def import_CSV_file(self, *args): # Appends the records from a .csv file to the current Asset d = wx.FileDialog(self, "Import", "", "", "*.csv", wx.FD_OPEN) if d.ShowModal() == wx.ID_OK: self.edited = True fname = d.GetFilename() dir = d.GetDirectory() total_name_in = os.path.join(dir, fname) total_name_extension_place = total_name_in.find(".csv") total_name_def = "" total_name_qif = "" if total_name_extension_place != -1: total_name_def = total_name_in[:total_name_extension_place] + ".def" total_name_qif = total_name_in[:total_name_extension_place] + ".qif" # pr total_name_in, total_name_def, total_name_qif error = "" try: fromfile = open(total_name_in, 'r') except: error = total_name_in + ' does not exist / cannot be opened !!\n' if total_name_qif != "": try: tofile = open(totoal_name_qif, 'a') except: error = total_name_qif + ' cannot be created !!\n' if total_name_def != "": if os.path.isfile(total_name_def): deffile = open(total_name_def, 'r') else: error = total_name_def + ' does not exist / cannot be opened !!\n' if error == "": tofile = total_name_qif self.read_csv(fromfile, tofile, deffile) self.cur_asset.read_qif(total_name_qif) fromfile.close() deffile.close() self.redraw_all(-1) if self.cur_asset.name: self.SetTitle("PyAsset: %s" % self.cur_asset.name) else: self.Display(error) return def process_asset_list(self, assetList): for i in range(len(assetList.assets)): cur_asset = assetList.assets[i] cur_name = cur_asset.get_name() j = self.assets.index(cur_name) if j != -1: self.assets.assets[ j] = cur_asset # For now, just replace, when dates are working, save later date JJG 1/22/2022 else: self.assets.append_by_object(cur_asset) self.redraw_all() def import_XLSM_file(self, *args): # Appends or Merges as appropriate the records from a .xlsm file to the current Asset d = wx.FileDialog(self, "Import", "", "", "*.xlsm", wx.FD_OPEN) if d.ShowModal() == wx.ID_OK: self.edited = True fname = d.GetFilename() dir = d.GetDirectory() total_name_in = os.path.join(dir, fname) error = "" try: fromfile = open(total_name_in, 'r') fromfile.close() except: error = total_name_in + ' does not exist / cannot be opened !!\n' if error == "": self.cur_assets = None xlsm = ExcelToAsset(ignore_sheets=[ 'Assets', 'Bills', 'Shop Your Way transactions', 'Slate transactions', 'Slate old transactions' ]) xlsm.OpenXLSMFile(total_name_in) latest_assets = xlsm.ProcessAssetsSheet(self) self.process_asset_list(latest_assets) transaction_sheet_names = xlsm.GetTransactionSheetNames() for sheet in transaction_sheet_names: sheet_index = self.assets.index(sheet) if sheet_index != -1: self.assets[ sheet_index].transactions = xlsm.ProcessTransactionSheet( self.assets[sheet_index], sheet) if self.assets[sheet_index].transactions: proj_value = self.assets[ sheet_index].transactions.update_current_and_projected_values( ) self.assets[sheet_index].set_value_proj(proj_value) else: print(sheet + " not found in asset list") #TODO: Process latest_bills here (False since not written yet!) if False: self.latest_bills = xlsm.ProcessBillsSheet(self.bills) print(self.latest_bills) else: self.DisplayMsg(error) def update_from_net(self, *args): w = iMacrosToAsset() w.Init() net_asset_codes = [ ("HFCU", 1, [False, False, False, True]), #("BOA",-1,[False,True]), #("AMEX",-1,[True,True]), #("CITI",-1,[True]), #("MACYS",-1,[True]), #("SYW",-1,[True]), #("TSP",-1,[False,False,False,True]), #("MET",1,[False]) ] for net_asset_code in net_asset_codes: latest_assets = w.GetNetInfo(net_asset_code) #print latest_assets for i in range(len(latest_assets)): net_asset = latest_assets.__getitem__(i) if net_asset != None: latest_name = net_asset.get_name() found = False for j in range(len(self.assets)): cur_name = self.assets[j].get_name() if "(" in cur_name: cur_name = cur_name.split("(")[1].split(")")[0] if cur_name in latest_name: net_index = j found = True break if not found: self.assets.append(latest_name) net_index = -1 # Always update Value (Curr) column and type ... others check if non-zero value before update is done! self.assets[net_index].set_value(net_asset.get_value()) self.assets[net_index].set_type(net_asset.get_type()) if net_asset.get_value_proj() != 0.0: self.assets[net_index].set_value_proj( net_asset.get_value_proj()) if net_asset.get_last_pull_date() != 0.0: self.assets[net_index].set_last_pull_date( net_asset.get_last_pull_date()) if net_asset.get_limit() != 0.0: self.assets[net_index].set_limit(net_asset.get_limit()) if net_asset.get_avail() != 0.0: self.assets[net_index].set_avail(net_asset.get_avail()) if net_asset.get_avail_proj() != 0.0: self.assets[net_index].set_avail_proj( net_asset.get_avail_proj()) if net_asset.get_rate() != 0.0: self.assets[net_index].set_rate(net_asset.get_rate()) if net_asset.get_payment() != 0.0: self.assets[net_index].set_payment( net_asset.get_payment()) if net_asset.get_due_date() != None: self.assets[net_index].set_due_date( net_asset.get_due_date()) if net_asset.get_sched_date() != None: self.assets[net_index].set_sched_date( net_asset.get_sched_date()) if net_asset.get_min_pay() != 0.0: self.assets[net_index].set_min_pay( net_asset.get_min_pay()) if net_asset.get_stmt_bal() != 0.0: self.assets[net_index].set_stmt_bal( net_asset.get_stmt_bal()) if net_asset.get_amt_over() != 0.0: self.assets[net_index].set_amt_over( net_asset.get_amt_over()) if net_asset.get_cash_limit() != 0.0: self.assets[net_index].set_cash_limit( net_asset.get_cash_limit()) if net_asset.get_cash_used() != 0.0: self.assets[net_index].set_cash_used( net_asset.get_cash_used()) if net_asset.get_cash_avail() != 0.0: self.assets[net_index].set_cash_avail( net_asset.get_cash_avail()) w.Finish() self.redraw_all() def properties(self, *args): dateFormat = Date.get_global_date_format(self) ref_date_parsed = Date.parse_date(self, self.ref_date, dateFormat) if ref_date_parsed != None: ref_date_dt = ref_date_parsed["dt"] ref_date = wx.DateTime.FromDMY(ref_date_dt.day, ref_date_dt.month, ref_date_dt.year).Format(dateFormat) else: ref_date = "" # For now to test! JJG 08/06/2021 frame = PropertyFrameWithForm(self, self.dateFormat, self.payType, ref_date, self.netpay, self.payDepositAcct) frame.Show() def setDateFormat(self, new_DateFormat): self.dateFormat = new_DateFormat def setPayType(self, new_type): self.payType = new_type def setRefDate(self, new_ref_date): self.ref_date = new_ref_date def setNetPay(self, new_netpay): self.netpay = new_netpay def setPayDepositAcct(self, new_PayDepositAcct): self.payDepositAcct = new_PayDepositAcct def getDateFormat(self): return self.dateFormat def getPayType(self): return self.payType def getRefDate(self): return self.ref_date def getNetPay(self): return self.netpay def getPayDepositAcct(self): return self.payDepositAcct def export_text(self, *args): d = wx.FileDialog(self, "Save", "", "", "*.txt", wx.SAVE) if d.ShowModal() == wx.ID_OK: fname = d.GetFilename() dir = d.GetDirectory() self.cur_asset.write_txt(os.path.join(dir, fname)) def archive(self, *args): d = wx.TextEntryDialog( self, "Archive transactions before what date (mm/dd/yy)?", "Archive Date") if d.ShowModal() == wx.ID_OK: date = Date(d.GetValue()) else: date = None d.Destroy() if not date: return archive = Asset() newcb_starttransaction = Transaction() newcb_starttransaction.amount = 0 newcb_starttransaction.payee = "Starting Balance" newcb_starttransaction.memo = "Archived by PyAsset" newcb_starttransaction.state = "cleared" newcb_starttransaction.date = date newcb = Asset() newcb.filename = self.cur_asset.filename newcb.name = self.cur_asset.name newcb.append(newcb_starttransaction) archtot = 0 for transaction in self.cur_asset: if transaction.date < date and transaction.state == "cleared": archive.append(transaction) archtot += transaction.amount else: newcb.append(transaction) newcb_starttransaction.amount = archtot self.cur_asset = newcb while 1: d = wx.FileDialog(self, "Save Archive As", "", "", "*.qif", wx.SAVE) if d.ShowModal() == wx.ID_OK: fname = d.GetFilename() dir = d.GetDirectory() d.Destroy() if fname: break archive.write_qif(os.path.join(dir, fname)) self.redraw_all(-1) self.edited = True def newentry(self, *args): self.edited = True self.assets.append("New Asset") self.assetGrid.AppendRows() nassets = self.assetGrid.GetNumberRows() self.assetGrid.SetGridCursor(nassets - 1, 0) self.assetGrid.MakeCellVisible(nassets - 1, 1) self.redraw_all() def sort(self, *args): self.edited = True self.assets.sort() self.redraw_all() def deleteentry(self, *args): index = self.assetGrid.GetGridCursorRow() indices = self.assetGrid.SelectedCells if index >= 0: d = wx.MessageDialog(self, "Really delete this asset?", "Really delete?", wx.YES_NO) if d.ShowModal() == wx.ID_YES: del self.assets[index] self.redraw_all( ) # TODO: Can we make a self.redraw(index-1) so that only the assets[index-1:] get updated? JJG 07/09/2021 def about(self, *args): d = wx.MessageDialog( self, "Python Asset Manager\n" "Copyright (c) 2016-2022 Joseph J. Gorak\n" "Released under the Gnu GPL\n", "About PyAsset", wx.OK | wx.ICON_INFORMATION) d.ShowModal() d.Destroy() def gethelp(self, *args): d = HelpDialog(self, -1, "Help", __doc__) val = d.ShowModal() d.Destroy() def MsgBox(self, message): d = wx.MessageDialog(self, message, "error", wx.OK | wx.ICON_INFORMATION) d.ShowModal() d.Destroy()
class MyTaskBarIcon(TaskBarIcon): ICON = "logo.ico" # 图标地址 ID_ABOUT = NewIdRef() # 菜单选项“关于”的ID ID_EXIT = NewIdRef() # 菜单选项“退出”的ID ID_UPLOAD = NewIdRef() # 菜单选项“显示页面”的ID ID_LOGIN = NewIdRef() # 菜单选项“显示页面”的ID TITLE = "SMPIC" # 鼠标移动到图标上显示的文字 def __init__(self): TaskBarIcon.__init__(self) self.SetIcon(Icon(self.ICON), self.TITLE) # 设置图标和标题 self.Bind(EVT_MENU, self.onAbout, id=self.ID_ABOUT) # 绑定“关于”选项的点击事件 self.Bind(EVT_MENU, self.onExit, id=self.ID_EXIT) # 绑定“退出”选项的点击事件 self.Bind(EVT_MENU, self.onUpload, id=self.ID_UPLOAD) self.Bind(EVT_MENU, self.OnLogin, id=self.ID_LOGIN) self.frame = Frame(parent=None, title='登录', size=(285, 160)) self.frame.Bind(EVT_CLOSE, lambda event: self.frame.Show(False)) panel = Panel(self.frame, -1) label_user = StaticText(panel, -1, "账号:", pos=(10, 10)) label_pass = StaticText(panel, -1, "密码:", pos=(10, 50)) self.entry_user = TextCtrl(panel, -1, size=(210, 20), pos=(50, 10)) self.entry_pass = TextCtrl(panel, -1, size=(210, 20), pos=(50, 50), style=TE_PASSWORD) self.but_login = Button(panel, -1, "登陆", size=(50, 30), pos=(10, 80)) self.but_register = Button(panel, -1, "注册SM.MS账号", size=(110, 30), pos=(150, 80)) self.but_not_login = Button(panel, -1, "免登陆使用", size=(80, 30), pos=(65, 80)) self.but_login.Bind(EVT_BUTTON, self.on_but_login) self.but_register.Bind(EVT_BUTTON, self.on_but_register) self.but_not_login.Bind(EVT_BUTTON, self.on_but_not_login) self.frame.Center() token = init_config() if token == '0': self.frame.Show(True) else: self.frame.Show(False) self.frame.SetMaxSize((285, 160)) self.frame.SetMinSize((285, 160)) ThreadKey(self) self.frame2 = Trans(parent=None, title='上传中', size=(50, 20)) self.frame2.Center() self.frame2.Show(False) self.frame3 = Trans(parent=None, title='上传成功', size=(50, 20)) self.frame3.Center() self.frame3.Show(False) self.frame4 = Trans(parent=None, title='上传失败', size=(50, 20)) self.frame4.Center() self.frame4.Show(False) self.frame5 = Trans(parent=None, title='每分钟限制上传20张,请等待冷却', size=(200, 20)) self.frame5.Center() self.frame5.Show(False) # “关于”选项的事件处理器 def onAbout(self, event): MessageBox('Author:Jack Wang\nEmail Address:[email protected]\nLatest Update:2019-12-13', "info") # “退出”选项的事件处理器 def onExit(self, event): global listener listener.stop() Exit() # “显示页面”选项的事件处理器 def onUpload(self, event): get_pic_from_clipboard(self) def OnLogin(self, event): self.frame.Show(True) # 创建菜单选项 def CreatePopupMenu(self): menu = Menu() for mentAttr in self.getMenuAttrs(): menu.Append(mentAttr[1], mentAttr[0]) return menu # 获取菜单的属性元组 def getMenuAttrs(self): return [('上传剪贴板至SM.MS', self.ID_UPLOAD), ('登录', self.ID_LOGIN), ('关于', self.ID_ABOUT), ('退出', self.ID_EXIT)] def on_but_login(self, event): username = self.entry_user.GetValue() password = self.entry_pass.GetValue() try: token = Smms.get_token(username, password) with open('config.yml', 'r', encoding='utf-8') as f: cont = f.read() config = yaml.load(cont, Loader=yaml.BaseLoader) with open('config.yml', 'w', encoding='utf-8') as f: config['token'] = token yaml.dump(config, f, default_flow_style=False, encoding='utf-8', allow_unicode=True) self.frame.Show(False) MessageBox('登陆成功!\n' '使用方法:\n1.首先复制一张图片,本地的或者网\n' '页上的,或者使用截图工具截图;\n' '2.随后按' + hotkeys + '上传;\n' '3.成功后会返回url至你的剪贴板。\n\n提示:\n可编辑config.yml修改快捷键', "温馨提示") except KeyError: MessageBox('密码或账号错误', "警告") def on_but_not_login(self, event): try: with open('config.yml', 'r', encoding='utf-8') as f: cont = f.read() config = yaml.load(cont, Loader=yaml.BaseLoader) with open('config.yml', 'w', encoding='utf-8') as f: config['token'] = 'not login' yaml.dump(config, f, default_flow_style=False, encoding='utf-8', allow_unicode=True) self.frame.Show(False) MessageBox( '使用方法:\n1.首先复制一张图片,本地的或者网\n' '页上的,或者使用截图工具截图;\n' '2.随后按' + hotkeys + '上传;\n' '3.成功后会返回url至你的剪贴板。\n\n提示:\n1.免登录使用将无法在线查看你的全部上\n传记录,仅可查看本IP的上传记录\n2.可编辑config.yml修改快捷键', "温馨提示") except KeyError: MessageBox('出现了未知问题,请提交issue', "警告") def on_but_register(self, event): openweb('https://sm.ms/register') def LoginAgain(self): # 删除线程 MessageBox('登录已失效,需重新登录', "警告") self.frame.Show(True) def Uploading(self): pos = GetMousePosition() pos = (pos[0] + 15, pos[1]) self.frame2.SetPosition(pos) def timestop(): self.frame2.Show(False) timer.cancel() self.frame2.Show(True) timer = Timer(2.0, timestop) timer.start() def UploadSuccess(self): pos = GetMousePosition() pos = (pos[0] + 15, pos[1]) self.frame3.SetPosition(pos) def timestop(): self.frame3.Show(False) timer.cancel() self.frame3.Show(True) timer = Timer(2.0, timestop) timer.start() def UploadFailed(self): pos = GetMousePosition() pos = (pos[0] + 15, pos[1]) self.frame4.SetPosition(pos) def timestop(): self.frame4.Show(False) timer.cancel() self.frame4.Show(True) timer = Timer(2.0, timestop) timer.start() def UploadMax(self): pos = GetMousePosition() pos = (pos[0]+15,pos[1]) self.frame5.SetPosition(pos) def timestop(): self.frame5.Show(False) timer.cancel() self.frame5.Show(True) timer = Timer(5.0, timestop) timer.start()