class NewActionModulation(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.initUI() def initUI(self): self.parent.title("Test") self.frameTab = Frame(self, relief=RAISED, borderwidth=1) self.frameTab.grid(row=3, column=0, columnspan=4) self.grid(row=0, column=0) self.frameTab.grid(row=0, column=0) self.note_book = Notebook(self.frameTab) self.specific_actions = ActionModulation.ActionModulation(self.note_book) self.note_book.add(self.specific_actions.getFrame(), text="specific actions") self.general_actions = GeneralActionModulation.GeneralActionModulation(self.note_book) self.note_book.add(self.general_actions.getFrame(), text="general actions") self.note_book.grid(row=0, column=0) self.frameButtons = Frame(self, relief=RAISED, borderwidth=1) self.frameButtons.grid(row=3, column=0, columnspan=4) self.buttonReset = Button(self.frameButtons, text="Reset") self.buttonReset.grid(row=0, column=0) self.buttonAbort = Button(self.frameButtons, text="Abort") self.buttonAbort.grid(row=0, column=1) self.buttonStop = Button(self.frameButtons, text="Stop") self.buttonStop.grid(row=0, column=2) self.buttonSendAction = Button(self.frameButtons, text="Send Action") self.buttonSendAction.grid(row=0, column=4) self.buttonSendEmotion = Button(self.frameButtons, text="Send Emotion") self.buttonSendEmotion.grid(row=0, column=5) def getCurrentTab(self): return self.note_book.index(self.note_book.select()) def getFirstTab(self): return self.specific_actions def getSecondTab(self): return self.general_actions def getButtonSendAction(self): return self.buttonSendAction def getButtonSendEmotion(self): return self.buttonSendEmotion def getButtonReset(self): return self.buttonReset def getButtonAbort(self): return self.buttonAbort def getButtonStop(self): return self.buttonStop
class MainWindow(object): def __init__(self, root, debugger): ''' ----------------------------------------------------- | main button toolbar | ----------------------------------------------------- | < ma | in content area > | | | | | | | File list | File name | Inspector | | (stack/ | Code area | | | breakpnts) | | | | | | | | | | | ----------------------------------------------------- | status bar area | ----------------------------------------------------- ''' # Obtain and expand the current working directory. base_path = os.path.abspath(os.getcwd()) base_path = os.path.normcase(base_path) + '/' # Create a filename normalizer based on the CWD. self.filename_normalizer = filename_normalizer(base_path) self.debugger = debugger # Associate the debugger with this view. self.debugger.view = self # Root window self.root = root self.root.title('Bugjar') self.root.geometry('1024x768') # Prevent the menus from having the empty tearoff entry self.root.option_add('*tearOff', False) # Catch the close button self.root.protocol("WM_DELETE_WINDOW", self.cmd_quit) # Catch the "quit" event. self.root.createcommand('exit', self.cmd_quit) # Setup the menu self._setup_menubar() # Set up the main content for the window. self._setup_button_toolbar() self._setup_main_content() self._setup_status_bar() # Now configure the weights for the root frame self.root.columnconfigure(0, weight=1) self.root.rowconfigure(0, weight=0) self.root.rowconfigure(1, weight=1) self.root.rowconfigure(2, weight=0) debugger.start() ###################################################### # Internal GUI layout methods. ###################################################### def _setup_menubar(self): # Menubar self.menubar = Menu(self.root) # self.menu_Apple = Menu(self.menubar, name='Apple') # self.menubar.add_cascade(menu=self.menu_Apple) self.menu_file = Menu(self.menubar) self.menubar.add_cascade(menu=self.menu_file, label='File') self.menu_program = Menu(self.menubar) self.menubar.add_cascade(menu=self.menu_program, label='Program') self.menu_help = Menu(self.menubar) self.menubar.add_cascade(menu=self.menu_help, label='Help') # self.menu_Apple.add_command(label='Test', command=self.cmd_dummy) # self.menu_file.add_command(label='New', command=self.cmd_dummy, accelerator="Command-N") self.menu_file.add_command(label='Open...', command=self.cmd_open_file, accelerator="Command-O") self.root.bind('<Command-o>', self.cmd_open_file) # self.menu_file.add_command(label='Close', command=self.cmd_dummy) self.menu_program.add_command(label='Run', command=self.cmd_run, accelerator="R") self.root.bind('<r>', self.cmd_run) self.menu_program.add_command(label='Step', command=self.cmd_step, accelerator="S") self.root.bind('<s>', self.cmd_step) self.menu_program.add_command(label='Next', command=self.cmd_next, accelerator="N") self.root.bind('<n>', self.cmd_next) self.menu_program.add_command(label='Return', command=self.cmd_return, accelerator="BackSpace") self.root.bind('<BackSpace>', self.cmd_return) self.menu_help.add_command(label='Open Documentation', command=self.cmd_bugjar_docs) self.menu_help.add_command(label='Open Bugjar project page', command=self.cmd_bugjar_page) self.menu_help.add_command(label='Open Bugjar on GitHub', command=self.cmd_bugjar_github) self.menu_help.add_command(label='Open BeeWare project page', command=self.cmd_beeware_page) # last step - configure the menubar self.root['menu'] = self.menubar def _setup_button_toolbar(self): ''' The button toolbar runs as a horizontal area at the top of the GUI. It is a persistent GUI component ''' # Main toolbar self.toolbar = Frame(self.root) self.toolbar.grid(column=0, row=0, sticky=(W, E)) # Buttons on the toolbar self.run_button = Button(self.toolbar, text='Run', command=self.cmd_run) self.run_button.grid(column=0, row=0) self.step_button = Button(self.toolbar, text='Step', command=self.cmd_step) self.step_button.grid(column=1, row=0) self.next_button = Button(self.toolbar, text='Next', command=self.cmd_next) self.next_button.grid(column=2, row=0) self.return_button = Button(self.toolbar, text='Return', command=self.cmd_return) self.return_button.grid(column=3, row=0) self.toolbar.columnconfigure(0, weight=0) self.toolbar.rowconfigure(0, weight=0) def _setup_main_content(self): ''' Sets up the main content area. It is a persistent GUI component ''' # Main content area self.content = PanedWindow(self.root, orient=HORIZONTAL) self.content.grid(column=0, row=1, sticky=(N, S, E, W)) # Create subregions of the content self._setup_file_lists() self._setup_code_area() self._setup_inspector() # Set up weights for the left frame's content self.content.columnconfigure(0, weight=1) self.content.rowconfigure(0, weight=1) self.content.pane(0, weight=1) self.content.pane(1, weight=2) self.content.pane(2, weight=1) def _setup_file_lists(self): self.file_notebook = Notebook(self.content, padding=(0, 5, 0, 5)) self.content.add(self.file_notebook) self._setup_stack_frame_list() self._setup_breakpoint_list() def _setup_stack_frame_list(self): self.stack_frame = Frame(self.content) self.stack_frame.grid(column=0, row=0, sticky=(N, S, E, W)) self.file_notebook.add(self.stack_frame, text='Stack') self.stack = StackView(self.stack_frame, normalizer=self.filename_normalizer) self.stack.grid(column=0, row=0, sticky=(N, S, E, W)) # # The tree's vertical scrollbar self.stack_scrollbar = Scrollbar(self.stack_frame, orient=VERTICAL) self.stack_scrollbar.grid(column=1, row=0, sticky=(N, S)) # # Tie the scrollbar to the text views, and the text views # # to each other. self.stack.config(yscrollcommand=self.stack_scrollbar.set) self.stack_scrollbar.config(command=self.stack.yview) # Setup weights for the "stack" tree self.stack_frame.columnconfigure(0, weight=1) self.stack_frame.columnconfigure(1, weight=0) self.stack_frame.rowconfigure(0, weight=1) # Handlers for GUI events self.stack.bind('<<TreeviewSelect>>', self.on_stack_frame_selected) def _setup_breakpoint_list(self): self.breakpoints_frame = Frame(self.content) self.breakpoints_frame.grid(column=0, row=0, sticky=(N, S, E, W)) self.file_notebook.add(self.breakpoints_frame, text='Breakpoints') self.breakpoints = BreakpointView(self.breakpoints_frame, normalizer=self.filename_normalizer) self.breakpoints.grid(column=0, row=0, sticky=(N, S, E, W)) # The tree's vertical scrollbar self.breakpoints_scrollbar = Scrollbar(self.breakpoints_frame, orient=VERTICAL) self.breakpoints_scrollbar.grid(column=1, row=0, sticky=(N, S)) # Tie the scrollbar to the text views, and the text views # to each other. self.breakpoints.config(yscrollcommand=self.breakpoints_scrollbar.set) self.breakpoints_scrollbar.config(command=self.breakpoints.yview) # Setup weights for the "breakpoint list" tree self.breakpoints_frame.columnconfigure(0, weight=1) self.breakpoints_frame.columnconfigure(1, weight=0) self.breakpoints_frame.rowconfigure(0, weight=1) # Handlers for GUI events self.breakpoints.tag_bind('breakpoint', '<Double-Button-1>', self.on_breakpoint_double_clicked) self.breakpoints.tag_bind('breakpoint', '<<TreeviewSelect>>', self.on_breakpoint_selected) self.breakpoints.tag_bind('file', '<<TreeviewSelect>>', self.on_breakpoint_file_selected) def _setup_code_area(self): self.code_frame = Frame(self.content) self.code_frame.grid(column=1, row=0, sticky=(N, S, E, W)) # Label for current file self.current_file = StringVar() self.current_file_label = Label(self.code_frame, textvariable=self.current_file) self.current_file_label.grid(column=0, row=0, sticky=(W, E)) # Code display area self.code = DebuggerCode(self.code_frame, debugger=self.debugger) self.code.grid(column=0, row=1, sticky=(N, S, E, W)) # Set up weights for the code frame's content self.code_frame.columnconfigure(0, weight=1) self.code_frame.rowconfigure(0, weight=0) self.code_frame.rowconfigure(1, weight=1) self.content.add(self.code_frame) def _setup_inspector(self): self.inspector_frame = Frame(self.content) self.inspector_frame.grid(column=2, row=0, sticky=(N, S, E, W)) self.inspector = InspectorView(self.inspector_frame) self.inspector.grid(column=0, row=0, sticky=(N, S, E, W)) # The tree's vertical scrollbar self.inspector_scrollbar = Scrollbar(self.inspector_frame, orient=VERTICAL) self.inspector_scrollbar.grid(column=1, row=0, sticky=(N, S)) # Tie the scrollbar to the text views, and the text views # to each other. self.inspector.config(yscrollcommand=self.inspector_scrollbar.set) self.inspector_scrollbar.config(command=self.inspector.yview) # Setup weights for the "breakpoint list" tree self.inspector_frame.columnconfigure(0, weight=1) self.inspector_frame.columnconfigure(1, weight=0) self.inspector_frame.rowconfigure(0, weight=1) self.content.add(self.inspector_frame) def _setup_status_bar(self): # Status bar self.statusbar = Frame(self.root) self.statusbar.grid(column=0, row=2, sticky=(W, E)) # Current status self.run_status = StringVar() self.run_status_label = Label(self.statusbar, textvariable=self.run_status) self.run_status_label.grid(column=0, row=0, sticky=(W, E)) self.run_status.set('Not running') # Main window resize handle self.grip = Sizegrip(self.statusbar) self.grip.grid(column=1, row=0, sticky=(S, E)) # Set up weights for status bar frame self.statusbar.columnconfigure(0, weight=1) self.statusbar.columnconfigure(1, weight=0) self.statusbar.rowconfigure(0, weight=0) ###################################################### # Utility methods for controlling content ###################################################### def show_file(self, filename, line=None, breakpoints=None): """Show the content of the nominated file. If specified, line is the current line number to highlight. If the line isn't currently visible, the window will be scrolled until it is. breakpoints is a list of line numbers that have current breakpoints. If refresh is true, the file will be reloaded and redrawn. """ # Set the filename label for the current file self.current_file.set(self.filename_normalizer(filename)) # Update the code view; this means changing the displayed file # if necessary, and updating the current line. if filename != self.code.filename: self.code.filename = filename for bp in self.debugger.breakpoints(filename).values(): if bp.enabled: self.code.enable_breakpoint(bp.line) else: self.code.disable_breakpoint(bp.line) self.code.line = line ###################################################### # TK Main loop ###################################################### def mainloop(self): self.root.mainloop() ###################################################### # TK Command handlers ###################################################### def cmd_quit(self): "Quit the debugger" self.debugger.stop() self.root.quit() def cmd_run(self, event=None): "Run until the next breakpoint, or end of execution" self.debugger.do_run() def cmd_step(self, event=None): "Step into the next line of code" self.debugger.do_step() def cmd_next(self, event=None): "Run the next line of code in the current frame" self.debugger.do_next() def cmd_return(self, event=None): "Return to the previous frame" self.debugger.do_return() def cmd_open_file(self, event=None): "Open a file in the breakpoint pane" filename = tkFileDialog.askopenfilename( initialdir=os.path.abspath(os.getcwd())) if filename: # Convert to canonical form filename = os.path.abspath(filename) filename = os.path.normcase(filename) # Show the file contents self.code.filename = filename # Ensure the file appears on the breakpoint list self.breakpoints.insert_filename(filename) # Show the breakpoint panel self.file_notebook.select(self.breakpoints_frame) # ... select the new filename self.breakpoints.selection_set(filename) # .. and clear any currently selected item on the stack tree self.stack.selection_remove(self.stack.selection()) def cmd_bugjar_page(self): "Show the Bugjar project page" webbrowser.open_new('http://pybee.org/bugjar') def cmd_bugjar_github(self): "Show the Bugjar GitHub repo" webbrowser.open_new('http://github.com/pybee/bugjar') def cmd_bugjar_docs(self): "Show the Bugjar documentation" # If this is a formal release, show the docs for that # version. otherwise, just show the head docs. if len(NUM_VERSION) == 3: webbrowser.open_new('http://bugjar.readthedocs.org/en/v%s/' % VERSION) else: webbrowser.open_new('http://bugjar.readthedocs.org/') def cmd_beeware_page(self): "Show the BeeWare project page" webbrowser.open_new('http://pybee.org/') ###################################################### # Handlers for GUI actions ###################################################### def on_stack_frame_selected(self, event): "When a stack frame is selected, highlight the file and line" if event.widget.selection(): _, index = event.widget.selection()[0].split(':') line, frame = self.debugger.stack[int(index)] # Display the file in the code view self.show_file(filename=frame['filename'], line=line) # Display the contents of the selected frame in the inspector self.inspector.show_frame(frame) # Clear any currently selected item on the breakpoint tree self.breakpoints.selection_remove(self.breakpoints.selection()) def on_breakpoint_selected(self, event): "When a breakpoint on the tree has been selected, show the breakpoint" if event.widget.selection(): parts = event.widget.focus().split(':') bp = self.debugger.breakpoint((parts[0], int(parts[1]))) self.show_file(filename=bp.filename, line=bp.line) # Clear any currently selected item on the stack tree self.stack.selection_remove(self.stack.selection()) def on_breakpoint_file_selected(self, event): "When a file is selected on the breakpoint tree, show the file" if event.widget.selection(): filename = event.widget.focus() self.show_file(filename=filename) # Clear any currently selected item on the stack tree self.stack.selection_remove(self.stack.selection()) def on_breakpoint_double_clicked(self, event): "When a breakpoint on the tree is double clicked, toggle it's status" if event.widget.selection(): parts = event.widget.focus().split(':') bp = self.debugger.breakpoint((parts[0], int(parts[1]))) if bp.enabled: self.debugger.disable_breakpoint(bp) else: self.debugger.enable_breakpoint(bp) # Clear any currently selected item on the stack tree self.stack.selection_remove(self.stack.selection()) ###################################################### # Handlers for debugger responses ###################################################### def on_stack(self, stack): "A report of a new stack" # Make sure the stack frame list is displayed self.file_notebook.select(self.stack_frame) # Update the stack list self.stack.update_stack(stack) if len(stack) > 0: # Update the display of the current file line = stack[-1][0] filename = stack[-1][1]['filename'] self.show_file(filename=filename, line=line) # Select the current stack frame in the frame list self.stack.selection_set('frame:%s' % (len(stack) - 1)) else: # No current frame (probably end of execution), # so clear the current line marker self.code.line = None def on_line(self, filename, line): "A single line of code has been executed" self.run_status.set('Line (%s:%s)' % (filename, line)) def on_call(self, args): "A callable has been invoked" self.run_status.set('Call: %s' % args) def on_return(self, retval): "A callable has returned" self.run_status.set('Return: %s' % retval) def on_exception(self, name, value): "An exception has been raised" self.run_status.set('Exception: %s - %s' % (name, value)) tkMessageBox.showwarning(message='%s: %s' % (name, value)) def on_postmortem(self): "An exception has been raised" self.run_status.set('Post mortem mode') tkMessageBox.showerror( message='Entering post mortem mode. Step/Next will restart') def on_restart(self): "The code has finished running, and will start again" self.run_status.set('Not running') tkMessageBox.showinfo( message='Program has finished, and will restart.') def on_info(self, message): "The debugger needs to inform the user of something" tkMessageBox.showinfo(message=message) def on_warning(self, message): "The debugger needs to warn the user of something" tkMessageBox.showwarning(message=message) def on_error(self, message): "The debugger needs to report an error" tkMessageBox.showerror(message=message) def on_breakpoint_enable(self, bp): "A breakpoint has been enabled in the debugger" # If the breakpoint is in the currently displayed file, updated # the display of the breakpoint. if bp.filename == self.code.filename: self.code.enable_breakpoint(bp.line, temporary=bp.temporary) # ... then update the display of the breakpoint on the tree self.breakpoints.update_breakpoint(bp) def on_breakpoint_disable(self, bp): "A breakpoint has been disabled in the debugger" # If the breakpoint is in the currently displayed file, updated # the display of the breakpoint. if bp.filename == self.code.filename: self.code.disable_breakpoint(bp.line) # ... then update the display of the breakpoint on the tree self.breakpoints.update_breakpoint(bp) def on_breakpoint_ignore(self, bp, count): "A breakpoint has been ignored by the debugger" # If the breakpoint is in the currently displayed file, updated # the display of the breakpoint. if bp.filename == self.code.filename: self.code.ignore_breakpoint(bp.line) # ... then update the display of the breakpoint on the tree self.breakpoints.update_breakpoint(bp) def on_breakpoint_clear(self, bp): "A breakpoint has been cleared in the debugger" # If the breakpoint is in the currently displayed file, updated # the display of the breakpoint. if bp.filename == self.code.filename: self.code.clear_breakpoint(bp.line) # ... then update the display of the breakpoint on the tree self.breakpoints.update_breakpoint(bp)
class MainWindow(object): def __init__(self, root, debugger): ''' ----------------------------------------------------- | main button toolbar | ----------------------------------------------------- | < ma | in content area > | | | | | | | File list | File name | Inspector | | (stack/ | Code area | | | breakpnts) | | | | | | | | | | | ----------------------------------------------------- | status bar area | ----------------------------------------------------- ''' # Obtain and expand the current working directory. base_path = os.path.abspath(os.getcwd()) base_path = os.path.normcase(base_path) + '/' # Create a filename normalizer based on the CWD. self.filename_normalizer = filename_normalizer(base_path) self.debugger = debugger # Associate the debugger with this view. self.debugger.view = self # Root window self.root = root self.root.title('Bugjar') self.root.geometry('1024x768') # Prevent the menus from having the empty tearoff entry self.root.option_add('*tearOff', False) # Catch the close button self.root.protocol("WM_DELETE_WINDOW", self.cmd_quit) # Catch the "quit" event. self.root.createcommand('exit', self.cmd_quit) # Setup the menu self._setup_menubar() # Set up the main content for the window. self._setup_button_toolbar() self._setup_main_content() self._setup_status_bar() # Now configure the weights for the root frame self.root.columnconfigure(0, weight=1) self.root.rowconfigure(0, weight=0) self.root.rowconfigure(1, weight=1) self.root.rowconfigure(2, weight=0) debugger.start() ###################################################### # Internal GUI layout methods. ###################################################### def _setup_menubar(self): # Menubar self.menubar = Menu(self.root) # self.menu_Apple = Menu(self.menubar, name='Apple') # self.menubar.add_cascade(menu=self.menu_Apple) self.menu_file = Menu(self.menubar) self.menubar.add_cascade(menu=self.menu_file, label='File') self.menu_program = Menu(self.menubar) self.menubar.add_cascade(menu=self.menu_program, label='Program') self.menu_help = Menu(self.menubar) self.menubar.add_cascade(menu=self.menu_help, label='Help') # self.menu_Apple.add_command(label='Test', command=self.cmd_dummy) # self.menu_file.add_command(label='New', command=self.cmd_dummy, accelerator="Command-N") self.menu_file.add_command(label='Open...', command=self.cmd_open_file, accelerator="Command-O") self.root.bind('<Command-o>', self.cmd_open_file) # self.menu_file.add_command(label='Close', command=self.cmd_dummy) self.menu_program.add_command(label='Run', command=self.cmd_run, accelerator="R") self.root.bind('<r>', self.cmd_run) self.menu_program.add_command(label='Step', command=self.cmd_step, accelerator="S") self.root.bind('<s>', self.cmd_step) self.menu_program.add_command(label='Next', command=self.cmd_next, accelerator="N") self.root.bind('<n>', self.cmd_next) self.menu_program.add_command(label='Return', command=self.cmd_return, accelerator="BackSpace") self.root.bind('<BackSpace>', self.cmd_return) self.menu_help.add_command(label='Open Documentation', command=self.cmd_bugjar_docs) self.menu_help.add_command(label='Open Bugjar project page', command=self.cmd_bugjar_page) self.menu_help.add_command(label='Open Bugjar on GitHub', command=self.cmd_bugjar_github) self.menu_help.add_command(label='Open BeeWare project page', command=self.cmd_beeware_page) # last step - configure the menubar self.root['menu'] = self.menubar def _setup_button_toolbar(self): ''' The button toolbar runs as a horizontal area at the top of the GUI. It is a persistent GUI component ''' # Main toolbar self.toolbar = Frame(self.root) self.toolbar.grid(column=0, row=0, sticky=(W, E)) # Buttons on the toolbar self.run_button = Button(self.toolbar, text='Run', command=self.cmd_run) self.run_button.grid(column=0, row=0) self.step_button = Button(self.toolbar, text='Step', command=self.cmd_step) self.step_button.grid(column=1, row=0) self.next_button = Button(self.toolbar, text='Next', command=self.cmd_next) self.next_button.grid(column=2, row=0) self.return_button = Button(self.toolbar, text='Return', command=self.cmd_return) self.return_button.grid(column=3, row=0) self.toolbar.columnconfigure(0, weight=0) self.toolbar.rowconfigure(0, weight=0) def _setup_main_content(self): ''' Sets up the main content area. It is a persistent GUI component ''' # Main content area self.content = PanedWindow(self.root, orient=HORIZONTAL) self.content.grid(column=0, row=1, sticky=(N, S, E, W)) # Create subregions of the content self._setup_file_lists() self._setup_code_area() self._setup_inspector() # Set up weights for the left frame's content self.content.columnconfigure(0, weight=1) self.content.rowconfigure(0, weight=1) self.content.pane(0, weight=1) self.content.pane(1, weight=2) self.content.pane(2, weight=1) def _setup_file_lists(self): self.file_notebook = Notebook(self.content, padding=(0, 5, 0, 5)) self.content.add(self.file_notebook) self._setup_stack_frame_list() self._setup_breakpoint_list() def _setup_stack_frame_list(self): self.stack_frame = Frame(self.content) self.stack_frame.grid(column=0, row=0, sticky=(N, S, E, W)) self.file_notebook.add(self.stack_frame, text='Stack') self.stack = StackView(self.stack_frame, normalizer=self.filename_normalizer) self.stack.grid(column=0, row=0, sticky=(N, S, E, W)) # # The tree's vertical scrollbar self.stack_scrollbar = Scrollbar(self.stack_frame, orient=VERTICAL) self.stack_scrollbar.grid(column=1, row=0, sticky=(N, S)) # # Tie the scrollbar to the text views, and the text views # # to each other. self.stack.config(yscrollcommand=self.stack_scrollbar.set) self.stack_scrollbar.config(command=self.stack.yview) # Setup weights for the "stack" tree self.stack_frame.columnconfigure(0, weight=1) self.stack_frame.columnconfigure(1, weight=0) self.stack_frame.rowconfigure(0, weight=1) # Handlers for GUI events self.stack.bind('<<TreeviewSelect>>', self.on_stack_frame_selected) def _setup_breakpoint_list(self): self.breakpoints_frame = Frame(self.content) self.breakpoints_frame.grid(column=0, row=0, sticky=(N, S, E, W)) self.file_notebook.add(self.breakpoints_frame, text='Breakpoints') self.breakpoints = BreakpointView(self.breakpoints_frame, normalizer=self.filename_normalizer) self.breakpoints.grid(column=0, row=0, sticky=(N, S, E, W)) # The tree's vertical scrollbar self.breakpoints_scrollbar = Scrollbar(self.breakpoints_frame, orient=VERTICAL) self.breakpoints_scrollbar.grid(column=1, row=0, sticky=(N, S)) # Tie the scrollbar to the text views, and the text views # to each other. self.breakpoints.config(yscrollcommand=self.breakpoints_scrollbar.set) self.breakpoints_scrollbar.config(command=self.breakpoints.yview) # Setup weights for the "breakpoint list" tree self.breakpoints_frame.columnconfigure(0, weight=1) self.breakpoints_frame.columnconfigure(1, weight=0) self.breakpoints_frame.rowconfigure(0, weight=1) # Handlers for GUI events self.breakpoints.tag_bind('breakpoint', '<Double-Button-1>', self.on_breakpoint_double_clicked) self.breakpoints.tag_bind('breakpoint', '<<TreeviewSelect>>', self.on_breakpoint_selected) self.breakpoints.tag_bind('file', '<<TreeviewSelect>>', self.on_breakpoint_file_selected) def _setup_code_area(self): self.code_frame = Frame(self.content) self.code_frame.grid(column=1, row=0, sticky=(N, S, E, W)) # Label for current file self.current_file = StringVar() self.current_file_label = Label(self.code_frame, textvariable=self.current_file) self.current_file_label.grid(column=0, row=0, sticky=(W, E)) # Code display area self.code = DebuggerCode(self.code_frame, debugger=self.debugger) self.code.grid(column=0, row=1, sticky=(N, S, E, W)) # Set up weights for the code frame's content self.code_frame.columnconfigure(0, weight=1) self.code_frame.rowconfigure(0, weight=0) self.code_frame.rowconfigure(1, weight=1) self.content.add(self.code_frame) def _setup_inspector(self): self.inspector_frame = Frame(self.content) self.inspector_frame.grid(column=2, row=0, sticky=(N, S, E, W)) self.inspector = InspectorView(self.inspector_frame) self.inspector.grid(column=0, row=0, sticky=(N, S, E, W)) # The tree's vertical scrollbar self.inspector_scrollbar = Scrollbar(self.inspector_frame, orient=VERTICAL) self.inspector_scrollbar.grid(column=1, row=0, sticky=(N, S)) # Tie the scrollbar to the text views, and the text views # to each other. self.inspector.config(yscrollcommand=self.inspector_scrollbar.set) self.inspector_scrollbar.config(command=self.inspector.yview) # Setup weights for the "breakpoint list" tree self.inspector_frame.columnconfigure(0, weight=1) self.inspector_frame.columnconfigure(1, weight=0) self.inspector_frame.rowconfigure(0, weight=1) self.content.add(self.inspector_frame) def _setup_status_bar(self): # Status bar self.statusbar = Frame(self.root) self.statusbar.grid(column=0, row=2, sticky=(W, E)) # Current status self.run_status = StringVar() self.run_status_label = Label(self.statusbar, textvariable=self.run_status) self.run_status_label.grid(column=0, row=0, sticky=(W, E)) self.run_status.set('Not running') # Main window resize handle self.grip = Sizegrip(self.statusbar) self.grip.grid(column=1, row=0, sticky=(S, E)) # Set up weights for status bar frame self.statusbar.columnconfigure(0, weight=1) self.statusbar.columnconfigure(1, weight=0) self.statusbar.rowconfigure(0, weight=0) ###################################################### # Utility methods for controlling content ###################################################### def show_file(self, filename, line=None, breakpoints=None): """Show the content of the nominated file. If specified, line is the current line number to highlight. If the line isn't currently visible, the window will be scrolled until it is. breakpoints is a list of line numbers that have current breakpoints. If refresh is true, the file will be reloaded and redrawn. """ # Set the filename label for the current file self.current_file.set(self.filename_normalizer(filename)) # Update the code view; this means changing the displayed file # if necessary, and updating the current line. if filename != self.code.filename: self.code.filename = filename for bp in self.debugger.breakpoints(filename).values(): if bp.enabled: self.code.enable_breakpoint(bp.line) else: self.code.disable_breakpoint(bp.line) self.code.line = line ###################################################### # TK Main loop ###################################################### def mainloop(self): self.root.mainloop() ###################################################### # TK Command handlers ###################################################### def cmd_quit(self): "Quit the debugger" self.debugger.stop() self.root.quit() def cmd_run(self, event=None): "Run until the next breakpoint, or end of execution" self.debugger.do_run() def cmd_step(self, event=None): "Step into the next line of code" self.debugger.do_step() def cmd_next(self, event=None): "Run the next line of code in the current frame" self.debugger.do_next() def cmd_return(self, event=None): "Return to the previous frame" self.debugger.do_return() def cmd_open_file(self, event=None): "Open a file in the breakpoint pane" filename = tkFileDialog.askopenfilename(initialdir=os.path.abspath(os.getcwd())) if filename: # Convert to canonical form filename = os.path.abspath(filename) filename = os.path.normcase(filename) # Show the file contents self.code.filename = filename # Ensure the file appears on the breakpoint list self.breakpoints.insert_filename(filename) # Show the breakpoint panel self.file_notebook.select(self.breakpoints_frame) # ... select the new filename self.breakpoints.selection_set(filename) # .. and clear any currently selected item on the stack tree self.stack.selection_remove(self.stack.selection()) def cmd_bugjar_page(self): "Show the Bugjar project page" webbrowser.open_new('http://pybee.org/bugjar') def cmd_bugjar_github(self): "Show the Bugjar GitHub repo" webbrowser.open_new('http://github.com/pybee/bugjar') def cmd_bugjar_docs(self): "Show the Bugjar documentation" # If this is a formal release, show the docs for that # version. otherwise, just show the head docs. if len(NUM_VERSION) == 3: webbrowser.open_new('http://bugjar.readthedocs.org/en/v%s/' % VERSION) else: webbrowser.open_new('http://bugjar.readthedocs.org/') def cmd_beeware_page(self): "Show the BeeWare project page" webbrowser.open_new('http://pybee.org/') ###################################################### # Handlers for GUI actions ###################################################### def on_stack_frame_selected(self, event): "When a stack frame is selected, highlight the file and line" if event.widget.selection(): _, index = event.widget.selection()[0].split(':') line, frame = self.debugger.stack[int(index)] # Display the file in the code view self.show_file(filename=frame['filename'], line=line) # Display the contents of the selected frame in the inspector self.inspector.show_frame(frame) # Clear any currently selected item on the breakpoint tree self.breakpoints.selection_remove(self.breakpoints.selection()) def on_breakpoint_selected(self, event): "When a breakpoint on the tree has been selected, show the breakpoint" if event.widget.selection(): parts = event.widget.focus().split(':') bp = self.debugger.breakpoint((parts[0], int(parts[1]))) self.show_file(filename=bp.filename, line=bp.line) # Clear any currently selected item on the stack tree self.stack.selection_remove(self.stack.selection()) def on_breakpoint_file_selected(self, event): "When a file is selected on the breakpoint tree, show the file" if event.widget.selection(): filename = event.widget.focus() self.show_file(filename=filename) # Clear any currently selected item on the stack tree self.stack.selection_remove(self.stack.selection()) def on_breakpoint_double_clicked(self, event): "When a breakpoint on the tree is double clicked, toggle it's status" if event.widget.selection(): parts = event.widget.focus().split(':') bp = self.debugger.breakpoint((parts[0], int(parts[1]))) if bp.enabled: self.debugger.disable_breakpoint(bp) else: self.debugger.enable_breakpoint(bp) # Clear any currently selected item on the stack tree self.stack.selection_remove(self.stack.selection()) ###################################################### # Handlers for debugger responses ###################################################### def on_stack(self, stack): "A report of a new stack" # Make sure the stack frame list is displayed self.file_notebook.select(self.stack_frame) # Update the stack list self.stack.update_stack(stack) if len(stack) > 0: # Update the display of the current file line = stack[-1][0] filename = stack[-1][1]['filename'] self.show_file(filename=filename, line=line) # Select the current stack frame in the frame list self.stack.selection_set('frame:%s' % (len(stack) - 1)) else: # No current frame (probably end of execution), # so clear the current line marker self.code.line = None def on_line(self, filename, line): "A single line of code has been executed" self.run_status.set('Line (%s:%s)' % (filename, line)) def on_call(self, args): "A callable has been invoked" self.run_status.set('Call: %s' % args) def on_return(self, retval): "A callable has returned" self.run_status.set('Return: %s' % retval) def on_exception(self, name, value): "An exception has been raised" self.run_status.set('Exception: %s - %s' % (name, value)) tkMessageBox.showwarning(message='%s: %s' % (name, value)) def on_postmortem(self): "An exception has been raised" self.run_status.set('Post mortem mode') tkMessageBox.showerror(message='Entering post mortem mode. Step/Next will restart') def on_restart(self): "The code has finished running, and will start again" self.run_status.set('Not running') tkMessageBox.showinfo(message='Program has finished, and will restart.') def on_info(self, message): "The debugger needs to inform the user of something" tkMessageBox.showinfo(message=message) def on_warning(self, message): "The debugger needs to warn the user of something" tkMessageBox.showwarning(message=message) def on_error(self, message): "The debugger needs to report an error" tkMessageBox.showerror(message=message) def on_breakpoint_enable(self, bp): "A breakpoint has been enabled in the debugger" # If the breakpoint is in the currently displayed file, updated # the display of the breakpoint. if bp.filename == self.code.filename: self.code.enable_breakpoint(bp.line, temporary=bp.temporary) # ... then update the display of the breakpoint on the tree self.breakpoints.update_breakpoint(bp) def on_breakpoint_disable(self, bp): "A breakpoint has been disabled in the debugger" # If the breakpoint is in the currently displayed file, updated # the display of the breakpoint. if bp.filename == self.code.filename: self.code.disable_breakpoint(bp.line) # ... then update the display of the breakpoint on the tree self.breakpoints.update_breakpoint(bp) def on_breakpoint_ignore(self, bp, count): "A breakpoint has been ignored by the debugger" # If the breakpoint is in the currently displayed file, updated # the display of the breakpoint. if bp.filename == self.code.filename: self.code.ignore_breakpoint(bp.line) # ... then update the display of the breakpoint on the tree self.breakpoints.update_breakpoint(bp) def on_breakpoint_clear(self, bp): "A breakpoint has been cleared in the debugger" # If the breakpoint is in the currently displayed file, updated # the display of the breakpoint. if bp.filename == self.code.filename: self.code.clear_breakpoint(bp.line) # ... then update the display of the breakpoint on the tree self.breakpoints.update_breakpoint(bp)
class MainApplication(Tk): def __init__(self, network_discoverer): Tk.__init__(self) self.winfo_toplevel().title("fHTTP") self.title_font = tkfont.Font(family='Helvetica', size=14, weight='bold', slant='italic') self.h2_font = tkfont.Font(family='Helvetica', size=12, weight='bold') self.h3_font = tkfont.Font(family='Helvetica', size=11, weight='bold') self.network_discoverer = network_discoverer self.own_mac_address = network_discoverer.get_own_mac_address() self.own_ip_address = network_discoverer.get_own_ip_address() self.ip_to_mac = None self.ip_to_mac_record = None self.configure(background='darkgrey') self.is_spoofing = self.is_extracting = self.is_filtering = False self.verbose_mode = False # verbose mode on/off for output frame self.victims = None self.target = None width = int(self.winfo_screenwidth() * 0.5) height = int(self.winfo_screenheight() * 0.8) x_start = int(self.winfo_screenwidth() * 0.25) y_start = int(self.winfo_screenheight() * 0.1) self.geometry('%dx%d+%d+%d' % (width, height, x_start, y_start)) self.resizable(0, 0) # do not feel like dealing with resizable frames self.conf_menu_bar() # configure menu-bar img_icon = PhotoImage(file=media_dir + os.path.sep + 'fhttp_logo.ico') self.tk.call('wm', 'iconphoto', self._w, img_icon) for row in range(0, 100): self.rowconfigure(row, weight=1) self.columnconfigure(row, weight=1) # notebook configuration (tabs) style = Style() style.theme_settings( "default", { "TNotebook": { "configure": { "tabmargins": [0, 0, 0, 0] } }, "TNotebook.Tab": { "configure": { "padding": [8, 1, 8, 1] } } }) self.notebook = Notebook(self) self.notebook.grid(row=1, column=0, columnspan=100, rowspan=10, sticky='nesw', padx=5) # output frame configuration self.output = OutputFrame(parent=self) self.output.grid(row=13, column=0, columnspan=100, rowspan=85, sticky='nesw', padx=5) # notebook frames self.tabs = {} self.tab_mapping = OrderedDict([ (StartFrame, 'Start'), (LocalNetworkScanFrame, 'Local Network Scan'), (ARPSpoofFrame, 'ARP Spoofing'), (InjectorExtractorFrame, 'Injection and Extraction') ]) for tab in self.tab_mapping.keys(): tab_frame_name = self.tab_mapping[tab] frame = tab(parent=self.notebook, controller=self) self.notebook.add(frame, text=tab_frame_name) self.tabs[tab.__name__] = frame self.notebook.tab(self.notebook.index( self.tabs['InjectorExtractorFrame']), state=DISABLED) self.notebook.tab(self.notebook.index(self.tabs['ARPSpoofFrame']), state=DISABLED) tkMessageBox.showinfo( "fHTTP", "\n\n\nWelcome to fhttp\n\n" "We inherently trust no one, including each other\n\n\n".ljust( 500)) def conf_menu_bar(self): menu_bar = Menu(self) # help menu help_menu = Menu(menu_bar, tearoff=0) help_menu.add_command(label='About', command=self.display_about) help_menu.add_command(label='Support and Documentation', command=self.display_support_doc) # help_menu.add_separator() menu_bar.add_cascade(label='Help', menu=help_menu) menu_bar.add_command(label='Exit', command=self.quit) self.config(menu=menu_bar) def clean_output_and_attack_frame(self): self.output = OutputFrame(parent=self) self.output.grid(row=13, column=0, columnspan=100, rowspan=85, sticky='nesw', padx=5) @staticmethod def display_about(): tkMessageBox.showinfo( "About", "fhttp is an application which is capable of exploiting vulnerabilities " "such as ARP cache poisoning. The (man-in-the-middle) positions that are acquired " "through the exploitation of these vulnerabilities are then used for things such as " "packet-sniffing, the `theft' of (insecure) cookies and img-tag-injection\n\n" "Abdel K. Bokharouss and Adriaan Knapen \n") @staticmethod def display_support_doc(): webbrowser.open('https://github.com/akbokha/fhttp') def show_frame(self, page_name, select=True, update=False): frame = self.tabs[page_name] if update: try: frame.update() except AttributeError: pass if select: self.notebook.select(self.notebook.index(frame)) def scan_and_update(self): self.ip_to_mac_record = self.network_discoverer.get_ip_to_mac_mapping( update=True) self.ip_to_mac = self.ip_to_mac_record.get_all()
class Application(tk.Frame): def __init__(self, master): tk.Frame.__init__(self, master) self.master = master self.master.title("Netstat Live") self.pack(fill=tk.BOTH, expand=tk.Y) master.protocol("WM_DELETE_WINDOW", self.app_quit) self._app_quit = False self._freeze = False self.tabs = Notebook(self) self.tabs_frames = OrderedDict() self.tabs_frames['TCP4'] = {'query': netstat_tcp4} self.tabs_frames['UDP4'] = {'query': netstat_udp4} self.tabs_frames['TCP6'] = {'query': netstat_tcp6} self.tabs_frames['UDP6'] = {'query': netstat_udp6} for tab in self.tabs_frames: # Creating tabs self.tabs_frames[tab]['tab'] = tk.Frame(self.tabs) self.tabs.add(self.tabs_frames[tab]['tab'], text=tab) #self.tabs_frames[tab]['tab'].pack(fill=tk.BOTH) # Adding Treeview widget to tabs self.tabs_frames[tab]['tbl'] = Treeview(self.tabs_frames[tab]['tab']) self.tabs_frames[tab]['tbl']['columns'] = ('Pid', 'User', 'Local addr', 'Remote addr', 'State') for column in self.tabs_frames[tab]['tbl']['columns']: self.tabs_frames[tab]['tbl'].heading(column, text=column) self.tabs_frames[tab]['tbl'].column(column, width=150) self.tabs_frames[tab]['scrollbar_y'] = Scrollbar(self.tabs_frames[tab]['tab'], orient=tk.VERTICAL, command=self.tabs_frames[tab]['tbl'].yview) self.tabs_frames[tab]['tbl']['yscroll'] = self.tabs_frames[tab]['scrollbar_y'].set self.tabs_frames[tab]['scrollbar_y'].pack(side=tk.RIGHT, fill=tk.Y) self.tabs_frames[tab]['tbl'].pack(expand=tk.Y, fill=tk.BOTH) # Bind right click event for displaying context menu self.tabs_frames[tab]['tbl'].bind('<Button-3>', self.context_menu_popup) self.tabs_frames[tab]['tbl'].bind('<Button-1>', self.context_menu_unpost) # Creating queue for each tab self.tabs_frames[tab]['queue'] = Queue(maxsize=1) self.tabs.pack(fill=tk.BOTH, expand=tk.Y) # Freeze button self.buttons = tk.Frame(master) self.buttons.pack(side=tk.BOTTOM, fill=tk.BOTH) self.freeze_btn = tk.Button(self.buttons, text='Freeze', command=self.freeze_btn_handler) self.freeze_btn.pack(side=tk.RIGHT) # Check dependencies self._xclip = True self._whois = True try: out = subprocess.check_output(['xclip', '-h'], stderr=subprocess.STDOUT) except: self._xclip = False try: out = subprocess.check_output(['whois', '--version'], stderr=subprocess.STDOUT) except: self._whois = False # Connections list context menu self._remote_addr = '' self.context_menu = tk.Menu(self, tearoff=0) if self._xclip: self.context_menu.add_command(label='Copy remote addr.', command=self.xclip) if self._whois: self.context_menu.add_command(label='Whois', command=self.whois) self.tabs.bind('<Button-1>', self.context_menu_unpost) self.poll = Thread(target=self.thread) self.poll.start() def context_menu_popup(self, event): current_tab = self.get_active_tab() tbl = self.tabs_frames[current_tab]['tbl'] item = tbl.identify_row(event.y) if item and len(tbl.get_children(item)) == 0: tbl.selection_set(item) # Get remote addr value self._remote_addr = tbl.set(item, column='Remote addr') self.context_menu.post(event.x_root, event.y_root) else: # Mouse pointer is not over item pass def context_menu_unpost(self, event): self.context_menu.unpost() def get_active_tab(self): try: current_tab = self.tabs.tab(self.tabs.select(), 'text') return current_tab except RuntimeError: # Sometimes raised on KeyboardInterrupt sys.stderr.write('Terminated.\n') self._app_quit = True sys.exit(0) def thread(self): while not self._app_quit: current_tab = self.tabs_frames[self.get_active_tab()] if current_tab['queue'].empty(): # Get netstat data try: netstat = current_tab['query']() except RuntimeError: sys.stderr.write('Main thread destroyed.\n') # Put to queue current_tab['queue'].put(netstat, True) else: sleep(0.5) def app_quit(self): self._app_quit = True self.master.destroy() def refresh(self): current_tab = self.get_active_tab() queue = self.tabs_frames[current_tab]['queue'] if not self._freeze and not queue.empty(): # Get active tab tbl = self.tabs_frames[current_tab]['tbl'] # Remember focus self.tabs_frames[current_tab]['focus'] = tbl.selection() data = queue.get(False) processes = [] for proc in data: processes.append(proc[6]) processes = tuple(set(processes)) # Unique list of processes in netstat # Clear tree: for proc in tbl.get_children(): tbl.delete(*tbl.get_children(proc)) for proc in processes: proc_name = '%s (%s)' % (os.path.basename(str(proc)), str(proc)) if not tbl.exists(proc_name): # Create root items for each process name tbl.insert('', 'end', proc_name, text=proc_name) for proc in data: proc_name = '%s (%s)' % (os.path.basename(str(proc[6])), str(proc[6])) # Pid User Local addr Remote addr State values = (str(proc[5]), str(proc[1]), str(proc[2]), str(proc[3]), str(proc[4])) h = hash(tuple(proc)) try: tbl.insert(proc_name, 'end', h, text=proc_name, values=values) except: pass # Removing empty root items for proc in tbl.get_children(): if len(tbl.get_children(proc)) == 0: tbl.delete(proc) # Restore focus try: tbl.selection_set(self.tabs_frames[current_tab]['focus']) except: pass self.master.after(500, self.refresh) def freeze_btn_handler(self): # Toggle freeze state if self._freeze: self.freeze_btn['text'] = 'Freeze' else: self.freeze_btn['text'] = 'Continue' self._freeze = not self._freeze def xclip(self, data=None): if not data: data = self._remote_addr try: xclip = subprocess.Popen(['xclip', '-selection', 'clipboard'], stdin=subprocess.PIPE) xclip.communicate(input=data) xclip.terminate() except: pass def whois(self, addr=None): if not addr: addr = self._remote_addr addr = addr.split(':') try: reverse = subprocess.check_output(['dig', '+short', '-x', addr[0]]) except: reverse = None try: out = subprocess.check_output(['whois', addr[0]]) except: out = 'No info for this host.' self.whois_popup = {} self.whois_popup['window'] = tk.Toplevel(self) self.whois_popup['window'].title('Whois %s' % addr[0]) self.whois_popup['frame'] = tk.Frame(self.whois_popup['window']) self.whois_popup['frame'].pack(fill=tk.BOTH, expand=tk.Y) self.whois_popup['text'] = tk.Text(self.whois_popup['frame'], wrap=tk.WORD, height=32, width=96) self.whois_popup['text'].pack(fill=tk.BOTH, expand=tk.Y, side=tk.LEFT) self.whois_popup['scrollbar_y'] = Scrollbar(self.whois_popup['frame']) self.whois_popup['scrollbar_y'].config(command=self.whois_popup['text'].yview) self.whois_popup['scrollbar_y'].pack(side=tk.RIGHT, fill=tk.Y) self.whois_popup['text'].config(yscrollcommand=self.whois_popup['scrollbar_y'].set) if reverse: reverse = 'Reverse lookup: %s\n' % reverse self.whois_popup['text'].insert(tk.END, reverse) self.whois_popup['text'].insert(tk.END, out) tk.Button(self.whois_popup['window'], text='Ok', command=self.whois_popup['window'].destroy).pack()
class Interface(): def __init__(self): print("PASTA ATUAL MAIN: " + os.getcwd()) self.errorReport = ErrorReport("logs_errors/error_db.log") self.db = DatabaseGui() if self.db.checkStatus(): self.defineFontsVars() self.configWindow("1.0.0") self.defineVars() self.configWidgetsMenuOptions() self.configWidgetsCreateForm() self.configWidgetsGetApps() self.setWidgets() ############################ FUNCAO TEMPORARIA APENAS PARA DESENVOLVIMENTO self.nextTabFrameFieldForm() else: self.errorReport.showAndSaveError( self.db.getErrorDb(), "Erro ao inicializar banco de dados") def defineVars(self): self.frameOld = None self.optionVar = IntVar() self.nameFormVar = StringVar() self.pathImageFormVar = StringVar() self.titleFormVar = StringVar() self.validateDateReg = self.window.register(validateDate) self.validatePhoneReg = self.window.register(validatePhone) self.nameFormVar.trace("w", self.checkInfoAppCompleted) self.pathImageFormVar.trace("w", self.checkInfoAppCompleted) self.menuOptionsFunctions = [ self.activeOptionCreateForm, self.activeOptionGetApps ] self.listElementThisForm = {} self.idTemporaryElement = 0 self.menuRightStateVar = False def defineFontsVars(self): self.font = ("Arial", 13) self.fontMin = ("Arial", 10) self.fontMax = ("Arial", 15) def setWidgets(self): self.optionVar.set(0) self.pathImageFormVar.set("link da imagem") self.rb1.invoke( ) #Aciona o RadioButton CreateForm para renderizar os elementos na frameCreateForm def configWindow(self, version): self.window = Tk() self.window.title("Forms App {}".format(version)) self.window.geometry("900x500+150+100") self.window.iconbitmap("images/imagesFormsApp/imageApp.ico") title = "Crie seu App, formulários, realize estatísticas, \nedite e estude seus dados com o Forms App" image = renderPhoto("images/imagesFormsApp/imageApp.png", (60, 60)) Label(self.window, font=("Arial Rounded MT Bold", 15), background="thistle", foreground="chocolate", \ text=title, padx=10, pady=10, image=image, compound=RIGHT)\ .pack(side=TOP, fill="x", ipady=5) self.frameBody = Frame(self.window, background="paleturquoise") self.frameBody.pack(side=TOP, expand=True, fill=BOTH) self.menuRight = Frame(self.frameBody, background="paleturquoise", width=150) self.menuRight.pack(side=RIGHT, fill=Y) def configWidgetsMenuOptions(self): frameOptions = Frame(self.frameBody, background="paleturquoise") frameOptions.pack(side=LEFT, fill=Y, padx=5, pady=5) self.rb1 = Radiobutton(frameOptions, font=self.font, text="Novo App", variable=self.optionVar, value=0, indicatoron=0, width=15, height=2, command=self.actionOptions) self.rb1.grid(row=1, column=0) self.rb2 = Radiobutton(frameOptions, font=self.font, text="Todos", variable=self.optionVar, value=1, indicatoron=0, width=15, height=2, command=self.actionOptions) self.rb2.grid(row=2, column=0) def configWidgetsCreateForm(self): self.frameCreateForm = Frame(self.frameBody) self.framesNotebook = Notebook(self.frameCreateForm) self.framesNotebook.pack(expand=True, fill=BOTH) self.tabFrameInfoForm = Frame(self.framesNotebook) self.tabFrameFieldForm = Frame(self.framesNotebook) self.framesNotebook.add(self.tabFrameInfoForm, compound=LEFT, image=renderPhoto( "images\\imagesFormsApp\\app.png", (40, 40)), sticky=W + E + N + S, text="Info App", padding='0.1i') self.framesNotebook.add(self.tabFrameFieldForm, compound=LEFT, image=renderPhoto( "images\\imagesFormsApp\\document.png", (40, 40)), sticky=W + E + N + S, text="Item", padding='0.1i') self.framesNotebook.hide(self.tabFrameFieldForm) # -------------- tabFrameInfoForm ------------- title = "Crie seu App aqui" Label(self.tabFrameInfoForm, text=title, font=self.font)\ .grid(row=0, column=0, columnspan=5) Label(self.tabFrameInfoForm, text="Nome", font=self.fontMin).grid(row=1, column=0) inputName = Entry(self.tabFrameInfoForm, font=self.fontMin, textvariable=self.nameFormVar) inputName.grid(row=1, column=1, pady=10, sticky=W + E + N + S) #inputName.bind("<KeyPress>", self.checkInfoAppCompleted) Label(self.tabFrameInfoForm, text="Descrição", font=self.fontMin).grid(row=2, column=0) self.textWidget = Text(self.tabFrameInfoForm, pady=10, font=self.fontMin, width=50, height=3) self.textWidget.grid(row=2, column=1, sticky=W + E + N + S) self.descriptionFormVar = self.createVarByTextWidget(self.textWidget) self.imageWidget = Label(self.tabFrameInfoForm, padx=10, pady=10, background="lightcyan", anchor=N) self.imageWidget.grid(row=1, column=2, rowspan=2, sticky=W + E + N + S, padx=10, pady=10) Label(self.tabFrameInfoForm, padx=10, pady=10, background="lightcyan", font=self.fontMin, textvariable=self.pathImageFormVar)\ .grid(row=3, column=1, sticky=W+E+N+S) Button(self.tabFrameInfoForm, font=self.fontMin, text="Procurar Imagem", command=self.actionChoiseImageForm)\ .grid(row=3, column=2, padx=10, pady=10) self.buttonNext = Button(self.tabFrameInfoForm, state="disabled", font=self.fontMin, text="Prosseguir", command=self.actionNextTabFrameFieldForm) self.buttonNext.grid(row=4, column=1, padx=20, pady=15) # -------------- tabFrameFieldForm ------------- Label(self.tabFrameFieldForm, textvariable=self.titleFormVar, font=self.font)\ .pack(side=TOP) frameBodyForm = Frame(self.tabFrameFieldForm, background="lightcyan") frameBodyForm.pack(side=TOP, fill=BOTH, expand=True, padx=5) frameMenuElementsForm = Frame( frameBodyForm) #Frame que contera todos os elementos existentes frameMenuElementsForm.pack(side=LEFT, fill=Y, ipadx=5) self.frameRenderElementsForm = Frame( frameBodyForm ) #Frame que contera todos os elementos escolhidos pelo usuario self.frameRenderElementsForm.pack(side=LEFT, fill=Y, ipadx=5, ipady=5) Label(frameMenuElementsForm, text="Elementos", font=self.font).pack(side=TOP) for element in self.db.getAllElemments( ): #Mostra todos os elementos em forma de botoes para serem adicionados no formulário function = lambda id_element=element[0], name_element=element[1], type_element=element[2], multline=element[3], widget_tkinter=element[5]:\ self.actionAddElement(id_element, name_element, type_element, multline, widget_tkinter) Button(frameMenuElementsForm, width=15, height=2, \ text=element[1], command=function, repeatdelay=700, \ borderwidth=3, activebackground="lightseagreen", \ background="darkcyan", cursor="sb_right_arrow").pack(side=TOP) #Cria opcoes especificas no meu direito para FieldForm self.createMenuSideForFieldForm() def checkInfoAppCompleted( self, a, b, c ): #checa se todos os campos de informacoes do app foram preenchidas if self.nameFormVar.get( ) and self.pathImageFormVar.get() <> "link da imagem": self.buttonNext.config(state="active") self.titleFormVar.set("Crie o formulário para seu App( " + self.nameFormVar.get() + " ) aqui!") else: self.activeDeactivateTabFrameFieldForm() self.buttonNext.config(state="disabled") self.buttonSaveApp.config(state="disabled") def checkFormCompleted(self): if self.listElementThisForm: self.buttonSaveApp.config(state="active") else: self.buttonSaveApp.config(state="disabled") def actionAddElement( self, id_element, name_element, type_element, multline, widget_tkinter ): #Adiciona elemento para renderizacao com evento de botao infoAppFrame = Frame(self.frameRenderElementsForm, background="powderblue") infoAppFrame.pack(side=TOP, fill=X) infoAppFrame.idTemporaryElement = self.idTemporaryElement def removeElement( ): #Funcao que remove o frame da tela e deleta o item da lista de elementos adicionados do formulario del self.listElementThisForm[infoAppFrame.idTemporaryElement] infoAppFrame.destroy() self.checkFormCompleted() Button(infoAppFrame, text="X", command=removeElement, font=("Arial", 6), takefocus=False)\ .pack(side=RIGHT, ipadx=2, padx=2) nameElementVar = StringVar() nameElement = Entry(infoAppFrame, width=18, justify=CENTER, relief=FLAT, \ textvariable=nameElementVar, font=("Agency FB", 14)) nameElement.pack(side=LEFT, padx=10, fill=X) nameElementVar.set(name_element) nameElement.focus_force() nameElement.select_range(0, END) self.viewElement(infoAppFrame, widget_tkinter) #Salva na lista o id do elemento,nome da variavel controladora e o tipo de dado que sera inserido no banco self.listElementThisForm[self.idTemporaryElement] = (id_element, nameElementVar, type_element, infoAppFrame) self.idTemporaryElement += 1 self.checkFormCompleted() def viewElement(self, infoAppFrame, widget_tkinter): "Apenas renderiza os elementos na tela sem mais configuracoes" if widget_tkinter == "entry": inputElement = Entry(infoAppFrame, takefocus=False, state="disabled", width=40, font=self.font) elif widget_tkinter == "text": inputElement = Text(infoAppFrame, takefocus=False, state="disabled", width=40, height=4, font=self.font) elif widget_tkinter == "spinbox": inputElement = Spinbox(infoAppFrame, takefocus=False, state="disabled", width=7, font=self.font) elif widget_tkinter == "entry-date": inputElement = Entry(infoAppFrame, takefocus=False, state="disabled", width=10, font=self.font) elif widget_tkinter == "entry-phone": inputElement = Entry(infoAppFrame, takefocus=False, state="disabled", width=15, font=self.font) inputElement.pack(side=LEFT, padx=10, pady=10) return inputElement def renderElement(self, infoAppFrame, widget_tkinter): "Renderiza os elementos na tela com configurações de variáveis" inputElementVar = None if widget_tkinter == "entry": inputElementVar = StringVar() inputElement = Entry(infoAppFrame, width=40, textvariable=inputElementVar, font=self.font) elif widget_tkinter == "entry-date": inputElementVar = StringVar() inputElement = Entry(infoAppFrame, width=10, textvariable=inputElementVar, font=self.font) inputElement.config(validate="key", validatecommand=(self.validadeDateReg, '%i', '%P', '%S', '%s')) elif widget_tkinter == "entry-phone": inputElementVar = StringVar() inputElement = Entry(infoAppFrame, width=15, textvariable=inputElementVar, font=self.font) inputElement.config(validate="key", validatecommand=(self.validadePhoneReg, '%i', '%P', '%S', '%s')) elif widget_tkinter == "spinbox": inputElementVar = StringVar() inputElement = Spinbox(infoAppFrame, width=5, textvariable=inputElementVar, font=self.font) elif widget_tkinter == "text": inputElement = Text(infoAppFrame, width=40, height=4, font=self.font) inputElementVar = self.createVarByTextWidget(inputElement) inputElement.pack(side=LEFT, padx=10, pady=10) return (inputElement, inputElementVar) def createVarByTextWidget(self, textWidget): def funcSet(value): textWidget.delete("0.0", END) textWidget.insert("0.0", value) return type( "StringVar", (), { "set": staticmethod(funcSet), "get": staticmethod(lambda: textWidget.get("0.0", END)) }) def actionChoiseImageForm(self): path_origin = tkFileDialog.askopenfilename( initialdir="/", title="Selecione o Arquivo", filetypes=(("Arquivos jpeg", "*.jpg"), ("Arquivos png", "*.png"), ("Todos arquivos", "*.*"))) if path_origin: file_name = os.path.basename(path_origin) self.pathImageFormVar.set("images/iconsApps/" + file_name) path_origin = path_origin.encode("latin-1") path_destiny = ("images/iconsApps/" + file_name).encode("latin-1") print(path_origin, path_destiny, type(savePhoto)) savePhoto(path_origin, path_destiny, (100, 100)) image = renderPhoto(path_destiny, (100, 100)) self.imageWidget["image"] = image self.imageWidget["background"] = "SystemButtonFace" def actionNextTabFrameFieldForm(self): "Salva o app na db e pula para a proxima aba" #self.nameFormVar.set("Eventos Mensais") #self.textWidget.insert("0.0", "Eventos e palestrar de tecnologia que estão perto de ocorrer no ano de 2018.") self.nextTabFrameFieldForm() def cleanInfoApp(self): self.nameFormVar.set("") self.pathImageFormVar.set("") self.descriptionFormVar.set("") def cleanFieldForm(self): for element in self.listElementThisForm.values(): element[-1].destroy() def saveAll(self): nameTableFormated = self.formatNameTable(self.nameFormVar.get()) + str( randint(1, 1000000)) appId = self.saveApp(nameTableFormated) #Salva as informacoes do App self.saveFieldsForm( appId) #Salva as ordens dos elementos no formulario self.saveTableForm( nameTableFormated) #Salva a tabela para inserir os futuros itens self.cleanInfoApp() #Limpa todos os campos preenchimentos de Info App self.cleanFieldForm( ) #Remove todos os Itens adicionados na criacao do formulario self.activeDeactivateTabFrameFieldForm( ) #Torna a aba Item invisivel novamente def saveApp(self, nameTableFormated): "Salva o app no banco de dados" self.db.saveRecordApp(self.nameFormVar.get(), self.textWidget.get("0.0", END), nameTableFormated, self.pathImageFormVar.get()) return self.db.getIdOfLastRecordInApps()[0] def saveFieldsForm(self, appId): #(id_element, nameElementVar, type_element, inputElement) index_posicao = 0 indexTemps = list(self.listElementThisForm) indexTemps.sort() for indexTemp in indexTemps: id_element, nameElementVar, type_element, _ = self.listElementThisForm.get( indexTemp) #salvar em saveFieldApp ---> id_formulario, id_elemento, titulo, texto_ajuda, index_posicao self.db.saveFieldApp(appId, id_element, str(nameElementVar.get()), "", index_posicao) index_posicao += 1 def saveTableForm(self, nameTableFormated): try: fields_types = map(lambda element: self.formatNameColumn(element[1].get())+\ " "+element[2], self.listElementThisForm.values()) self.db.saveTableApp(nameTableFormated, fields_types) except Exception as error: self.errorReport.showAndSaveError( error.message, "Erro ocorreu durante salvamento da tabela") def createMenuSideForFieldForm(self): if not self.menuRightStateVar: self.menuRight["background"] = "red" self.menuRightCreateForm = Frame(self.menuRight) self.menuRightCreateForm.pack(side=TOP, padx=10, pady=10) self.buttonSaveApp = Button(self.menuRightCreateForm, command=self.saveAll, \ font=self.font, text="Salvar App") self.buttonSaveApp.pack(side=TOP, ipadx=10) self.menuRightStateVar = True def hideMenuFieldForm(self): self.menuRightCreateForm.forget() def showMenuFieldForm(self): self.menuRightCreateForm.pack(side=TOP, padx=10, pady=10) def nextTabFrameFieldForm(self): self.activeDeactivateTabFrameFieldForm() self.framesNotebook.select(self.tabFrameFieldForm) def activeDeactivateTabFrameFieldForm(self): self.framesNotebook.hide(self.tabFrameFieldForm) def formatNameColumn(self, name_field): name_formated = "_".join(name_field.lower().split(" ")[0:2]) return name_formated def formatNameTable(self, name_form): name_formated = "_".join(name_form.lower().split(" ")[0:2]) return name_formated def configWidgetsGetApps( self ): # Configura todos os widgets que pertencem ao frame que mostra todos os apps e forms self.frameGetApps = Frame(self.frameBody) self.frameAbasGetApps = Notebook(self.frameGetApps) self.frameAbasGetApps.pack(side=TOP, fill=BOTH) frameApp = Frame(self.frameAbasGetApps) frameInfoApp = Frame(frameApp) frameInfoApp.pack(side=TOP, fill=BOTH) frameFieldsApp = Frame(frameApp) frameFieldsApp.pack(side=TOP, fill=BOTH) for idApp, nomeApp, pathImage in self.db.getAllInfoForms( "id", "nome_formulario", "caminho_imagem"): image = renderPhoto(pathImage, (35, 35)) self.frameAbasGetApps.add(frameApp, compound=LEFT, image=image, text=nomeApp, sticky=W + E + N + S) break # def generateTabsApps(self): # self.listTabsApps = [] # for app_info in self.db.getAllInfoForms("id", "nome_formulario"): # self.listTabsApps.append(self.generateTab( )) # def activeTabApp(self, name_form, description, name_table, path_image): # self.frameInfoApp # self.frameFieldsApp def actionOptions(self): if self.frameOld: self.frameOld.forget() self.frameOld = self.menuOptionsFunctions[self.optionVar.get()]() def activeOptionCreateForm(self): self.frameCreateForm.pack(side=LEFT, expand=True, fill=BOTH) self.showMenuFieldForm() return self.frameCreateForm def activeOptionGetApps(self): self.frameGetApps.pack(side=LEFT, expand=True, fill=BOTH) self.hideMenuFieldForm() return self.frameGetApps
class View(Toplevel): def __init__(self, model): self.model = model self.model_config = self.model.get_config() self.channels_num = 0 self.channels_amount = 0 self.root = Tk() self.root.resizable(width=FALSE, height=FALSE) self.root.title("RaaS. event_proxy configurator") #: self.root.iconbitmap('resourse/vit.ico') self.config_route = self.model.get_config_route() self.panelFrame = Frame(self.root, height=60) self.canvas = Canvas(self.root, borderwidth=0) self.textFrame = Frame(self.canvas, height=340, width=600) self.mainFrame = LabelFrame(self.root, width=200, text="Main:", height=340, relief=RAISED, borderwidth=1) self.chanelFrame = LabelFrame(self.root, width=370, text="Channels:", height=340, relief=RAISED, borderwidth=1) #: self.vsb = Scrollbar(self.root, orient="horizontal", #: command=self.canvas.xview) #:self.canvas.configure(xscrollcommand=self.vsb.set) #:self.vsb.pack(side="bottom", fill="x") self.canvas.pack(side="bottom", fill="both", expand=True) self.canvas.configure(scrollregion=self.canvas.bbox("all")) self.root.protocol("WM_DELETE_WINDOW", self.quit_handler) self.tabs = Notebook(self.root) self.in_channel_text = [] self.out_port_text = [] self.out_channel_text = [] self.c = self.model.get_channels().keys() self.channels_len = len(self.model.get_channels()) #:print self.model.get_channels() self.panelFrame.pack(side='top', fill='x') self.textFrame.pack(side='bottom', fill='both', expand=1) self.mainFrame.place(x=10, y=60) self.chanelFrame.place(x=220, y=60) self.tabs.place(x=230, y=80) x = (self.root.winfo_screenwidth() - self.root.winfo_reqwidth()) / 2 y = (self.root.winfo_screenheight() - self.root.winfo_reqheight()) / 2 self.root.geometry("+%d+%d" % (x-150, y-150)) for i in range(self.channels_len): self.channels_num += 1 self.channels_amount += 1 self.f1 = Frame(self.tabs, height=290, width=350) self.tabs.add(self.f1, text='Channel {0}'.format(i + 1)) self.in_channel = Label(self.f1, text="In channel") self.out_port = Label(self.f1, text="Out port") self.out_channel = Label(self.f1, text="Out channel") self.in_channel_text.append(Entry(self.f1, width=20, bd=3)) self.in_channel_text[i].insert(0, self.c[i]) self.out_port_text.append(Entry(self.f1, width=20, bd=3)) self.out_port_text[i].insert(0, self.model.get_channels()[ self.c[i]].out_port) self.out_channel_text.append(Entry(self.f1, width=20, bd=3)) self.out_channel_text[i].insert(0, self.model.get_channels()[ self.c[i]].out_channel) self.in_channel.place(x=5, y=10) self.in_channel_text[i].place(x=5, y=30) self.out_port.place(x=5, y=50) self.out_port_text[i].place(x=5, y=70) self.out_channel.place(x=5, y=90) self.out_channel_text[i].place(x=5, y=110) self.del_ch_btn = Button(self.f1, text='Delete channel {0}'.format( self.channels_amount), command= lambda: self.del_channel(i)) self.del_ch_btn.bind("<Button-1>") self.del_ch_btn.place(x=5, y=140, width=100, height=30) self.server_host_label = Label(self.root, text="Server host") self.server_port_label = Label(self.root, text="Server port") self.raas_port_label = Label(self.root, text="Raas port") self.encoding_label = Label(self.root, text='Encoding') self.levenshtein_distance_label = Label(self.root, text='Levenshtein distance') self.window_time_label = Label(self.root, text='Window time') self.server_host_entity = Entry(self.root, width=20, bd=3) self.server_host_entity.insert(0, self.model_config['server_host']) self.server_port_entity = Entry(self.root, width=20, bd=3) self.server_port_entity.insert(0, self.model_config['server_port']) self.raas_port_entity = Entry(self.root, width=20, bd=3) self.raas_port_entity.insert(0, self.model_config['raas_port']) self.encoding_entry = Entry(self.root, width=20, bd=3) self.encoding_entry.insert(0, self.model_config['encoding']) self.levenshtein_distance_entry = Entry(self.root, width=20, bd=3) self.levenshtein_distance_entry.insert(0, self.model_config[ 'levenshtein_distance']) self.window_time_entry = Entry(self.root, width=20, bd=3) self.window_time_entry.insert(0, self.model_config['window_time']) self.var = IntVar() self.cfg_debug = self.model_config['debug'] if self.cfg_debug == 'True': self.var.set(1) else: self.var.set(0) self.check_debug = Checkbutton(self.root, text='Debug', variable=self.var) self.filter_var = IntVar() self.cfg_use_filter = self.model_config['use_filter'] if self.cfg_use_filter == 'True': self.filter_var.set(1) else: self.filter_var.set(0) self.check_use_filter = Checkbutton(self.root, text='Use filter', variable=self.filter_var) self.addBtn = Button(self.panelFrame, text='Add channel') self.saveBtn = Button(self.panelFrame, text='Save') self.quitBtn = Button(self.panelFrame, text='Quit') self.saveBtn.bind("<Button-1>", self.SaveFile) self.quitBtn.bind("<Button-1>", self.Quit) self.addBtn.bind("<Button-1>", self.add_channel) self.saveBtn.place(x=10, y=10, width=40, height=40) self.quitBtn.place(x=60, y=10, width=40, height=40) self.addBtn.place(x=220, y=10, width=80, height=40) self.server_host_label.place(x=20, y=80) self.server_host_entity.place(x=20, y=100) self.server_port_label.place(x=20, y=120) self.server_port_entity.place(x=20, y=140) self.raas_port_label.place(x=20, y=160) self.raas_port_entity.place(x=20, y=180) self.encoding_label.place(x=20, y=200) self.encoding_entry.place(x=20, y=220) self.check_debug.place(x=20, y=250) self.f = Frame(self.root, height=1, width=190, bg='grey') self.f.place(x=15, y=275) self.levenshtein_distance_label.place(x=20, y=280) self.levenshtein_distance_entry.place(x=20, y=300) self.window_time_label.place(x=20, y=320) self.window_time_entry.place(x=20, y=340) self.check_use_filter.place(x=20, y=370) def del_channel(self, numb): rwidth = self.root.winfo_width() rheight = self.root.winfo_height() if self.channels_num > 6: self.chanelFrame.config(width=self.chanelFrame.winfo_width() - 65) self.root.geometry("%dx%d" % (rwidth - 65, rheight)) if self.channels_num == 6: self.chanelFrame.config(width=self.chanelFrame.winfo_width() - 20) self.root.geometry("%dx%d" % (rwidth - 20, rheight)) dvar = self.tabs.tabs().index(self.tabs.select()) self.in_channel_text.pop(dvar) self.out_channel_text.pop(dvar) self.out_port_text.pop(dvar) self.channels_num -= 1 self.tabs.forget(self.tabs.select()) tabs_list = self.tabs.tabs() self.root.update() def add_channel(self, env): if self.channels_num > 15: tkMessageBox.showerror('Error', 'You can not add more than 16 channels') return False rwidth = self.root.winfo_width() rheight = self.root.winfo_height() if self.channels_num == 5: self.chanelFrame.config(width=self.chanelFrame.winfo_width() + 20) self.root.geometry("%dx%d" % (rwidth + 20, rheight)) if self.channels_num > 5: self.chanelFrame.config(width=self.chanelFrame.winfo_width() + 65) self.root.geometry("%dx%d" % (rwidth + 65, rheight)) self.f1 = Frame(self.tabs, height=290, width=350) self.tabs.add(self.f1, text='Channel {0}'.format(self.channels_amount + 1)) self.in_channel = Label(self.f1, text="In channel") self.out_port = Label(self.f1, text="Out port") self.out_channel = Label(self.f1, text="Out channel") self.in_channel_text.append(Entry(self.f1, width=20, bd=3)) self.out_port_text.append(Entry(self.f1, width=20, bd=3)) self.out_channel_text.append(Entry(self.f1, width=20, bd=3)) self.in_channel.place(x=5, y=10) self.in_channel_text[self.channels_num].place(x=5, y=30) self.out_port.place(x=5, y=50) self.out_port_text[self.channels_num].place(x=5, y=70) self.out_channel.place(x=5, y=90) self.out_channel_text[self.channels_num].place(x=5, y=110) self.del_ch_btn = Button(self.f1, text='Delete channel {0}'.format( self.channels_num + 1), command= lambda: self.del_channel(self.channels_num)) self.del_ch_btn.bind("<Button-1>") self.del_ch_btn.place(x=5, y=140, width=100, height=30) self.channels_num += 1 self.channels_amount += 1 def Quit(self, env): if tkMessageBox.askyesno('Quit', 'Whant to save config before quit?'): self.SaveFile(env) self.root.destroy() def quit_handler(self): if tkMessageBox.askyesno('Quit', 'Whant to save config before quit?'): self.save_handler() self.root.destroy() def validate_int(self, var, text, channel): if not var.isdigit(): tkMessageBox.showerror("Error", "Error in {1}. Value of field '{0}' must be int.".format(text, channel)) return False return True def validate_empty(self, var, text): if not var: tkMessageBox.showerror("Error", "Field {0} must be not empty.".format(text)) return False return True def validate_channels(self): if not self.channels_num: tkMessageBox.showerror("Error", "You must add at least one channel") return False return True def validate_change_field(self): self.validating_config = self.model.get_updated_config() self.flag = False if self.server_host_entity.get() != str(self.validating_config['server_host']): self.flag = True if self.server_port_entity.get() != str(self.validating_config['server_port']): self.flag = True if self.raas_port_entity.get() != str(self.validating_config['raas_port']): self.flag = True if self.encoding_entry.get() != str(self.validating_config['encoding']): self.flag = True if str(self.levenshtein_distance_entry.get()) != str(self.validating_config['levenshtein_distance']): self.flag = True if str(self.window_time_entry.get()) != str(self.validating_config['window_time']): self.flag = True self.tmp = IntVar() if self.validating_config['debug'] == 'True': self.tmp.set(1) else: self.tmp.set(0) if self.tmp.get() != self.var.get(): self.flag = True self.tmp_filter = IntVar() if self.validating_config['use_filter'] == 'True': self.tmp_filter.set(1) else: self.tmp_filter.set(0) if self.tmp_filter.get() != self.filter_var.get(): self.flag = True #TODO: add validating of channels if self.channels_num != self.channels_amount or self.channels_len != self.channels_num: return True for i in range(self.channels_num): if self.in_channel_text[i].get() != str(self.c[i]): self.flag = True if self.out_port_text[i].get() != str(self.model.get_channels()[ self.c[i]].out_port): self.flag = True if self.out_channel_text[i].get() != str(self.model.get_channels()[ self.c[i]].out_channel): self.flag = True return self.flag def validate_all(self): #if not self.validate_change_field(): # return False if not self.validate_channels(): return False if not self.validate_empty(self.server_host_entity.get(), 'Server host'): return False if not self.validate_empty(self.encoding_entry.get(), 'Encoding'): return False if not self.validate_empty(self.levenshtein_distance_entry.get(), 'Levenshtein distance'): return False if not self.validate_int(self.server_port_entity.get(), 'Server port', ''): return False if not self.validate_int(self.raas_port_entity.get(), 'Raas port', ''): return False if not self.validate_int(self.levenshtein_distance_entry.get(), 'Levenshtein distance', ''): return False if not self.validate_int(self.window_time_entry.get(), 'Window time', ''): return False for i in range(self.channels_num): if not self.validate_int(self.in_channel_text[i].get(), 'In channel', ' Channel {0}'.format(i + 1)): return False if not self.validate_int(self.out_port_text[i].get(), 'Out port', ' Channel {0}'.format(i + 1)): return False if not self.validate_int(self.out_channel_text[i].get(), 'Out channel', ' Channel {0}'.format(i + 1)): return False return True def SaveFile(self, env): self.save_handler() def save_handler(self): if not self.validate_all(): return False config = ConfigParser.RawConfigParser() config.add_section('Main') config.set('Main', 'server_host', self.server_host_entity.get()) config.set('Main', 'server_port', self.server_port_entity.get()) config.set('Main', 'raas_port', self.raas_port_entity.get()) result = 'False' if self.var.get(): result = 'True' config.set('Main', 'debug', result) config.set('Main', 'encoding', self.encoding_entry.get()) config.set('Main', 'levenshtein_distance', self.levenshtein_distance_entry.get()) config.set('Main', 'window_time', self.window_time_entry.get()) result_filter = 'False' if self.filter_var.get(): result_filter = 'True' config.set('Main', 'use_filter', result_filter) for i in range(self.channels_num): config.add_section('Channel{0}'.format(i + 1)) config.set('Channel{0}'.format(i + 1), 'in_channel', self.in_channel_text[i].get()) config.set('Channel{0}'.format(i + 1), 'out_port', self.out_port_text[i].get()) config.set('Channel{0}'.format(i + 1), 'out_channel', self.out_channel_text[i].get()) with open(self.config_route, 'wb') as configfile: config.write(configfile) tkMessageBox.showinfo("Info", "Successfully saved.") def run(self): self.root.mainloop()
class Metadator(Tk): def __init__(self): u""" Main window constructor Creates 1 frame and 2 labeled subframes """ # first: the log # see: http://sametmax.com/ecrire-des-logs-en-python/ self.logger = logging.getLogger() self.logger.setLevel(logging.DEBUG) # all errors will be get log_form = logging.Formatter('%(asctime)s || %(levelname)s || %(message)s') logfile = RotatingFileHandler('Metadator_LOG.log', 'a', 5000000, 1) logfile.setLevel(logging.DEBUG) logfile.setFormatter(log_form) self.logger.addHandler(logfile) self.logger.info('\n\t ======== Metadator ========') # first messages self.logger.info('Starting the UI') # checking the path to GDAL in the path if "GDAL_DATA" not in env.keys(): try: gdal.SetConfigOption(str('GDAL_DATA'), str(path.abspath(r'data/gdal'))) except: print("Oups! Something has gone wrong...\ see: https://github.com/Guts/Metadator/issues/21") else: pass # basics settings Tk.__init__(self) # constructor of parent graphic class self.title(u'Metadator {0}'.format(MetadatorVersion)) self.style = Style() # more friendly windows style if opersys == 'win32': self.logger.info('Op. system: {0}'.format(platform.platform())) self.iconbitmap('Metadator.ico') # windows icon self.uzer = env.get(u'USERNAME') elif opersys == 'linux2': self.logger.info('Op. system: {0}'.format(platform.platform())) self.uzer = env.get(u'USER') icon = Image("photo", file=r'data/img/metadator.gif') self.call('wm', 'iconphoto', self._w, icon) self.minsize(580, 100) self.style.theme_use('clam') elif opersys == 'darwin': self.logger.info('Op. system: {0}'.format(platform.platform())) self.uzer = env.get(u'USER') else: self.logger.warning('Operating system not tested') self.logger.info('Op. system: {0}'.format(platform.platform())) self.resizable(width=False, height=False) self.focus_force() self.logger.info('GDAL version: {}'.format(gdal.__version__)) # variables self.def_rep = "" # folder to search for self.def_lang = 'FR' # language to start self.def_doc = IntVar() # to export into Word self.def_xls = IntVar() # to export into Excel 2003 self.def_xml = IntVar() # to export into ISO 19139 self.def_cat = IntVar() # to merge all output Word files self.def_odt = IntVar() # to export into OpenDocumentText self.def_dict = IntVar() # to make a dictionnary of data self.def_kass = IntVar() # to handle field name case sensitive self.def_stat = IntVar() # to active/disable stats fields self.li_pro = [] # list for profiles in language selected self.li_shp = [] # list for shapefiles path self.li_tab = [] # list for MapInfo tables path self.num_folders = 0 # number of folders explored self.today = strftime("%Y-%m-%d") # date of the day self.dico_layer = OD() # dictionary about layer properties self.dico_profil = OD() # dictionary from profile selected self.dico_fields = OD() # dictionary for fields information self.dico_rekur = OD() # dictionary of recurring attributes self.dico_err = OD() # errors list self.dico_help = OD() # dictionary of help texts li_lang = [lg for lg in listdir(r'locale')] # available languages self.blabla = OD() # texts dictionary # GUI fonts ft_tit = tkFont.Font(family="Times", size=10, weight=tkFont.BOLD) # fillfulling self.load_settings() self.load_texts(self.def_lang) self.li_profiles(self.def_lang) self.li_rekurs(self.def_lang) self.recup_help(self.def_lang) # Tabs self.nb = Notebook(self) self.tab_globals = Frame(self.nb) # tab_id = 0 self.tab_options = Frame(self.nb) # tab_id = 1 self.tab_attribs = Frame(self.nb) # tab_id = 2 self.nb.add(self.tab_globals, text=self.blabla.get('gui_tab1'), padding=3) self.nb.add(self.tab_options, text=self.blabla.get('gui_tab2'), padding=3) self.nb.add(self.tab_attribs, text=self.blabla.get('gui_tab3'), padding=3) self.logger.info('UI created') ### Tab 1: global # Frames self.FrPath = Labelframe(self.tab_globals, name='main', text=self.blabla.get('tab1_fr1')) self.FrProg = Labelframe(self.tab_globals, name='progression', text=self.blabla.get('tab1_frprog')) ## Frame 1 # target folder self.labtarg = Label(self.FrPath, text=self.blabla.get('tab1_path')) self.target = Entry(self.FrPath, width=25) self.browsetarg = Button(self.FrPath, # browse button text=self.blabla.get('tab1_browse'), command=lambda: self.setpathtarg(), takefocus=True) self.browsetarg.focus_force() # force the focus on self.profil = Label(self.FrPath, text=self.blabla.get('tab1_prof')) # profiles switcher self.ddl_profil = Combobox(self.FrPath, values=self.li_pro, width=5) self.ddl_profil.current(0) self.ddl_profil.bind("<<ComboboxSelected>>", self.select_profil) # widgets placement self.labtarg.grid(row=1, column=1, columnspan=1, sticky=N + S + W + E, padx=2, pady=8) self.target.grid(row=1, column=2, columnspan=1, sticky=N + S + W + E, padx=2, pady=8) self.browsetarg.grid(row=1, column=3, sticky=N + S + W + E, padx=2, pady=8) self.profil.grid(row=2, column=1, sticky=N + S + W + E, padx=2, pady=8) self.ddl_profil.grid(row=2, column=2, sticky=W + E + N + S, columnspan=2, padx=2, pady=8) # tooltips InfoBulle(self.target, message=self.dico_help.get(30)[1]) InfoBulle(self.browsetarg, message=self.dico_help.get(30)[1]) InfoBulle(self.ddl_profil, message=self.dico_help.get(31)[1]) ## Frame 2 # variables self.status = StringVar(self.FrProg, '') # widgets self.prog_layers = Progressbar(self.FrProg, orient="horizontal") self.prog_fields = Progressbar(self.FrProg, orient="horizontal") # widgets placement Label(self.FrProg, textvariable=self.status, foreground='DodgerBlue').pack(expand=1) self.prog_layers.pack(expand=1, fill=X) # Frames placement self.FrPath.pack(expand=1, fill='both') self.FrProg.pack(expand=1, fill='both') ### Tab 2: options # Export options caz_doc = Checkbutton(self.tab_options, text=u'HTML / Word (.doc/.docx)', variable=self.def_doc, command=lambda: self.catalog_dependance()) caz_xls = Checkbutton(self.tab_options, text=u'Excel 2003 (.xls)', variable=self.def_xls) caz_xml = Checkbutton(self.tab_options, text=u'XML (ISO 19139)', variable=self.def_xml) self.caz_cat = Checkbutton(self.tab_options, text=self.blabla.get('tab2_merge'), variable=self.def_cat) caz_odt = Checkbutton(self.tab_options, text=u'Open Document Text (.odt)', variable=self.def_odt) # widgets placement caz_doc.grid(row=1, column=0, sticky=N + S + W + E, padx=2, pady=2) self.caz_cat.grid(row=2, column=0, sticky=N + S + W + E, padx=2, pady=2) caz_xls.grid(row=1, column=1, sticky=N + S + W + E, padx=2, pady=2) caz_xml.grid(row=2, column=1, sticky=N + S + W + E, padx=2, pady=2) caz_odt.grid(row=3, column=1, sticky=N + S + W + E, padx=2, pady=2) # disabling the widgets which work only on Windows OS if opersys != 'win32': self.logger.info('Disabling Windows reserved functions.') self.def_doc.set(0) self.def_cat.set(0) caz_doc.configure(state='disabled') self.caz_cat.configure(state='disabled') else: pass # make the catalog option depending on the Word option self.catalog_dependance() # tooltips InfoBulle(caz_doc, message=self.dico_help.get(33)[1], image=self.dico_help.get(33)[2]) InfoBulle(caz_xls, message=self.dico_help.get(34)[1], image=self.dico_help.get(34)[2]) InfoBulle(caz_xml, message=self.dico_help.get(35)[1], image=self.dico_help.get(35)[2]) InfoBulle(caz_odt, message=self.dico_help.get(36)[1], image=self.dico_help.get(36)[2]) InfoBulle(self.caz_cat, message=self.dico_help.get(37)[1], image=self.dico_help.get(37)[2]) ### Tab 3: recurring attributes # Attribute selector self.lab_chps = Label(self.tab_attribs, text=self.blabla.get('tab3_sele')) self.ddl_attr = Combobox(self.tab_attribs, values=self.dico_rekur.keys()) self.ddl_attr.bind("<<ComboboxSelected>>", self.edit_rekur) self.supr = Button(self.tab_attribs, text=self.blabla.get('tab3_supp'), command=self.del_rekur) # frame self.FrRekur = Labelframe(self.tab_attribs, name='attributes', text=self.blabla.get('tab3_tit')) # attribute settings self.tab3_LBnom = Label(self.FrRekur, text=self.blabla.get('tab3_nom'), state=DISABLED) self.tab3_ENnom = Entry(self.FrRekur, state=DISABLED) self.tab3_LBdesc = Label(self.FrRekur, text=self.blabla.get('tab3_desc'), state=DISABLED) self.tab3_TXdesc = Text(self.FrRekur, height=5, width=30, wrap=WORD, state=DISABLED) self.tab3_CBcass = Checkbutton(self.FrRekur, text=self.blabla.get('tab3_cass'), variable=self.def_kass, state=DISABLED) self.tab3_CBstat = Checkbutton(self.FrRekur, text=self.blabla.get('tab3_stat'), variable=self.def_stat, state=DISABLED) # Validation button self.save = Button(self.FrRekur, text=self.blabla.get('tab3_save'), command=self.save_rekur, state='disabled') # widgets placement self.lab_chps.grid(row=1, column=1, sticky=N + S + W, padx=2, pady=2) self.ddl_attr.grid(row=1, column=2, sticky=N + S + W + E, padx=2, pady=2) self.supr.grid(row=1, column=3, sticky=N + S + W + E, padx=2, pady=2) self.tab3_LBnom.grid(row=1, column=0, columnspan=1, sticky=N + S + W, padx=2, pady=2) self.tab3_ENnom.grid(row=1, column=1, columnspan=1, sticky=N + S + W + E, padx=2, pady=2) self.tab3_LBdesc.grid(row=2, column=0, columnspan=1, sticky=N + S + W + E, padx=2, pady=2) self.tab3_TXdesc.grid(row=2, column=1, columnspan=2, sticky=N + S + W + E, padx=2, pady=2) self.tab3_CBcass.grid(row=3, column=0, columnspan=1, sticky=N + S + W + E, padx=2, pady=2) self.tab3_CBstat.grid(row=3, column=1, columnspan=1, sticky=N + S + W + E, padx=2, pady=2) self.save.grid(row=5, column=0, columnspan=4, sticky=N + S + W + E, padx=2, pady=2) # Frame placement self.FrRekur.grid(row=2, column=1, columnspan=3, sticky=N + S + W + E, padx=2, pady=2) # tooltips InfoBulle(self.lab_chps, message=self.dico_help.get(38)[1]) InfoBulle(self.ddl_attr, message=self.dico_help.get(39)[1]) InfoBulle(self.supr, message=self.dico_help.get(40)[1]) InfoBulle(self.tab3_CBcass, message=self.dico_help.get(41)[1]) InfoBulle(self.tab3_CBstat, message=self.dico_help.get(42)[1]) ## Main frame # Hola self.welcome = Label(self, text=self.blabla.get('hi') + self.uzer, font=ft_tit, foreground="red2") # Image self.icone = PhotoImage(master=self, file=r'data/img/metadator.gif') Label(self, image=self.icone).grid(row=2, column=0, padx=2, pady=2, sticky=N + S + W + E) # credits s = Style(self) s.configure('Kim.TButton', foreground='DodgerBlue', borderwidth=0, relief="flat") Button(self, text='by Julien M. (2015)', style='Kim.TButton', command=lambda: open_new('https://github.com/Guts')).grid(row=3, padx=2, pady=2, sticky=W+E) # language switcher self.ddl_lang = Combobox(self, values=li_lang, width=5) self.ddl_lang.current(li_lang.index(self.def_lang)) self.ddl_lang.bind("<<ComboboxSelected>>", self.change_lang) # Go go go button self.val = Button(self, text=self.blabla.get('tab1_go'), state='active', command=lambda: self.process()) # Cancel button self.can = Button(self, text=self.blabla.get('gui_quit'), command=self.destroy) # widgets placement self.welcome.grid(row=0, column=0, columnspan=1, sticky=N + S + W + E, padx=2, pady=2) self.ddl_lang.grid(row=1, column=0, sticky=N, padx=2, pady=0) self.can.grid(row=4, column=0, sticky=N + S + W + E, padx=2, pady=2) self.val.grid(row=4, column=1, sticky=N + S + W + E, padx=2, pady=2) # tooltips InfoBulle(self.ddl_lang, message=self.dico_help.get(32)[1]) ### Notebook placement self.nb.grid(row=0, rowspan=4, column=1, sticky=N + S + W + E) # keep updated list of profiles self.maj() def maj(self): """ update the profiles dropdown list every second """ try: self.li_profiles(self.ddl_lang.get()) self.ddl_profil['values'] = self.li_pro self.after(1000, self.maj) except WindowsError: # avoid an error occuring with browse button self.after(1000, self.maj) pass def alter_state(self, parent, new_state): """ just a function to change easily the state of all children widgets of a parent class parent=Tkinter class with children (Frame, Labelframe, Tk, etc.) new_state=Tkinter keyword for widget state (ACTIVE, NORMAL, DISABLED) """ for child in parent.winfo_children(): child.configure(state=new_state) # end of function return parent, new_state def catalog_dependance(self): """ unselect the catalog option if the word option is unselected """ if self.def_doc.get() == 0: self.def_cat.set(0) self.caz_cat.config(state='disabled') elif self.def_doc.get() == 1: self.caz_cat.config(state='normal') # end of function return def load_settings(self): u""" load settings from last execution """ confile = 'options.ini' config = ConfigParser.RawConfigParser() config.read(confile) # basics self.def_lang = config.get('basics', 'def_codelang') self.def_rep = config.get('basics', 'def_rep') # export preferences self.def_doc.set(config.get('export_preferences', 'def_word')) self.def_cat.set(config.get('export_preferences', 'def_cat')) self.def_xls.set(config.get('export_preferences', 'def_xls')) self.def_xml.set(config.get('export_preferences', 'def_xml')) self.def_dict.set(config.get('export_preferences', 'def_dict')) self.def_odt.set(config.get('export_preferences', 'def_odt')) # log self.logger.info('Last options loaded') # End of function return config, self.def_rep, self.def_lang, self.def_doc def save_settings(self): u""" save options in order to make the next execution easier """ confile = 'options.ini' config = ConfigParser.RawConfigParser() # add sections config.add_section('basics') config.add_section('export_preferences') # basics config.set('basics', 'def_codelang', self.ddl_lang.get()) config.set('basics', 'def_rep', self.target.get()) # export preferences config.set('export_preferences', 'def_word', self.def_doc.get()) config.set('export_preferences', 'def_cat', self.def_cat.get()) config.set('export_preferences', 'def_xls', self.def_xls.get()) config.set('export_preferences', 'def_xml', self.def_xml.get()) config.set('export_preferences', 'def_dict', self.def_dict.get()) config.set('export_preferences', 'def_odt', self.def_odt.get()) # Writing the configuration file with open(confile, 'wb') as configfile: config.write(configfile) # End of function return config def change_lang(self, event): u""" update the texts dictionary with the language selected """ new_lang = event.widget.get() # change to the new language selected self.load_texts(new_lang) self.li_profiles(new_lang) self.li_rekurs(new_lang) self.ddl_profil.delete(0, END) self.ddl_profil.config(values=self.li_pro) self.ddl_profil.update() self.ddl_attr.config(values=self.dico_rekur.keys()) self.recup_help(new_lang) # update widgets text # tab1 self.nb.tab(0, text=self.blabla.get('gui_tab1')) self.welcome.config(text=self.blabla.get('hi') + self.uzer) self.can.config(text=self.blabla.get('gui_quit')) self.FrPath.config(text=self.blabla.get('tab1_fr1')) self.FrProg.config(text=self.blabla.get('tab1_frprog')) self.labtarg.config(text=self.blabla.get('tab1_path')) self.browsetarg.config(text=self.blabla.get('tab1_browse')) self.val.config(text=self.blabla.get('tab1_go')) self.profil.config(text=self.blabla.get('tab1_prof')) # tab2 self.nb.tab(1, text=self.blabla.get('gui_tab2')) self.caz_cat.config(text=self.blabla.get('tab2_merge')) # tab3 self.nb.tab(2, text=self.blabla.get('gui_tab3')) self.lab_chps.config(text=self.blabla.get('tab3_sele')) self.supr.config(text=self.blabla.get('tab3_supp')) self.FrRekur.config(text=self.blabla.get('tab3_tit')) self.tab3_LBnom.config(text=self.blabla.get('tab3_nom')) self.tab3_LBdesc.config(text=self.blabla.get('tab3_desc')) self.tab3_CBcass.config(text=self.blabla.get('tab3_cass')) self.tab3_CBstat.config(text=self.blabla.get('tab3_stat')) self.save.config(text=self.blabla.get('tab3_save')) # End of function return self.blabla def load_texts(self, lang='FR'): u""" Load texts according to the selected language """ # clearing the text dictionary self.blabla.clear() # open xml cursor xml = ET.parse('locale/{0}/lang_{0}.xml'.format(lang)) # Looping and gathering texts from the xml file for elem in xml.getroot().getiterator(): self.blabla[elem.tag] = elem.text # updating the GUI self.update() # en of function return self.blabla def setpathtarg(self): """ ...browse and insert the path of target folder """ foldername = askdirectory(parent=self, initialdir=self.def_rep, mustexist=True, title=self.blabla.get('gui_cible')) # check if a folder has been choosen if foldername: try: self.target.delete(0, END) self.target.insert(0, foldername) except: info(title=self.blabla.get('nofolder'), message=self.blabla.get('nofolder')) return # count shapefiles and MapInfo files in a separated thread proc = threading.Thread(target=self.li_geofiles, args=(foldername, )) proc.daemon = True proc.start() # end of function return foldername def li_geofiles(self, foldertarget): u""" List shapefiles and MapInfo files (.tab, not .mid/mif) contained in the folders structure """ # reseting global variables self.li_shp = [] self.li_tab = [] self.browsetarg.config(state=DISABLED) # Looping in folders structure self.status.set(self.blabla.get('tab1_prog1')) self.prog_layers.start() for root, dirs, files in walk(unicode(foldertarget)): self.num_folders = self.num_folders + len(dirs) for f in files: """ looking for files with geographic data """ try: unicode(path.join(root, f)) full_path = path.join(root, f) except UnicodeDecodeError: full_path = path.join(root, f.decode('latin1')) # Looping on files contained if path.splitext(full_path.lower())[1].lower() == '.shp'\ and (path.isfile('{0}.dbf'.format(full_path[:-4])) or path.isfile('{0}.DBF'.format(full_path[:-4])))\ and (path.isfile('{0}.shx'.format(full_path[:-4])) or path.isfile('{0}.SHX'.format(full_path[:-4]))): """ listing compatible shapefiles """ # add complete path of shapefile self.li_shp.append(full_path) elif path.splitext(full_path.lower())[1] == '.tab'\ and (path.isfile(full_path[:-4] + '.dat') or path.isfile(full_path[:-4] + '.DAT'))\ and (path.isfile(full_path[:-4] + '.map') or path.isfile(full_path[:-4] + '.MAP'))\ and (path.isfile(full_path[:-4] + '.id') or path.isfile(full_path[:-4] + '.ID')): """ listing MapInfo tables """ # add complete path of MapInfo file self.li_tab.append(full_path) # stopping the progress bar self.prog_layers.stop() # Lists ordering and tupling self.li_shp.sort() self.li_shp = tuple(self.li_shp) self.li_tab.sort() self.li_tab = tuple(self.li_tab) # setting the label text and activing the buttons self.status.set(unicode(len(self.li_shp)) + u' shapefiles - ' + unicode(len(self.li_tab)) + u' tables (MapInfo) - ' + unicode(self.num_folders) + self.blabla.get('log_numfold')) self.browsetarg.config(state=ACTIVE) self.val.config(state=ACTIVE) # End of function return foldertarget, self.li_shp, self.li_tab def li_profiles(self, lang): u""" list profiles already existing """ # reseting global variable self.li_pro = [] # Looping in folders structure folder_profiles = path.join('locale/', lang + '/profiles/') self.li_pro = [lg[:-4] for lg in listdir(folder_profiles)] self.li_pro.append(self.blabla.get('tab1_new')) # End of function return folder_profiles, self.li_pro def li_rekurs(self, lang): u""" List recurring attributes that already exist in the selected language """ # clearing the text dictionary self.dico_rekur.clear() champis = path.abspath(r'locale/{0}/champignons_{0}.xml'.format(lang)) xml = ET.parse(champis) # Looping and gathering texts from the xml file for elem in xml.findall('champ'): rek_name = elem.find('intitule').text rek_desc = elem.find('description').text rek_kass = elem.find('case').text rek_stat = elem.find('stats').text self.dico_rekur[rek_name] = rek_desc, rek_kass, rek_stat self.dico_rekur[self.blabla.get('tab3_new')] = '', 0, 0 # updating the GUI self.update() # End of function return self.dico_rekur def edit_rekur(self, event): u""" preparing the form to edit a recurring attribute """ rekur = event.widget.get() # deactivate the selector self.ddl_attr.config(state=DISABLED) # activate the form self.alter_state(self.FrRekur, NORMAL) # change to the new language selected self.tab3_ENnom.insert(0, rekur) self.tab3_TXdesc.insert(1.0, self.dico_rekur.get(rekur)[0]) self.def_kass.set(self.dico_rekur.get(rekur)[1]) self.def_stat.set(self.dico_rekur.get(rekur)[2]) # End of function return self.dico_rekur def save_rekur(self): u""" save the recurring attribute edited """ # check if the attribute already exists if self.tab3_ENnom.get() in self.dico_rekur: if not askyesno(title=self.blabla.get('tab3_alert_exist1'), message=self.blabla.get('tab3_alert_exist2')): return else: pass else: pass # save self.dico_rekur[self.tab3_ENnom.get()] = self.tab3_TXdesc.get(1.0, END).rstrip(),\ self.def_kass.get(),\ self.def_stat.get() # reset the form self.tab3_ENnom.delete(0, END) self.tab3_TXdesc.delete(1.0, END) self.def_kass.set(0) self.def_stat.set(0) # deactivate the form self.alter_state(self.FrRekur, DISABLED) # updating the dropdown list self.ddl_attr.config(state=NORMAL) self.ddl_attr.delete(0, END) self.ddl_attr['values'] = self.dico_rekur.keys() # End of function return self.dico_rekur def del_rekur(self): u""" delete the selected recurring attribute """ # reactivate the selector self.ddl_attr.config(state=ACTIVE) self.dico_rekur.pop(self.ddl_attr.get()) self.ddl_attr.delete(0, END) self.ddl_attr['values'] = self.dico_rekur.keys() # reset the form self.tab3_ENnom.delete(0, END) self.tab3_TXdesc.delete(1.0, END) self.def_kass.set(0) self.def_stat.set(0) # deactivate the form self.alter_state(self.FrRekur, DISABLED) # End of function return self.dico_rekur def saveas_rekurs(self, lang): u""" save the recurring fields into the file dedicated """ rekur = ET.Element(u'champs') xml_path = r'locale/{0}/champignons_{0}.xml'.format(lang) self.dico_rekur.pop(self.blabla.get('tab3_new')) with open(xml_path, 'w') as champis: for elem in self.dico_rekur.keys(): rek = ET.SubElement(rekur, u'champ') # name of recurring attribute rek_name = ET.SubElement(rek, u'intitule') rek_name.text = elem # description of recurring attribute rek_desc = ET.SubElement(rek, u'description') rek_desc.text = self.dico_rekur.get(elem)[0] # stats option of recurring attribute rek_stats = ET.SubElement(rek, u'stats') rek_stats.text = unicode(self.dico_rekur.get(elem)[1]) # case sensitive option of recurring attribute rek_case = ET.SubElement(rek, u'case') rek_case.text = unicode(self.dico_rekur.get(elem)[2]) # creating the xml tree out_rekurs = ET.ElementTree(rekur) # saving it out_rekurs.write(xml_path, encoding='utf-8', xml_declaration='version="1.0"', method='xml') # End of function return self.dico_rekur def select_profil(self, event): """ when a profile is selected... """ profsel = event.widget.get() # if user wants to use an existing profile or create a new one if profsel == self.blabla.get('tab1_new'): self.val.config(text=self.blabla.get('tab1_crprofil')) else: self.val.config(text=self.blabla.get('tab1_go')) # end of function return self.val def recup_profil(self, lang): """ get the information from the profile selected """ # clearing the profile dictionary self.dico_profil.clear() # specific path to profile file path_profile = path.join('locale/{0}/profiles/{1}.xml'.format(lang, self.ddl_profil.get())) with open(path_profile, 'r') as profile: # open xml parser xml = ET.parse(profile) # basic informations self.dico_profil['description'] = xml.find('description').text self.dico_profil['sources'] = xml.find('sources').text self.dico_profil['url'] = xml.find('url').text self.dico_profil['url_label'] = xml.find('url_label').text self.dico_profil[u'diffusion'] = xml.find('diffusion').text # data language lang_data = xml.find(u'lang_data') self.dico_profil[u"lang_data"] = lang_data.find(u'name').text # metadata language lang_metad = xml.find(u'lang_metad') self.dico_profil[u"lang_md"] = lang_metad.find(u'name').text # diffusion constraints diff = xml.find(u'diffusion') self.dico_profil['diffusion'] = diff.find(u'name').text # update rythm rythm = xml.find(u'rythm') self.dico_profil['rythm'] = rythm.find(u'name').text # INSPIRE themes themes = xml.find('themesinspire') li_themesinspire = [theme.find('name').text for theme in themes.findall('theme')] self.dico_profil['themesinspire'] = li_themesinspire # custom keywords keywords = xml.find('keywords') li_keywords = [keyword.find('name').text for keyword in keywords.findall('keyword')] self.dico_profil['keywords'] = li_keywords # places keywords geokeywords = xml.find('geokeywords') li_geokeywords = [geokeyword.find('name').text for geokeyword in geokeywords.findall('geokeyword')] self.dico_profil['geokeywords'] = li_geokeywords # contacts contacts = xml.find(u'contacts') # point of contact cont = contacts.find(u'pointdecontact') self.dico_profil[u'cont_name'] = cont.find(u'name').text self.dico_profil[u'cont_orga'] = cont.find(u'org').text self.dico_profil[u'cont_mail'] = cont.find(u'mail').text self.dico_profil[u'cont_role'] = cont.find(u'role').text self.dico_profil[u'cont_func'] = cont.find(u'func')[0].text self.dico_profil[u'cont_street'] = cont.find(u'street').text self.dico_profil[u'cont_city'] = cont.find(u'city').text self.dico_profil[u'cont_cp'] = cont.find(u'cp').text self.dico_profil[u'cont_country'] = cont.find(u'country').text self.dico_profil[u'cont_phone'] = cont.find(u'tel').text # second contact (responsable, etc.) resp = contacts.find(u'second_contact') self.dico_profil[u'resp_name'] = resp.find(u'name').text self.dico_profil[u'resp_orga'] = resp.find(u'org').text self.dico_profil[u'resp_mail'] = resp.find(u'mail').text self.dico_profil[u'resp_role'] = resp.find(u'role').text self.dico_profil[u'resp_func'] = resp.find(u'func')[0].text self.dico_profil[u'resp_street'] = resp.find(u'street').text self.dico_profil[u'resp_city'] = resp.find(u'city').text self.dico_profil[u'resp_cp'] = resp.find(u'cp').text self.dico_profil[u'resp_country'] = resp.find(u'country').text self.dico_profil[u'resp_phone'] = resp.find(u'tel').text # End of function return self.dico_profil def recup_help(self, lang): """ get the help texts """ # specific path to xml file path_help = 'locale/%s/help_%s.xml' % (lang, lang) # reading and parsing the xml with open(path_help, 'r') as source: xml = ET.parse(source) # xml cursor for tooltip in xml.findall('tooltip'): idu = tooltip.find('id').text ref = tooltip.find('ref').text txt = tooltip.find('txt').text img = tooltip.find('image').text doc = tooltip.find('doc').text # fillfulling the INSPIRE dictionary self.dico_help[int(idu)] = ref, txt, img, doc # End of function return self.dico_help def process(self): u""" launch the different processes """ # display the main tab self.nb.select(0) # check option selected: process or create a new profile if self.ddl_profil.get() == self.blabla.get('tab1_new'): # launching the profile form self.logger.info('Creation of a new profile') tr_profile = threading.Thread(target=NewProfile, args=(self.blabla, self.ddl_lang.get(), self.dico_help, self.li_pro)) tr_profile.daemon = True tr_profile.run() # NewProfile(self.blabla, self.ddl_lang.get(), self.li_pro) self.li_profiles(self.ddl_lang.get()) # updating the dropdow list self.ddl_profil['values'] = self.li_pro return # check if the target folder has been selected if self.target.get() == "": info(title=self.blabla.get('info_blanktarget1'), message=self.blabla.get('info_blanktarget2')) return # check if a profile has been selected if self.ddl_profil.get() == "": info(title=self.blabla.get('info_blankprofile1'), message=self.blabla.get('info_blankprofile2')) return # disabling others GUI parts self.tab_globals.focus_force() self.alter_state(self.FrPath, DISABLED) # check if there are some layers into the folder structure if len(self.li_shp) + len(self.li_tab) == 0: self.logger.warning("No geofiles found in the folder structure") self.status.set(self.blabla.get('log_nodata')) return # specific variables dest = path.join(self.target.get(), 'metadator') if not path.isdir(dest): # test if folder already exists mkdir(dest, 0777) # if not, we create it # getting profile informations self.recup_profil(self.ddl_lang.get()) # saving options in a separated thread tr_options = threading.Thread(target=self.save_settings) tr_options.daemon = True tr_options.start() self.logger.info('Current options saved') # saving recurring fiels in a separated thread tr_rekurs = threading.Thread(target=self.saveas_rekurs, args=(self.ddl_lang.get(), )) tr_rekurs.daemon = True tr_rekurs.start() # configuring the progression bar self.prog_layers["maximum"] = len(self.li_shp) + len(self.li_tab) self.prog_layers["value"] # Processing the shapefiles self.logger.info('\tStart processing the files') for shp in self.li_shp: """ looping on shapefiles list """ self.logger.info('Processing: %s' % path.basename(shp)) self.status.set(path.basename(shp)) # reset recipient data self.dico_layer.clear() self.dico_fields.clear() # getting separated process threads Read_SHP(shp, self.dico_layer, self.dico_fields, 'shape', self.blabla) # checking layer error if self.dico_layer.get('error'): # increment the progress bar self.prog_layers["value"] = self.prog_layers["value"] + 1 self.update() self.logger.warning('This shape has an issue: %s' % shp) continue # getting fields statistics only if needed if self.def_doc.get() == 1 or self.def_xls.get() == 1 or self.def_odt.get() == 1: StatsFields(shp, self.dico_fields, self.dico_rekur, self.blabla) # export according to options selected if self.def_doc.get() == 1: ExportToHTML(dest, self.dico_layer, self.dico_fields, self.dico_profil, self.dico_rekur, self.blabla) html_path = path.join(dest, "{0}_MD.html".format(self.dico_layer['name'][:-4])) ExportToDocX(html_path, dest) if self.def_xls.get() == 1: ExportToXLS(dest, self.dico_layer, self.dico_fields, self.dico_profil, self.dico_rekur, self.blabla) if self.def_xml.get() == 1: ExportToXML(dest, self.dico_layer, self.dico_profil, '', self.blabla, 1, 0) if self.def_odt.get() == 1: ExportToODT(dest, self.dico_layer, self.dico_fields, self.dico_profil, self.dico_rekur, self.blabla) # increment the progress bar self.prog_layers["value"] = self.prog_layers["value"] + 1 self.update() # Processing the MapInfo tables for tab in self.li_tab: """ looping on MapInfo tables list """ self.logger.info('Processing: %s' % path.basename(tab)) self.status.set(path.basename(tab)) # reset recipient data self.dico_layer.clear() self.dico_fields.clear() # getting the informations Read_TAB(tab, self.dico_layer, self.dico_fields, 'table', self.blabla) # checking layer error if self.dico_layer.get('error'): self.logger.warning('This MapInfo table has an issue: %s' % tab) # increment the progress bar self.prog_layers["value"] = self.prog_layers["value"] +1 self.update() continue # getting fields statistics only if needed if self.def_doc.get() == 1 \ or self.def_xls.get() == 1 \ or self.def_odt.get() == 1: StatsFields(tab, self.dico_fields, self.dico_rekur, self.blabla) # export according to options selected if self.def_doc.get() == 1: ExportToHTML(dest, self.dico_layer, self.dico_fields, self.dico_profil, self.dico_rekur, self.blabla) html_path = path.join(dest, "{0}_MD.html".format(self.dico_layer['name'][:-4])) ExportToDocX(html_path, dest) if self.def_xls.get() == 1: ExportToXLS(dest, self.dico_layer, self.dico_fields, self.dico_profil, self.dico_rekur, self.blabla) if self.def_xml.get() == 1: ExportToXML(dest, self.dico_layer, self.dico_profil, '', self.blabla, 1, 0) if self.def_odt.get() == 1: ExportToODT(dest, self.dico_layer, self.dico_fields, self.dico_profil, self.dico_rekur, self.blabla) # increment the progress bar self.prog_layers["value"] = self.prog_layers["value"] + 1 self.update() # Word catalog export if self.def_doc.get() == 1 and self.def_cat.get() == 1: self.status.set(self.blabla.get('info_cat')) self.update() DocxMerger(dest, '00_Metadator_Catalog', 'metadator_') else: pass # final message # msg = self.blabla.get('info_end2') + self.blabla.get('info_end3') # info(title=self.blabla.get('info_end'), message=msg) # opening the destination folder self.open_dir_file(dest) # cleaning up logging.info('Hurray! It worked! All seem to have been fine!') self.destroy() # end of function return def open_dir_file(self, target): """ Open a file or a directory in the explorer of the operating system http://sametmax.com/ouvrir-un-fichier-avec-le-bon-programme-en-python """ # check if the file or the directory exists if not path.exists(target): raise IOError('No such file: {0}'.format(target)) # check the read permission if not access(target, R_OK): raise IOError('Cannot access file: {0}'.format(target)) # open the directory or the file according to the os if opersys == 'win32': # Windows proc = startfile(target) elif opersys.startswith('linux'): # Linux: proc = subprocess.Popen(['xdg-open', target], stdout=subprocess.PIPE, stderr=subprocess.PIPE) elif opersys == 'darwin': # Mac: proc = subprocess.Popen(['open', '--', target], stdout=subprocess.PIPE, stderr=subprocess.PIPE) else: raise NotImplementedError( "Your `%s` isn't a supported operating system`." % opersys) # end of function return proc