Esempio n. 1
0
    def __init__(self, title):
        root = Tk()
        root.title(title)
        root.focus_set()
        root.rowconfigure(0, weight=0)
        root.columnconfigure(0, weight=1)
        root.rowconfigure(1, weight=1)
        self._root = root

        self.menubar = Frame(root)
        self.menubar.grid(row=0, column=0, sticky=(W, E))
        self.menubar['takefocus'] = False

        quit_button = Button(self.menubar, text='Quit', command=self.quit)
        quit_button.grid(row=0, column=0)

        self._menucolumn = 1
        self.views = list()

        self.paned_win = PanedWindow(root, orient=HORIZONTAL)
        self.paned_win.grid(row=1, column=0, sticky=(N, S, W, E))

        self._query = None
        self._accept_func = None

        self.sidebar_views = dict()
        self.sidebar_count = 0
        self.sidebar = PanedWindow(self.paned_win)
        self.paned_win.add(self.sidebar, weight=1)

        self.tabs = Notebook(self.paned_win)
        self.tabs.enable_traversal()
        self.paned_win.add(self.tabs, weight=5)
        self.root = self.tabs
Esempio n. 2
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=tk.HORIZONTAL)
        self.content.grid(column=0, row=1, sticky=(tk.N, tk.S, tk.E, tk.W))

        # Create the tree/control area on the left frame
        self._setup_left_frame()
        self._setup_project_file_tree()
        self._setup_global_file_tree()

        # Create the output/viewer area on the right frame
        self._setup_code_area()

        # 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=4)
Esempio n. 3
0
File: view.py Progetto: pybee/duvet
    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=tk.HORIZONTAL)
        self.content.grid(column=0, row=1, sticky=(tk.N, tk.S, tk.E, tk.W))

        # Create the tree/control area on the left frame
        self._setup_left_frame()
        self._setup_project_file_tree()
        self._setup_global_file_tree()

        # Create the output/viewer area on the right frame
        self._setup_code_area()

        # 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=4)
Esempio n. 4
0
File: view.py Progetto: pybee/duvet
class MainWindow(object):
    def __init__(self, root, options):
        '''
        -----------------------------------------------------
        | main button toolbar                               |
        -----------------------------------------------------
        |       < ma | in content area >                    |
        |            |                                      |
        | File list  | File name                            |
        |            |                                      |
        -----------------------------------------------------
        |     status bar area                               |
        -----------------------------------------------------

        '''
        # Obtain and expand the current working directory.
        if options.path:
            base_path = os.path.abspath(options.path)
        else:
            base_path = os.path.abspath(os.getcwd())
        self.base_path = os.path.normcase(base_path)

        # Create a filename normalizer based on the CWD.
        self.filename_normalizer = filename_normalizer(self.base_path)

        # Set up dummy coverage data
        self.coverage_data = {'lines': {}, 'total_coverage': None}

        # Root window
        self.root = root
        self.root.title('Duvet')
        self.root.geometry('1024x768')

        # Prevent the menus from having the empty tearoff entry
        self.root.option_add('*tearOff', tk.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)

    ######################################################
    # Internal GUI layout methods.
    ######################################################

    def _setup_menubar(self):
        # Menubar
        self.menubar = tk.Menu(self.root)

        # self.menu_Apple = Menu(self.menubar, name='Apple')
        # self.menubar.add_cascade(menu=self.menu_Apple)

        self.menu_file = tk.Menu(self.menubar)
        self.menubar.add_cascade(menu=self.menu_file, label='File')

        self.menu_help = tk.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='Close', command=self.cmd_dummy)

        self.menu_help.add_command(label='Open Documentation', command=self.cmd_duvet_docs)
        self.menu_help.add_command(label='Open Duvet project page', command=self.cmd_duvet_page)
        self.menu_help.add_command(label='Open Duvet on GitHub', command=self.cmd_duvet_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 = tk.Frame(self.root)
        self.toolbar.grid(column=0, row=0, sticky=(tk.W, tk.E))

        # Buttons on the toolbar
        self.refresh_button = tk.Button(self.toolbar, text='Refresh', command=self.cmd_refresh)
        self.refresh_button.grid(column=0, row=0)

        # Coverage summary for currently selected file.
        self.coverage_total_summary = tk.StringVar()
        self.coverage_total_summary_label = Label(
            self.toolbar,
            textvariable=self.coverage_total_summary,
            anchor=tk.E,
            padding=(5, 0, 5, 0),
            font=('Helvetica','20')
        )
        self.coverage_total_summary_label.grid(column=1, row=0, sticky=(tk.W, tk.E))

        self.toolbar.columnconfigure(0, weight=0)
        self.toolbar.columnconfigure(1, weight=1)
        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=tk.HORIZONTAL)
        self.content.grid(column=0, row=1, sticky=(tk.N, tk.S, tk.E, tk.W))

        # Create the tree/control area on the left frame
        self._setup_left_frame()
        self._setup_project_file_tree()
        self._setup_global_file_tree()

        # Create the output/viewer area on the right frame
        self._setup_code_area()

        # 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=4)

    def _setup_left_frame(self):
        '''
        The left frame mostly consists of the tree widget
        '''

        # The left-hand side frame on the main content area
        # The tabs for the two trees
        self.tree_notebook = Notebook(
            self.content,
            padding=(0, 5, 0, 5)
        )
        self.content.add(self.tree_notebook)

    def _setup_project_file_tree(self):

        self.project_file_tree_frame = tk.Frame(self.content)
        self.project_file_tree_frame.grid(column=0, row=0, sticky=(tk.N, tk.S, tk.E, tk.W))
        self.tree_notebook.add(self.project_file_tree_frame, text='Project')

        self.project_file_tree = FileView(self.project_file_tree_frame, normalizer=self.filename_normalizer, root=self.base_path)
        self.project_file_tree.grid(column=0, row=0, sticky=(tk.N, tk.S, tk.E, tk.W))

        # # The tree's vertical scrollbar
        self.project_file_tree_scrollbar = tk.Scrollbar(self.project_file_tree_frame, orient=tk.VERTICAL)
        self.project_file_tree_scrollbar.grid(column=1, row=0, sticky=(tk.N, tk.S))

        # # Tie the scrollbar to the text views, and the text views
        # # to each other.
        self.project_file_tree.config(yscrollcommand=self.project_file_tree_scrollbar.set)
        self.project_file_tree_scrollbar.config(command=self.project_file_tree.yview)

        # Setup weights for the "project_file_tree" tree
        self.project_file_tree_frame.columnconfigure(0, weight=1)
        self.project_file_tree_frame.columnconfigure(1, weight=0)
        self.project_file_tree_frame.rowconfigure(0, weight=1)

        # Handlers for GUI events
        self.project_file_tree.bind('<<TreeviewSelect>>', self.on_file_selected)

    def _setup_global_file_tree(self):

        self.global_file_tree_frame = tk.Frame(self.content)
        self.global_file_tree_frame.grid(column=0, row=0, sticky=(tk.N, tk.S, tk.E, tk.W))
        self.tree_notebook.add(self.global_file_tree_frame, text='Global')

        self.global_file_tree = FileView(self.global_file_tree_frame, normalizer=self.filename_normalizer)
        self.global_file_tree.grid(column=0, row=0, sticky=(tk.N, tk.S, tk.E, tk.W))

        # # The tree's vertical scrollbar
        self.global_file_tree_scrollbar = tk.Scrollbar(self.global_file_tree_frame, orient=tk.VERTICAL)
        self.global_file_tree_scrollbar.grid(column=1, row=0, sticky=(tk.N, tk.S))

        # # Tie the scrollbar to the text views, and the text views
        # # to each other.
        self.global_file_tree.config(yscrollcommand=self.global_file_tree_scrollbar.set)
        self.global_file_tree_scrollbar.config(command=self.global_file_tree.yview)

        # Setup weights for the "global_file_tree" tree
        self.global_file_tree_frame.columnconfigure(0, weight=1)
        self.global_file_tree_frame.columnconfigure(1, weight=0)
        self.global_file_tree_frame.rowconfigure(0, weight=1)

        # Handlers for GUI events
        self.global_file_tree.bind('<<TreeviewSelect>>', self.on_file_selected)

    def _setup_code_area(self):
        self.code_frame = tk.Frame(self.content)
        self.code_frame.grid(column=1, row=0, sticky=(tk.N, tk.S, tk.E, tk.W))

        # Label for current file
        self.current_file = tk.StringVar()
        self.current_file_label = Label(self.code_frame, textvariable=self.current_file)
        self.current_file_label.grid(column=0, row=0, sticky=(tk.W, tk.E))

        # Code display area
        self.code = CodeView(self.code_frame)
        self.code.grid(column=0, row=1, sticky=(tk.N, tk.S, tk.E, tk.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_status_bar(self):
        # Status bar
        self.statusbar = tk.Frame(self.root)
        self.statusbar.grid(column=0, row=2, sticky=(tk.W, tk.E))

        # Coverage summary for currently selected file.
        self.coverage_file_summary = tk.StringVar()
        self.coverage_file_summary_label = Label(self.statusbar, textvariable=self.coverage_file_summary)
        self.coverage_file_summary_label.grid(column=0, row=0, sticky=(tk.W, tk.E))
        self.coverage_file_summary.set('No file selected')

        # Main window resize handle
        self.grip = Sizegrip(self.statusbar)
        self.grip.grid(column=1, row=0, sticky=(tk.S, tk.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

            missing = self.coverage_data['missing'].get(os.path.normcase(filename), [])
            executed = self.coverage_data['lines'].get(os.path.normcase(filename), [])

            n_executed = len(executed)
            n_missing = len(missing)

            self.code.highlight_missing(missing)

            self.coverage_file_summary.set('%s/%s lines executed' % (n_executed, n_executed + n_missing))

        self.code.line = line

    def load_coverage(self):
        "Load and display coverage data"
        # Store the old list of files that have coverage data.
        # We do this so we can identify stale data on the tree.
        old_files = set(self.coverage_data['lines'].keys())
        old_total_coverage = self.coverage_data['total_coverage']

        loaded = False
        retry = True
        while not loaded and retry:
            try:
                # Load the new coverage data
                cov = coverage.coverage()
                cov.load()

                # Override precision for coverage reporting.
                coverage.results.Numbers.set_precision(1)

                if cov.data.measured_files():
                    self.coverage_data = {
                        'lines': {},
                        'missing': {},
                    }
                    totals = coverage.results.Numbers()

                    # Update the coverage display of every file mentioned in the file.
                    for filename in cov.data.measured_files():
                        filename = os.path.normcase(filename)
                        node = nodify(filename)
                        dirname, basename = os.path.split(filename)

                        # If the normalized version of the filename is the same as the
                        # filename, then the file *isn't* under the project root.
                        if filename == self.filename_normalizer(filename):
                            file_tree = self.global_file_tree
                        else:
                            file_tree = self.project_file_tree

                        try:
                            # # Make sure the file exists on the tree.
                            file_tree.insert_filename(dirname, basename)

                            # Compute the coverage percentage
                            analysis = cov._analyze(filename)

                            self.coverage_data['lines'][filename] = analysis.statements
                            self.coverage_data['missing'][filename] = analysis.missing
                            file_coverage = analysis.numbers.pc_covered

                            totals = totals + analysis.numbers

                            file_tree.set(node, 'coverage', analysis.numbers.pc_covered_str)
                            # file_tree.set(node, 'branch_coverage', str(len(lines)))

                            # Set the color of the tree node based on coverage
                            if file_coverage < 70.0:
                                file_tree.item(node, tags=['file', 'code', 'bad'])
                            elif file_coverage < 80.0:
                                file_tree.item(node, tags=['file', 'code', 'poor'])
                            elif file_coverage < 90.0:
                                file_tree.item(node, tags=['file', 'code', 'ok'])
                            elif file_coverage < 99.9:
                                file_tree.item(node, tags=['file', 'code', 'good'])
                            else:
                                file_tree.item(node, tags=['file', 'code', 'perfect'])

                        except coverage.misc.NoSource:
                            # could mean the file was deleted after running coverage
                            file_tree.item(node, tags=['bad'])

                        # We've updated the file, so we know it isn't stale.
                        try:
                            old_files.remove(filename)
                        except KeyError:
                            # File wasn't loaded before; ignore this.
                            pass

                        # Clear out any stale coverage data
                        for filename in old_files:
                            node = nodify(filename)
                            if file_tree.exists(node):
                                file_tree.set(node, 'coverage', '')
                                file_tree.item(node, tags=['file', 'code'])

                    # Compute the overall coverage
                    total_coverage = totals.pc_covered
                    self.coverage_data['total_coverage'] = total_coverage

                    coverage_text = u'%.1f%%' % total_coverage

                    # Update the text with up/down arrows to reflect change
                    if old_total_coverage is not None:
                        if total_coverage > old_total_coverage:
                            coverage_text = coverage_text + u' ⬆'
                        elif total_coverage < old_total_coverage:
                            coverage_text = coverage_text + u' ⬇'

                    self.coverage_total_summary.set(coverage_text)

                    # Set the color based on coverage level.
                    if total_coverage < 70.0:
                        self.coverage_total_summary_label.configure(foreground='red')
                    elif total_coverage < 80.0:
                        self.coverage_total_summary_label.configure(foreground='orange')
                    elif total_coverage < 90.0:
                        self.coverage_total_summary_label.configure(foreground='blue')
                    elif total_coverage < 99.9:
                        self.coverage_total_summary_label.configure(foreground='cyan')
                    else:
                        self.coverage_total_summary_label.configure(foreground='green')

                    # Refresh the file display
                    current_file = self.code._filename
                    if current_file:
                        self.code._filename = None
                        self.show_file(current_file)

                    loaded = True
                else:
                    retry = tkMessageBox.askretrycancel(
                        message="Couldn't find coverage data file. Have you generated coverage data? Is the .coverage in your current working directory",
                        title='No coverage data found'
                    )
            except Exception as e:
                retry = tkMessageBox.askretrycancel(
                    message="Couldn't load coverage data -- data file may be corrupted (Error was: %s)" % e,
                    title='Problem loading coverage data'
                )

        return loaded

    ######################################################
    # TK Main loop
    ######################################################

    def mainloop(self):
        self.root.mainloop()

    ######################################################
    # TK Command handlers
    ######################################################

    def cmd_quit(self):
        "Quit the program"
        self.root.quit()

    def cmd_refresh(self, event=None):
        "Refresh the coverage data"
        self.load_coverage()

    def cmd_duvet_page(self):
        "Show the Duvet project page"
        webbrowser.open_new('http://pybee.org/duvet')

    def cmd_duvet_github(self):
        "Show the Duvet GitHub repo"
        webbrowser.open_new('http://github.com/pybee/duvet')

    def cmd_duvet_docs(self):
        "Show the Duvet 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('https://duvet.readthedocs.io/en/v%s/' % VERSION)
        else:
            webbrowser.open_new('https://duvet.readthedocs.io/')

    def cmd_beeware_page(self):
        "Show the BeeWare project page"
        webbrowser.open_new('http://pybee.org/')

    ######################################################
    # Handlers for GUI actions
    ######################################################

    def on_file_selected(self, event):
        "When a file is selected, highlight the file and line"
        if event.widget.selection():
            filename = event.widget.selection()[0]

            # Display the file in the code view
            if os.path.isfile(filename):
                self.show_file(filename=filename)
            else:
                self.code.filename = None
Esempio n. 5
0
    def __init__(self, master, a_copier, a_supp, a_supp_avant_cp, original,
                 sauvegarde, show_size):
        Toplevel.__init__(self, master)
        self.geometry("%ix%i" %
                      (self.winfo_screenwidth(), self.winfo_screenheight()))
        self.rowconfigure(1, weight=1)
        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)
        self.title(_("Confirmation"))

        self.a_copier = a_copier
        self.a_supp = a_supp
        self.a_supp_avant_cp = a_supp_avant_cp

        h = max(len(a_supp), len(a_copier))

        style = Style(self)
        style.configure("text.TFrame", background="white", relief="sunken")

        Label(self,
              text=_("Synchronization from %(original)s to %(backup)s") % {
                  "original": original,
                  "backup": sauvegarde
              }).grid(row=0, columnspan=2, padx=10, pady=10)
        paned = PanedWindow(self, orient='horizontal')
        paned.grid(row=1, columnspan=2, sticky="eswn", padx=(10, 4), pady=4)
        paned.columnconfigure(0, weight=1)
        paned.columnconfigure(1, weight=1)
        paned.rowconfigure(1, weight=1)

        # --- copy
        frame_copie = Frame(paned)
        frame_copie.columnconfigure(0, weight=1)
        frame_copie.rowconfigure(1, weight=1)
        paned.add(frame_copie, weight=1)
        Label(frame_copie, text=_("To copy:")).grid(row=0,
                                                    columnspan=2,
                                                    padx=(10, 4),
                                                    pady=4)
        f_copie = Frame(frame_copie, style="text.TFrame", borderwidth=1)
        f_copie.columnconfigure(0, weight=1)
        f_copie.rowconfigure(0, weight=1)
        f_copie.grid(row=1, column=0, sticky="ewsn")
        txt_copie = Text(f_copie,
                         height=h,
                         wrap="none",
                         highlightthickness=0,
                         relief="flat")
        txt_copie.grid(row=0, column=0, sticky="eswn")
        scrollx_copie = Scrollbar(frame_copie,
                                  orient="horizontal",
                                  command=txt_copie.xview)
        scrolly_copie = Scrollbar(frame_copie,
                                  orient="vertical",
                                  command=txt_copie.yview)
        scrollx_copie.grid(row=2, column=0, sticky="ew")
        scrolly_copie.grid(row=1, column=1, sticky="ns")
        txt_copie.configure(yscrollcommand=scrolly_copie.set,
                            xscrollcommand=scrollx_copie.set)
        txt_copie.insert("1.0", "\n".join(a_copier))
        txt_copie.configure(state="disabled")
        self._size_copy = Label(frame_copie)
        self._size_copy.grid(row=3, column=0)

        # --- deletion
        frame_supp = Frame(paned)
        frame_supp.columnconfigure(0, weight=1)
        frame_supp.rowconfigure(1, weight=1)
        paned.add(frame_supp, weight=1)
        Label(frame_supp, text=_("To remove:")).grid(row=0,
                                                     columnspan=2,
                                                     padx=(4, 10),
                                                     pady=4)
        f_supp = Frame(frame_supp, style="text.TFrame", borderwidth=1)
        f_supp.columnconfigure(0, weight=1)
        f_supp.rowconfigure(0, weight=1)
        f_supp.grid(row=1, column=0, sticky="ewsn")
        txt_supp = Text(f_supp,
                        height=h,
                        wrap="none",
                        highlightthickness=0,
                        relief="flat")
        txt_supp.grid(row=0, column=0, sticky="eswn")
        scrollx_supp = Scrollbar(frame_supp,
                                 orient="horizontal",
                                 command=txt_supp.xview)
        scrolly_supp = Scrollbar(frame_supp,
                                 orient="vertical",
                                 command=txt_supp.yview)
        scrollx_supp.grid(row=2, column=0, sticky="ew")
        scrolly_supp.grid(row=1, column=1, sticky="ns")
        txt_supp.configure(yscrollcommand=scrolly_supp.set,
                           xscrollcommand=scrollx_supp.set)
        txt_supp.insert("1.0", "\n".join(a_supp))
        txt_supp.configure(state="disabled")
        self._size_supp = Label(frame_supp)
        self._size_supp.grid(row=3, column=0)

        Button(self, command=self.ok, text="Ok").grid(row=3,
                                                      column=0,
                                                      sticky="e",
                                                      padx=(10, 4),
                                                      pady=(4, 10))
        Button(self, text=_("Cancel"), command=self.destroy).grid(row=3,
                                                                  column=1,
                                                                  sticky="w",
                                                                  padx=(4, 10),
                                                                  pady=(4, 10))
        self.wait_visibility()
        self.grab_set()
        self.transient(self.master)
        if show_size:
            self.compute_size()
Esempio n. 6
0
    def __init__(self):
        Tk.__init__(self, className='FolderSync')
        self.title("FolderSync")
        self.geometry("%ix%i" %
                      (self.winfo_screenwidth(), self.winfo_screenheight()))
        self.protocol("WM_DELETE_WINDOW", self.quitter)
        self.icon = PhotoImage(master=self, file=IM_ICON)
        self.iconphoto(True, self.icon)
        self.rowconfigure(2, weight=1)
        self.columnconfigure(0, weight=1)

        # --- icons
        self.img_about = PhotoImage(master=self, file=IM_ABOUT)
        self.img_open = PhotoImage(master=self, file=IM_OPEN)
        self.img_plus = PhotoImage(master=self, file=IM_PLUS)
        self.img_moins = PhotoImage(master=self, file=IM_MOINS)
        self.img_sync = PhotoImage(master=self, file=IM_SYNC)
        self.img_prev = PhotoImage(master=self, file=IM_PREV)
        self.img_expand = PhotoImage(master=self, file=IM_EXPAND)
        self.img_collapse = PhotoImage(master=self, file=IM_COLLAPSE)

        self.original = ""
        self.sauvegarde = ""
        # list of files / folders to delete before starting the copy because
        # they are not of the same type on the original and the backup
        self.pb_chemins = []
        self.err_copie = False
        self.err_supp = False

        # --- init log files
        l = [f for f in listdir(PATH) if match(r"foldersync[0-9]+.pid", f)]
        nbs = []
        for f in l:
            with open(join(PATH, f)) as fich:
                old_pid = fich.read().strip()
            if exists("/proc/%s" % old_pid):
                nbs.append(int(search(r"[0-9]+", f).group()))
            else:
                remove(join(PATH, f))
        if not nbs:
            i = 0
        else:
            nbs.sort()
            i = 0
            while i in nbs:
                i += 1
        self.pidfile = PID_FILE % i
        open(self.pidfile, 'w').write(str(getpid()))

        self.log_copie = LOG_COPIE % i
        self.log_supp = LOG_SUPP % i

        self.logger_copie = setup_logger("copie", self.log_copie)
        self.logger_supp = setup_logger("supp", self.log_supp)
        date = datetime.now().strftime('%d/%m/%Y %H:%M')
        self.logger_copie.info("\n###  %s  ###\n" % date)
        self.logger_supp.info("\n###  %s  ###\n" % date)

        # --- filenames and extensions that will not be copied
        exclude_list = split(r'(?<!\\) ',
                             CONFIG.get("Defaults", "exclude_copie"))
        self.exclude_names = []
        self.exclude_ext = []
        for elt in exclude_list:
            if elt:
                if elt[:2] == "*.":
                    self.exclude_ext.append(elt[1:])
                else:
                    self.exclude_names.append(elt.replace("\ ", " "))

        # --- paths that will not be deleted
        self.exclude_path_supp = [
            ch.replace("\ ", " ") for ch in split(
                r'(?<!\\) ', CONFIG.get("Defaults", "exclude_supp")) if ch
        ]
        #        while "" in self.exclude_path_supp:
        #            self.exclude_path_supp.remove("")

        self.q_copie = Queue()
        self.q_supp = Queue()
        # True if a copy / deletion is running
        self.is_running_copie = False
        self.is_running_supp = False

        self.style = Style(self)
        self.style.theme_use("clam")
        self.style.configure("TProgressbar",
                             troughcolor='lightgray',
                             background='#387EF5',
                             lightcolor="#5D95F5",
                             darkcolor="#2758AB")
        self.style.map("TProgressbar",
                       lightcolor=[("disabled", "white")],
                       darkcolor=[("disabled", "gray")])
        self.style.configure("folder.TButton", padding=0)
        # --- menu
        self.menu = Menu(self, tearoff=False)
        self.configure(menu=self.menu)

        # -------- recents
        self.menu_recent = Menu(self.menu, tearoff=False)
        if RECENT:
            for ch_o, ch_s in RECENT:
                self.menu_recent.add_command(
                    label="%s -> %s" % (ch_o, ch_s),
                    command=lambda o=ch_o, s=ch_s: self.open(o, s))
        else:
            self.menu.entryconfigure(0, state="disabled")

        # -------- favorites
        self.menu_fav = Menu(self.menu, tearoff=False)
        self.menu_fav_del = Menu(self.menu_fav, tearoff=False)
        self.menu_fav.add_command(label=_("Add"),
                                  image=self.img_plus,
                                  compound="left",
                                  command=self.add_fav)
        self.menu_fav.add_cascade(label=_("Remove"),
                                  image=self.img_moins,
                                  compound="left",
                                  menu=self.menu_fav_del)
        for ch_o, ch_s in FAVORIS:
            label = "%s -> %s" % (ch_o, ch_s)
            self.menu_fav.add_command(
                label=label, command=lambda o=ch_o, s=ch_s: self.open(o, s))
            self.menu_fav_del.add_command(
                label=label, command=lambda nom=label: self.del_fav(nom))
        if not FAVORIS:
            self.menu_fav.entryconfigure(1, state="disabled")

        # -------- log files
        menu_log = Menu(self.menu, tearoff=False)
        menu_log.add_command(label=_("Copy"), command=self.open_log_copie)
        menu_log.add_command(label=_("Removal"),
                             command=self.open_log_suppression)

        # -------- settings
        menu_params = Menu(self.menu, tearoff=False)
        self.copy_links = BooleanVar(self,
                                     value=CONFIG.getboolean(
                                         "Defaults", "copy_links"))
        self.show_size = BooleanVar(self,
                                    value=CONFIG.getboolean(
                                        "Defaults", "show_size"))
        menu_params.add_checkbutton(label=_("Copy links"),
                                    variable=self.copy_links,
                                    command=self.toggle_copy_links)
        menu_params.add_checkbutton(label=_("Show total size"),
                                    variable=self.show_size,
                                    command=self.toggle_show_size)
        self.langue = StringVar(self, CONFIG.get("Defaults", "language"))
        menu_lang = Menu(menu_params, tearoff=False)
        menu_lang.add_radiobutton(label="English",
                                  value="en",
                                  variable=self.langue,
                                  command=self.change_language)
        menu_lang.add_radiobutton(label="Français",
                                  value="fr",
                                  variable=self.langue,
                                  command=self.change_language)
        menu_params.add_cascade(label=_("Language"), menu=menu_lang)
        menu_params.add_command(label=_("Exclude from copy"),
                                command=self.exclusion_copie)
        menu_params.add_command(label=_("Exclude from removal"),
                                command=self.exclusion_supp)

        self.menu.add_cascade(label=_("Recents"), menu=self.menu_recent)
        self.menu.add_cascade(label=_("Favorites"), menu=self.menu_fav)
        self.menu.add_cascade(label=_("Log"), menu=menu_log)
        self.menu.add_cascade(label=_("Settings"), menu=menu_params)
        self.menu.add_command(image=self.img_prev,
                              compound="center",
                              command=self.list_files_to_sync)
        self.menu.add_command(image=self.img_sync,
                              compound="center",
                              state="disabled",
                              command=self.synchronise)
        self.menu.add_command(image=self.img_about,
                              compound="center",
                              command=lambda: About(self))
        # --- tooltips
        wrapper = TooltipMenuWrapper(self.menu)
        wrapper.add_tooltip(4, _('Preview'))
        wrapper.add_tooltip(5, _('Sync'))
        wrapper.add_tooltip(6, _('About'))

        # --- path selection
        frame_paths = Frame(self)
        frame_paths.grid(row=0, sticky="ew", pady=(10, 0))
        frame_paths.columnconfigure(0, weight=1)
        frame_paths.columnconfigure(1, weight=1)
        f1 = Frame(frame_paths, height=26)
        f2 = Frame(frame_paths, height=26)
        f1.grid(row=0, column=0, sticky="ew")
        f2.grid(row=0, column=1, sticky="ew")
        f1.grid_propagate(False)
        f2.grid_propagate(False)
        f1.columnconfigure(1, weight=1)
        f2.columnconfigure(1, weight=1)

        # -------- path to original
        Label(f1, text=_("Original")).grid(row=0, column=0, padx=(10, 4))
        f11 = Frame(f1)
        f11.grid(row=0, column=1, sticky="nsew", padx=(4, 0))
        self.entry_orig = Entry(f11)
        self.entry_orig.place(x=1, y=0, bordermode='outside', relwidth=1)
        self.b_open_orig = Button(f1,
                                  image=self.img_open,
                                  style="folder.TButton",
                                  command=self.open_orig)
        self.b_open_orig.grid(row=0, column=2, padx=(0, 7))
        # -------- path to backup
        Label(f2, text=_("Backup")).grid(row=0, column=0, padx=(8, 4))
        f22 = Frame(f2)
        f22.grid(row=0, column=1, sticky="nsew", padx=(4, 0))
        self.entry_sauve = Entry(f22)
        self.entry_sauve.place(x=1, y=0, bordermode='outside', relwidth=1)
        self.b_open_sauve = Button(f2,
                                   image=self.img_open,
                                   width=2,
                                   style="folder.TButton",
                                   command=self.open_sauve)
        self.b_open_sauve.grid(row=0, column=5, padx=(0, 10))

        paned = PanedWindow(self, orient='horizontal')
        paned.grid(row=2, sticky="eswn")
        paned.rowconfigure(0, weight=1)
        paned.columnconfigure(1, weight=1)
        paned.columnconfigure(0, weight=1)

        # --- left side
        frame_left = Frame(paned)
        paned.add(frame_left, weight=1)
        frame_left.rowconfigure(3, weight=1)
        frame_left.columnconfigure(0, weight=1)

        # -------- files to copy
        f_left = Frame(frame_left)
        f_left.columnconfigure(2, weight=1)
        f_left.grid(row=2,
                    columnspan=2,
                    pady=(4, 2),
                    padx=(10, 4),
                    sticky="ew")

        Label(f_left, text=_("To copy")).grid(row=0, column=2)
        frame_copie = Frame(frame_left)
        frame_copie.rowconfigure(0, weight=1)
        frame_copie.columnconfigure(0, weight=1)
        frame_copie.grid(row=3,
                         column=0,
                         sticky="eswn",
                         columnspan=2,
                         pady=(2, 4),
                         padx=(10, 4))
        self.tree_copie = CheckboxTreeview(frame_copie,
                                           selectmode='none',
                                           show='tree')
        self.b_expand_copie = Button(f_left,
                                     image=self.img_expand,
                                     style="folder.TButton",
                                     command=self.tree_copie.expand_all)
        TooltipWrapper(self.b_expand_copie, text=_("Expand all"))
        self.b_expand_copie.grid(row=0, column=0)
        self.b_expand_copie.state(("disabled", ))
        self.b_collapse_copie = Button(f_left,
                                       image=self.img_collapse,
                                       style="folder.TButton",
                                       command=self.tree_copie.collapse_all)
        TooltipWrapper(self.b_collapse_copie, text=_("Collapse all"))
        self.b_collapse_copie.grid(row=0, column=1, padx=4)
        self.b_collapse_copie.state(("disabled", ))
        self.tree_copie.tag_configure("warning", foreground="red")
        self.tree_copie.tag_configure("link",
                                      font="tkDefaultFont 9 italic",
                                      foreground="blue")
        self.tree_copie.tag_bind("warning", "<Button-1>", self.show_warning)
        self.tree_copie.grid(row=0, column=0, sticky="eswn")
        self.scroll_y_copie = Scrollbar(frame_copie,
                                        orient="vertical",
                                        command=self.tree_copie.yview)
        self.scroll_y_copie.grid(row=0, column=1, sticky="ns")
        self.scroll_x_copie = Scrollbar(frame_copie,
                                        orient="horizontal",
                                        command=self.tree_copie.xview)
        self.scroll_x_copie.grid(row=1, column=0, sticky="ew")
        self.tree_copie.configure(yscrollcommand=self.scroll_y_copie.set,
                                  xscrollcommand=self.scroll_x_copie.set)
        self.pbar_copie = Progressbar(frame_left,
                                      orient="horizontal",
                                      mode="determinate")
        self.pbar_copie.grid(row=4,
                             columnspan=2,
                             sticky="ew",
                             padx=(10, 4),
                             pady=4)
        self.pbar_copie.state(("disabled", ))

        # --- right side
        frame_right = Frame(paned)
        paned.add(frame_right, weight=1)
        frame_right.rowconfigure(3, weight=1)
        frame_right.columnconfigure(0, weight=1)

        # -------- files to delete
        f_right = Frame(frame_right)
        f_right.columnconfigure(2, weight=1)
        f_right.grid(row=2,
                     columnspan=2,
                     pady=(4, 2),
                     padx=(4, 10),
                     sticky="ew")
        Label(f_right, text=_("To remove")).grid(row=0, column=2)
        frame_supp = Frame(frame_right)
        frame_supp.rowconfigure(0, weight=1)
        frame_supp.columnconfigure(0, weight=1)
        frame_supp.grid(row=3,
                        columnspan=2,
                        sticky="eswn",
                        pady=(2, 4),
                        padx=(4, 10))
        self.tree_supp = CheckboxTreeview(frame_supp,
                                          selectmode='none',
                                          show='tree')
        self.b_expand_supp = Button(f_right,
                                    image=self.img_expand,
                                    style="folder.TButton",
                                    command=self.tree_supp.expand_all)
        TooltipWrapper(self.b_expand_supp, text=_("Expand all"))
        self.b_expand_supp.grid(row=0, column=0)
        self.b_expand_supp.state(("disabled", ))
        self.b_collapse_supp = Button(f_right,
                                      image=self.img_collapse,
                                      style="folder.TButton",
                                      command=self.tree_supp.collapse_all)
        TooltipWrapper(self.b_collapse_supp, text=_("Collapse all"))
        self.b_collapse_supp.grid(row=0, column=1, padx=4)
        self.b_collapse_supp.state(("disabled", ))
        self.tree_supp.grid(row=0, column=0, sticky="eswn")
        self.scroll_y_supp = Scrollbar(frame_supp,
                                       orient="vertical",
                                       command=self.tree_supp.yview)
        self.scroll_y_supp.grid(row=0, column=1, sticky="ns")
        self.scroll_x_supp = Scrollbar(frame_supp,
                                       orient="horizontal",
                                       command=self.tree_supp.xview)
        self.scroll_x_supp.grid(row=1, column=0, sticky="ew")
        self.tree_supp.configure(yscrollcommand=self.scroll_y_supp.set,
                                 xscrollcommand=self.scroll_x_supp.set)
        self.pbar_supp = Progressbar(frame_right,
                                     orient="horizontal",
                                     mode="determinate")
        self.pbar_supp.grid(row=4,
                            columnspan=2,
                            sticky="ew",
                            padx=(4, 10),
                            pady=4)
        self.pbar_supp.state(("disabled", ))

        # --- bindings
        self.entry_orig.bind("<Key-Return>", self.list_files_to_sync)
        self.entry_sauve.bind("<Key-Return>", self.list_files_to_sync)
Esempio n. 7
0
    def __init__(self):
        Tk.__init__(self)
        self.title("FolderSync")
        self.geometry("%ix%i" %
                      (self.winfo_screenwidth(), self.winfo_screenheight()))
        self.protocol("WM_DELETE_WINDOW", self.quitter)
        self.icon = PhotoImage(master=self, file=IM_ICON)
        self.iconphoto(True, self.icon)
        self.rowconfigure(2, weight=1)
        self.columnconfigure(0, weight=1)

        # --- icons
        self.img_about = PhotoImage(master=self, file=IM_ABOUT)
        self.img_open = PhotoImage(master=self, file=IM_OPEN)
        self.img_plus = PhotoImage(master=self, file=IM_PLUS)
        self.img_moins = PhotoImage(master=self, file=IM_MOINS)
        self.img_sync = PhotoImage(master=self, file=IM_SYNC)
        self.img_prev = PhotoImage(master=self, file=IM_PREV)
        self.img_expand = PhotoImage(master=self, file=IM_EXPAND)
        self.img_collapse = PhotoImage(master=self, file=IM_COLLAPSE)

        self.original = ""
        self.sauvegarde = ""
        # liste des fichiers/dossiers à supprimer avant de lancer la copie car
        # ils sont de nature différente sur l'original et la sauvegarde
        self.pb_chemins = []
        self.err_copie = False
        self.err_supp = False

        # --- init log files
        l = [
            f for f in listdir('/tmp') if re.match(r"foldersync[0-9]+.pid", f)
        ]
        nbs = []
        for f in l:
            with open(join('/tmp', f)) as fich:
                old_pid = fich.read().strip()
            if exists("/proc/%s" % old_pid):
                nbs.append(int(re.search(r"[0-9]+", f).group()))
            else:
                remove(f)
        if not nbs:
            i = 0
        else:
            nbs.sort()
            i = 0
            while i in nbs:
                i += 1
        self.pidfile = PID_FILE % i
        open(self.pidfile, 'w').write(str(getpid()))

        self.log_copie = LOG_COPIE % i
        self.log_supp = LOG_SUPP % i

        self.logger_copie = setup_logger("copie", self.log_copie)
        self.logger_supp = setup_logger("supp", self.log_supp)
        date = datetime.now().strftime('%d/%m/%Y %H:%M')
        self.logger_copie.info("\n###  %s  ###\n" % date)
        self.logger_supp.info("\n###  %s  ###\n" % date)

        # --- filenames and extensions that will not be copied
        exclude_list = split(r'(?<!\\) ',
                             CONFIG.get("Defaults", "exclude_copie"))
        self.exclude_names = []
        self.exclude_ext = []
        for elt in exclude_list:
            if elt:
                if elt[:2] == "*.":
                    self.exclude_ext.append(elt[1:])
                else:
                    self.exclude_names.append(elt.replace("\ ", " "))

        # --- paths that will not be deleted
        self.exclude_path_supp = [
            ch.replace("\ ", " ") for ch in split(
                r'(?<!\\) ', CONFIG.get("Defaults", "exclude_supp")) if ch
        ]
        #        while "" in self.exclude_path_supp:
        #            self.exclude_path_supp.remove("")

        self.q_copie = Queue()
        self.q_supp = Queue()
        # True si une copie / suppression est en cours
        self.is_running_copie = False
        self.is_running_supp = False

        self.style = Style(self)
        self.style.theme_use("clam")
        self.style.configure("TProgressbar",
                             troughcolor='lightgray',
                             background='#387EF5',
                             lightcolor="#5D95F5",
                             darkcolor="#2758AB")
        self.style.map("TProgressbar",
                       lightcolor=[("disabled", "white")],
                       darkcolor=[("disabled", "gray")])
        self.style.configure("folder.TButton", padding=1)
        # --- menu
        self.menu = Menu(self, tearoff=False)
        self.configure(menu=self.menu)

        # emplacements récents
        self.menu_recent = Menu(self.menu, tearoff=False)
        if RECENT:
            for ch_o, ch_s in RECENT:
                self.menu_recent.add_command(
                    label="%s -> %s" % (ch_o, ch_s),
                    command=lambda o=ch_o, s=ch_s: self.open(o, s))
        else:
            self.menu.entryconfigure(0, state="disabled")

        # emplacements favoris
        self.menu_fav = Menu(self.menu, tearoff=False)
        self.menu_fav_del = Menu(self.menu_fav, tearoff=False)
        self.menu_fav.add_command(label="Ajouter",
                                  image=self.img_plus,
                                  compound="left",
                                  command=self.add_fav)
        self.menu_fav.add_cascade(label="Supprimer",
                                  image=self.img_moins,
                                  compound="left",
                                  menu=self.menu_fav_del)
        for ch_o, ch_s in FAVORIS:
            label = "%s -> %s" % (ch_o, ch_s)
            self.menu_fav.add_command(
                label=label, command=lambda o=ch_o, s=ch_s: self.open(o, s))
            self.menu_fav_del.add_command(
                label=label, command=lambda nom=label: self.del_fav(nom))
        if not FAVORIS:
            self.menu_fav.entryconfigure(1, state="disabled")

        # accès aux fichiers log
        menu_log = Menu(self.menu, tearoff=False)
        menu_log.add_command(label="Copie", command=self.open_log_copie)
        menu_log.add_command(label="Suppression",
                             command=self.open_log_suppression)

        # paramètres, préférences
        menu_params = Menu(self.menu, tearoff=False)
        self.copy_links = BooleanVar(self,
                                     value=CONFIG.getboolean(
                                         "Defaults", "copy_links"))
        menu_params.add_checkbutton(label="Copier les liens",
                                    variable=self.copy_links,
                                    command=self.toggle_copy_links)
        menu_params.add_command(label="Exclusions copie",
                                command=self.exclusion_copie)
        menu_params.add_command(label="Exclusions supp",
                                command=self.exclusion_supp)

        self.menu.add_cascade(label="Récents", menu=self.menu_recent)
        self.menu.add_cascade(label="Favoris", menu=self.menu_fav)
        self.menu.add_cascade(label="Log", menu=menu_log)
        self.menu.add_cascade(label="Paramètres", menu=menu_params)
        self.menu.add_command(image=self.img_prev,
                              compound="center",
                              command=self.list_files_to_sync)
        self.menu.add_command(image=self.img_sync,
                              compound="center",
                              state="disabled",
                              command=self.synchronise)
        self.menu.add_command(image=self.img_about,
                              compound="center",
                              command=lambda: About(self))

        # sélection chemins
        frame_paths = Frame(self)
        frame_paths.grid(row=0, sticky="ew", pady=(10, 0))
        frame_paths.columnconfigure(0, weight=1)
        frame_paths.columnconfigure(1, weight=1)
        f1 = Frame(frame_paths, height=26)
        f2 = Frame(frame_paths, height=26)
        f1.grid(row=0, column=0, sticky="ew")
        f2.grid(row=0, column=1, sticky="ew")
        f1.grid_propagate(False)
        f2.grid_propagate(False)
        f1.columnconfigure(1, weight=1)
        f2.columnconfigure(1, weight=1)

        ## chemin vers original
        Label(f1, text="Original").grid(row=0, column=0, padx=(10, 4))
        self.entry_orig = Entry(f1)
        self.entry_orig.grid(row=0, column=1, sticky="ew", padx=(4, 2))
        self.b_open_orig = Button(f1,
                                  image=self.img_open,
                                  style="folder.TButton",
                                  command=self.open_orig)
        self.b_open_orig.grid(row=0, column=2, padx=(1, 8))
        ## chemin vers sauvegarde
        Label(f2, text="Sauvegarde").grid(row=0, column=0, padx=(8, 4))
        self.entry_sauve = Entry(f2)
        self.entry_sauve.grid(row=0, column=1, sticky="ew", padx=(4, 2))
        self.b_open_sauve = Button(f2,
                                   image=self.img_open,
                                   width=2,
                                   style="folder.TButton",
                                   command=self.open_sauve)
        self.b_open_sauve.grid(row=0, column=5, padx=(1, 10))

        #        self.b_prev = Button(frame_paths, image=self.img_prev,
        #                             command=self.list_files_to_sync)
        #        self.b_prev.grid(row=1, column=4, padx=4)
        #
        #        self.b_sync = Button(frame_paths, image=self.img_sync,
        #                             command=self.synchronise)
        #        self.b_sync.grid(row=1, column=5, padx=(4, 10))
        #        self.b_sync.state(("disabled", ))
        #        self.b_prev = Button(self, image=self.img_prev,
        #                             command=self.list_files_to_sync)
        #        self.b_prev.grid(row=1, sticky="ew", pady=(4, 10), padx=10)

        paned = PanedWindow(self, orient='horizontal')
        paned.grid(row=2, sticky="eswn")
        paned.rowconfigure(0, weight=1)
        paned.columnconfigure(1, weight=1)
        paned.columnconfigure(0, weight=1)

        # --- côté gauche
        frame_left = Frame(paned)
        paned.add(frame_left, weight=1)
        frame_left.rowconfigure(3, weight=1)
        frame_left.columnconfigure(0, weight=1)

        # fichiers à copier
        f_left = Frame(frame_left)
        f_left.columnconfigure(2, weight=1)
        f_left.grid(row=2,
                    columnspan=2,
                    pady=(4, 2),
                    padx=(10, 4),
                    sticky="ew")

        Label(f_left, text="À copier").grid(row=0, column=2)
        frame_copie = Frame(frame_left)
        frame_copie.rowconfigure(0, weight=1)
        frame_copie.columnconfigure(0, weight=1)
        frame_copie.grid(row=3,
                         column=0,
                         sticky="eswn",
                         columnspan=2,
                         pady=(2, 4),
                         padx=(10, 4))
        self.tree_copie = CheckboxTreeview(frame_copie,
                                           selectmode='none',
                                           show='tree')
        self.b_expand_copie = Button(f_left,
                                     image=self.img_expand,
                                     style="folder.TButton",
                                     command=self.tree_copie.expand_all)
        self.b_expand_copie.grid(row=0, column=0)
        self.b_expand_copie.state(("disabled", ))
        self.b_collapse_copie = Button(f_left,
                                       image=self.img_collapse,
                                       style="folder.TButton",
                                       command=self.tree_copie.collapse_all)
        self.b_collapse_copie.grid(row=0, column=1, padx=4)
        self.b_collapse_copie.state(("disabled", ))
        self.tree_copie.tag_configure("warning", foreground="red")
        self.tree_copie.tag_configure("link",
                                      font="tkDefaultFont 9 italic",
                                      foreground="blue")
        self.tree_copie.tag_bind("warning", "<Button-1>", self.show_warning)
        self.tree_copie.grid(row=0, column=0, sticky="eswn")
        self.scroll_y_copie = Scrollbar(frame_copie,
                                        orient="vertical",
                                        command=self.tree_copie.yview)
        self.scroll_y_copie.grid(row=0, column=1, sticky="ns")
        self.scroll_x_copie = Scrollbar(frame_copie,
                                        orient="horizontal",
                                        command=self.tree_copie.xview)
        self.scroll_x_copie.grid(row=1, column=0, sticky="ew")
        self.tree_copie.configure(yscrollcommand=self.scroll_y_copie.set,
                                  xscrollcommand=self.scroll_x_copie.set)
        self.pbar_copie = Progressbar(frame_left,
                                      orient="horizontal",
                                      mode="determinate")
        self.pbar_copie.grid(row=4,
                             columnspan=2,
                             sticky="ew",
                             padx=(10, 4),
                             pady=4)
        self.pbar_copie.state(("disabled", ))

        # --- côté droit
        frame_right = Frame(paned)
        paned.add(frame_right, weight=1)
        frame_right.rowconfigure(3, weight=1)
        frame_right.columnconfigure(0, weight=1)

        # fichiers à supprimer
        f_right = Frame(frame_right)
        f_right.columnconfigure(2, weight=1)
        f_right.grid(row=2,
                     columnspan=2,
                     pady=(4, 2),
                     padx=(4, 10),
                     sticky="ew")
        Label(f_right, text="À supprimer").grid(row=0, column=2)
        frame_supp = Frame(frame_right)
        frame_supp.rowconfigure(0, weight=1)
        frame_supp.columnconfigure(0, weight=1)
        frame_supp.grid(row=3,
                        columnspan=2,
                        sticky="eswn",
                        pady=(2, 4),
                        padx=(4, 10))
        self.tree_supp = CheckboxTreeview(frame_supp,
                                          selectmode='none',
                                          show='tree')
        self.b_expand_supp = Button(f_right,
                                    image=self.img_expand,
                                    style="folder.TButton",
                                    command=self.tree_supp.expand_all)
        self.b_expand_supp.grid(row=0, column=0)
        self.b_expand_supp.state(("disabled", ))
        self.b_collapse_supp = Button(f_right,
                                      image=self.img_collapse,
                                      style="folder.TButton",
                                      command=self.tree_supp.collapse_all)
        self.b_collapse_supp.grid(row=0, column=1, padx=4)
        self.b_collapse_supp.state(("disabled", ))
        self.tree_supp.grid(row=0, column=0, sticky="eswn")
        self.scroll_y_supp = Scrollbar(frame_supp,
                                       orient="vertical",
                                       command=self.tree_supp.yview)
        self.scroll_y_supp.grid(row=0, column=1, sticky="ns")
        self.scroll_x_supp = Scrollbar(frame_supp,
                                       orient="horizontal",
                                       command=self.tree_supp.xview)
        self.scroll_x_supp.grid(row=1, column=0, sticky="ew")
        self.tree_supp.configure(yscrollcommand=self.scroll_y_supp.set,
                                 xscrollcommand=self.scroll_x_supp.set)
        self.pbar_supp = Progressbar(frame_right,
                                     orient="horizontal",
                                     mode="determinate")
        self.pbar_supp.grid(row=4,
                            columnspan=2,
                            sticky="ew",
                            padx=(4, 10),
                            pady=4)
        self.pbar_supp.state(("disabled", ))

        #        # lancer synchronisation
        #        self.b_sync = Button(self, image=self.img_sync,
        #                             command=self.synchronise)
        #        self.b_sync.grid(row=3, sticky="ew", pady=(4, 10), padx=10)
        #        self.b_sync.state(("disabled", ))

        # bindings
        self.entry_orig.bind("<Key-Return>", self.list_files_to_sync)
        self.entry_sauve.bind("<Key-Return>", self.list_files_to_sync)
Esempio n. 8
0
class Main(object):
    def __init__(self, title):
        root = Tk()
        root.title(title)
        root.focus_set()
        root.rowconfigure(0, weight=0)
        root.columnconfigure(0, weight=1)
        root.rowconfigure(1, weight=1)
        self._root = root

        self.menubar = Frame(root)
        self.menubar.grid(row=0, column=0, sticky=(W, E))
        self.menubar['takefocus'] = False

        quit_button = Button(self.menubar, text='Quit', command=self.quit)
        quit_button.grid(row=0, column=0)

        self._menucolumn = 1
        self.views = list()

        self.paned_win = PanedWindow(root, orient=HORIZONTAL)
        self.paned_win.grid(row=1, column=0, sticky=(N, S, W, E))

        self._query = None
        self._accept_func = None

        self.sidebar_views = dict()
        self.sidebar_count = 0
        self.sidebar = PanedWindow(self.paned_win)
        self.paned_win.add(self.sidebar, weight=1)

        self.tabs = Notebook(self.paned_win)
        self.tabs.enable_traversal()
        self.paned_win.add(self.tabs, weight=5)
        self.root = self.tabs

    def add_menubutton(self, label, action):
        button = Button(self.menubar, text=label, command=action)
        button.grid(row=0, column=self._menucolumn)
        self._menucolumn += 1

    def add_sidebar(self, view, name):
        self.sidebar_views[name] = view
        self.sidebar.add(view.widget, weight=1)
        view.widget.focus_set()
        self.sidebar_count += 1
        if self.sidebar_count == 1:
            self.sidebar_views['main'] = view

    def remove_sidebar_view(self, name):
        self.sidebar.forget(self.sidebar_views[name].widget)
        self.sidebar_count -= 1
        del self.sidebar_views[name]
        if self.sidebar_count == 0:
            del self.sidebar_views['main']

    def get_sidebar_view(self, name):
        return self.sidebar_views.get(name)

    def focus_sidebar(self):
        if 'main' in self.sidebar_views.keys():
            self.sidebar_views['main'].widget.focus_set()

    def focus_main_view(self):
        self.get_current_view().widget.focus_set()

    def new_view(self, view):
        self.views.append(view)
        self.tabs.add(view.widget, text=" {}.".format(self.tabs.index('end')))
        self.tabs.select(view.widget)

        view.widget.focus_set()
        self.view_changed()

    def remove_view(self, view):
        self.views.remove(view)
        self.tabs.forget(view.widget)
        if len(self.views) >= 1:
            widget = self.views[-1].widget
            self.tabs.select(widget)
            widget.focus_set()
        else:
            self.sidebar_views['main'].widget.focus_set()
        self.view_changed()

    def delete_current_view(self, event):
        if self.tabs.index('end') > 0:
            self.remove_view(self.get_current_view())

    def close_query(self):
        if self._query is not None:
            self._query.event_generate('<<MainQueryClose>>')
            self._query.destroy()
            self._query = None
            self._accept_func = None
            self._menucolumn -= 1

    def accept_query(self, event):
        if self._query is not None:
            if self._accept_func is not None:
                self._accept_func(event.widget.get(),
                                  event.widget.original_value)
                self.close_query()
            else:
                event.widget.event_generate('<<MainQueryAccept>>')

    def text_query(self, query_lable, original_text=None, accept_func=None):
        if self._query is not None:
            return
        frame = Frame(self.menubar)
        label = Label(frame, text=query_lable)
        label.grid(column=0, row=0, sticky=(N, S))
        self._accept_func = accept_func

        entry = Entry(frame)
        if original_text is not None:
            entry.insert(0, original_text)
        entry.original_value = original_text
        entry.grid(column=1, row=0, sticky=(N, S, W, E))
        kb.make_bindings(kb.text_query, {
            'accept': self.accept_query,
            'cancel': lambda e: self.close_query()
        }, entry.bind)

        frame.grid(column=self._menucolumn, row=0)
        self._menucolumn += 1
        entry.focus_set()
        self._query = frame

    def get_current_view(self):
        if self.tabs.index('end') > 0:
            return self.views[self.tabs.index('current')]
        else:
            return self.sidebar_views['main']

    def view_changed(self):
        self._root.event_generate('<<MainViewChanged>>')

    def display(self):
        self._root.mainloop()

    def quit(self):
        self._root.destroy()
Esempio n. 9
0
class Main(object):

    def __init__(self, title):
        root = Tk()
        root.title(title)
        root.focus_set()
        root.rowconfigure(0, weight=0)
        root.columnconfigure(0, weight=1)
        root.rowconfigure(1, weight=1)
        self._root = root

        self.menubar = Frame(root)
        self.menubar.grid(row=0, column=0, sticky=(W, E))
        self.menubar['takefocus'] = False

        quit_button = Button(self.menubar, text='Quit', command=self.quit)
        quit_button.grid(row=0, column=0)

        self._menucolumn = 1
        self.views = list()

        self.paned_win = PanedWindow(root, orient=HORIZONTAL)
        self.paned_win.grid(row=1, column=0, sticky=(N, S, W, E))

        self._query = None
        self._accept_func = None

        self.sidebar_views = dict()
        self.sidebar_count = 0
        self.sidebar = PanedWindow(self.paned_win)
        self.paned_win.add(self.sidebar, weight=1)
        
        self.tabs = Notebook(self.paned_win)
        self.tabs.enable_traversal()
        self.paned_win.add(self.tabs, weight=5)
        self.root = self.tabs

    def add_menubutton(self, label, action):
        button = Button(self.menubar, text=label, command=action)
        button.grid(row=0, column=self._menucolumn)
        self._menucolumn += 1

    def add_sidebar(self, view, name):
        self.sidebar_views[name] = view
        self.sidebar.add(view.widget, weight=1)
        view.widget.focus_set()
        self.sidebar_count += 1
        if self.sidebar_count == 1:
            self.sidebar_views['main'] = view

    def remove_sidebar_view(self, name):
        self.sidebar.forget(self.sidebar_views[name].widget)
        self.sidebar_count -= 1
        del self.sidebar_views[name]
        if self.sidebar_count == 0:
            del self.sidebar_views['main']

    def get_sidebar_view(self, name):
        return self.sidebar_views.get(name)

    def focus_sidebar(self):
        if 'main' in self.sidebar_views.keys():
            self.sidebar_views['main'].widget.focus_set()

    def focus_main_view(self):
        self.get_current_view().widget.focus_set()

    def new_view(self, view):
        self.views.append(view)
        self.tabs.add(view.widget, text=" {}.".format(self.tabs.index('end')))
        self.tabs.select(view.widget)

        view.widget.focus_set()
        self.view_changed()

    def remove_view(self, view):
        self.views.remove(view)
        self.tabs.forget(view.widget)
        if len(self.views) >= 1:
            widget = self.views[-1].widget
            self.tabs.select(widget)
            widget.focus_set()
        else:
            self.sidebar_views['main'].widget.focus_set()
        self.view_changed()

    def delete_current_view(self, event):
        if self.tabs.index('end') > 0:
            self.remove_view(self.get_current_view())

    def close_query(self):
        if self._query is not None:
            self._query.event_generate('<<MainQueryClose>>')
            self._query.destroy()
            self._query = None
            self._accept_func = None
            self._menucolumn -= 1

    def accept_query(self, event):
        if self._query is not None:
            if self._accept_func is not None:
                self._accept_func(event.widget.get(), event.widget.original_value)
                self.close_query()
            else:
                event.widget.event_generate('<<MainQueryAccept>>')

    def text_query(self, query_lable, original_text=None, accept_func=None):
        if self._query is not None:
            return
        frame = Frame(self.menubar)
        label = Label(frame, text=query_lable)
        label.grid(column=0, row=0, sticky=(N, S))
        self._accept_func = accept_func

        entry = Entry(frame)
        if original_text is not None:
            entry.insert(0, original_text)
        entry.original_value = original_text
        entry.grid(column=1, row=0, sticky=(N,S,W,E))
        kb.make_bindings(kb.text_query, 
                {'accept': self.accept_query,
                 'cancel': lambda e: self.close_query()}, entry.bind)

        frame.grid(column=self._menucolumn, row=0)
        self._menucolumn += 1
        entry.focus_set()
        self._query = frame

    def get_current_view(self):
        if self.tabs.index('end') > 0:
            return self.views[self.tabs.index('current')]
        else:
            return self.sidebar_views['main']

    def view_changed(self):
        self._root.event_generate('<<MainViewChanged>>')

    def display(self):
        self._root.mainloop()

    def quit(self):
        self._root.destroy()
Esempio n. 10
0
class MainWindow(object):
    def __init__(self, root, options):
        '''
        -----------------------------------------------------
        | main button toolbar                               |
        -----------------------------------------------------
        |       < ma | in content area >                    |
        |            |                                      |
        | File list  | File name                            |
        |            |                                      |
        -----------------------------------------------------
        |     status bar area                               |
        -----------------------------------------------------

        '''
        # Obtain and expand the current working directory.
        if options.path:
            base_path = os.path.abspath(options.path)
        else:
            base_path = os.path.abspath(os.getcwd())
        self.base_path = os.path.normcase(base_path)

        # Create a filename normalizer based on the CWD.
        self.filename_normalizer = filename_normalizer(self.base_path)

        # Set up dummy coverage data
        self.coverage_data = {'lines': {}, 'total_coverage': None}

        # Root window
        self.root = root
        self.root.title('Duvet')
        self.root.geometry('1024x768')

        # Prevent the menus from having the empty tearoff entry
        self.root.option_add('*tearOff', tk.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)

    ######################################################
    # Internal GUI layout methods.
    ######################################################

    def _setup_menubar(self):
        # Menubar
        self.menubar = tk.Menu(self.root)

        # self.menu_Apple = Menu(self.menubar, name='Apple')
        # self.menubar.add_cascade(menu=self.menu_Apple)

        self.menu_file = tk.Menu(self.menubar)
        self.menubar.add_cascade(menu=self.menu_file, label='File')

        self.menu_help = tk.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='Close', command=self.cmd_dummy)

        self.menu_help.add_command(label='Open Documentation',
                                   command=self.cmd_duvet_docs)
        self.menu_help.add_command(label='Open Duvet project page',
                                   command=self.cmd_duvet_page)
        self.menu_help.add_command(label='Open Duvet on GitHub',
                                   command=self.cmd_duvet_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 = tk.Frame(self.root)
        self.toolbar.grid(column=0, row=0, sticky=(tk.W, tk.E))

        # Buttons on the toolbar
        self.refresh_button = tk.Button(self.toolbar,
                                        text='Refresh',
                                        command=self.cmd_refresh)
        self.refresh_button.grid(column=0, row=0)

        # Coverage summary for currently selected file.
        self.coverage_total_summary = tk.StringVar()
        self.coverage_total_summary_label = Label(
            self.toolbar,
            textvariable=self.coverage_total_summary,
            anchor=tk.E,
            padding=(5, 0, 5, 0),
            font=('Helvetica', '20'))
        self.coverage_total_summary_label.grid(column=1,
                                               row=0,
                                               sticky=(tk.W, tk.E))

        self.toolbar.columnconfigure(0, weight=0)
        self.toolbar.columnconfigure(1, weight=1)
        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=tk.HORIZONTAL)
        self.content.grid(column=0, row=1, sticky=(tk.N, tk.S, tk.E, tk.W))

        # Create the tree/control area on the left frame
        self._setup_left_frame()
        self._setup_project_file_tree()
        self._setup_global_file_tree()

        # Create the output/viewer area on the right frame
        self._setup_code_area()

        # 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=4)

    def _setup_left_frame(self):
        '''
        The left frame mostly consists of the tree widget
        '''

        # The left-hand side frame on the main content area
        # The tabs for the two trees
        self.tree_notebook = Notebook(self.content, padding=(0, 5, 0, 5))
        self.content.add(self.tree_notebook)

    def _setup_project_file_tree(self):

        self.project_file_tree_frame = tk.Frame(self.content)
        self.project_file_tree_frame.grid(column=0,
                                          row=0,
                                          sticky=(tk.N, tk.S, tk.E, tk.W))
        self.tree_notebook.add(self.project_file_tree_frame, text='Project')

        self.project_file_tree = FileView(self.project_file_tree_frame,
                                          normalizer=self.filename_normalizer,
                                          root=self.base_path)
        self.project_file_tree.grid(column=0,
                                    row=0,
                                    sticky=(tk.N, tk.S, tk.E, tk.W))

        # # The tree's vertical scrollbar
        self.project_file_tree_scrollbar = tk.Scrollbar(
            self.project_file_tree_frame, orient=tk.VERTICAL)
        self.project_file_tree_scrollbar.grid(column=1,
                                              row=0,
                                              sticky=(tk.N, tk.S))

        # # Tie the scrollbar to the text views, and the text views
        # # to each other.
        self.project_file_tree.config(
            yscrollcommand=self.project_file_tree_scrollbar.set)
        self.project_file_tree_scrollbar.config(
            command=self.project_file_tree.yview)

        # Setup weights for the "project_file_tree" tree
        self.project_file_tree_frame.columnconfigure(0, weight=1)
        self.project_file_tree_frame.columnconfigure(1, weight=0)
        self.project_file_tree_frame.rowconfigure(0, weight=1)

        # Handlers for GUI events
        self.project_file_tree.bind('<<TreeviewSelect>>',
                                    self.on_file_selected)

    def _setup_global_file_tree(self):

        self.global_file_tree_frame = tk.Frame(self.content)
        self.global_file_tree_frame.grid(column=0,
                                         row=0,
                                         sticky=(tk.N, tk.S, tk.E, tk.W))
        self.tree_notebook.add(self.global_file_tree_frame, text='Global')

        self.global_file_tree = FileView(self.global_file_tree_frame,
                                         normalizer=self.filename_normalizer)
        self.global_file_tree.grid(column=0,
                                   row=0,
                                   sticky=(tk.N, tk.S, tk.E, tk.W))

        # # The tree's vertical scrollbar
        self.global_file_tree_scrollbar = tk.Scrollbar(
            self.global_file_tree_frame, orient=tk.VERTICAL)
        self.global_file_tree_scrollbar.grid(column=1,
                                             row=0,
                                             sticky=(tk.N, tk.S))

        # # Tie the scrollbar to the text views, and the text views
        # # to each other.
        self.global_file_tree.config(
            yscrollcommand=self.global_file_tree_scrollbar.set)
        self.global_file_tree_scrollbar.config(
            command=self.global_file_tree.yview)

        # Setup weights for the "global_file_tree" tree
        self.global_file_tree_frame.columnconfigure(0, weight=1)
        self.global_file_tree_frame.columnconfigure(1, weight=0)
        self.global_file_tree_frame.rowconfigure(0, weight=1)

        # Handlers for GUI events
        self.global_file_tree.bind('<<TreeviewSelect>>', self.on_file_selected)

    def _setup_code_area(self):
        self.code_frame = tk.Frame(self.content)
        self.code_frame.grid(column=1, row=0, sticky=(tk.N, tk.S, tk.E, tk.W))

        # Label for current file
        self.current_file = tk.StringVar()
        self.current_file_label = Label(self.code_frame,
                                        textvariable=self.current_file)
        self.current_file_label.grid(column=0, row=0, sticky=(tk.W, tk.E))

        # Code display area
        self.code = CodeView(self.code_frame)
        self.code.grid(column=0, row=1, sticky=(tk.N, tk.S, tk.E, tk.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_status_bar(self):
        # Status bar
        self.statusbar = tk.Frame(self.root)
        self.statusbar.grid(column=0, row=2, sticky=(tk.W, tk.E))

        # Coverage summary for currently selected file.
        self.coverage_file_summary = tk.StringVar()
        self.coverage_file_summary_label = Label(
            self.statusbar, textvariable=self.coverage_file_summary)
        self.coverage_file_summary_label.grid(column=0,
                                              row=0,
                                              sticky=(tk.W, tk.E))
        self.coverage_file_summary.set('No file selected')

        # Main window resize handle
        self.grip = Sizegrip(self.statusbar)
        self.grip.grid(column=1, row=0, sticky=(tk.S, tk.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

            missing = self.coverage_data['missing'].get(
                os.path.normcase(filename), [])
            executed = self.coverage_data['lines'].get(
                os.path.normcase(filename), [])

            n_executed = len(executed)
            n_missing = len(missing)

            self.code.highlight_missing(missing)

            self.coverage_file_summary.set(
                '%s/%s lines executed' % (n_executed, n_executed + n_missing))

        self.code.line = line

    def load_coverage(self):
        "Load and display coverage data"
        # Store the old list of files that have coverage data.
        # We do this so we can identify stale data on the tree.
        old_files = set(self.coverage_data['lines'].keys())
        old_total_coverage = self.coverage_data['total_coverage']

        loaded = False
        retry = True
        while not loaded and retry:
            try:
                # Load the new coverage data
                cov = coverage.coverage()
                cov.load()

                # Override precision for coverage reporting.
                coverage.results.Numbers.set_precision(1)

                if cov.data.measured_files():
                    self.coverage_data = {
                        'lines': {},
                        'missing': {},
                    }
                    totals = coverage.results.Numbers()

                    # Update the coverage display of every file mentioned in the file.
                    for filename in cov.data.measured_files():
                        filename = os.path.normcase(filename)
                        node = nodify(filename)
                        dirname, basename = os.path.split(filename)

                        # If the normalized version of the filename is the same as the
                        # filename, then the file *isn't* under the project root.
                        if filename == self.filename_normalizer(filename):
                            file_tree = self.global_file_tree
                        else:
                            file_tree = self.project_file_tree

                        try:
                            # # Make sure the file exists on the tree.
                            file_tree.insert_filename(dirname, basename)

                            # Compute the coverage percentage
                            analysis = cov._analyze(filename)

                            self.coverage_data['lines'][
                                filename] = analysis.statements
                            self.coverage_data['missing'][
                                filename] = analysis.missing
                            file_coverage = analysis.numbers.pc_covered

                            totals = totals + analysis.numbers

                            file_tree.set(node, 'coverage',
                                          analysis.numbers.pc_covered_str)
                            # file_tree.set(node, 'branch_coverage', str(len(lines)))

                            # Set the color of the tree node based on coverage
                            if file_coverage < 70.0:
                                file_tree.item(node,
                                               tags=['file', 'code', 'bad'])
                            elif file_coverage < 80.0:
                                file_tree.item(node,
                                               tags=['file', 'code', 'poor'])
                            elif file_coverage < 90.0:
                                file_tree.item(node,
                                               tags=['file', 'code', 'ok'])
                            elif file_coverage < 99.9:
                                file_tree.item(node,
                                               tags=['file', 'code', 'good'])
                            else:
                                file_tree.item(
                                    node, tags=['file', 'code', 'perfect'])

                        except coverage.misc.NoSource:
                            # could mean the file was deleted after running coverage
                            file_tree.item(node, tags=['bad'])

                        # We've updated the file, so we know it isn't stale.
                        try:
                            old_files.remove(filename)
                        except KeyError:
                            # File wasn't loaded before; ignore this.
                            pass

                        # Clear out any stale coverage data
                        for filename in old_files:
                            node = nodify(filename)
                            if file_tree.exists(node):
                                file_tree.set(node, 'coverage', '')
                                file_tree.item(node, tags=['file', 'code'])

                    # Compute the overall coverage
                    total_coverage = totals.pc_covered
                    self.coverage_data['total_coverage'] = total_coverage

                    coverage_text = u'%.1f%%' % total_coverage

                    # Update the text with up/down arrows to reflect change
                    if old_total_coverage is not None:
                        if total_coverage > old_total_coverage:
                            coverage_text = coverage_text + u' ⬆'
                        elif total_coverage < old_total_coverage:
                            coverage_text = coverage_text + u' ⬇'

                    self.coverage_total_summary.set(coverage_text)

                    # Set the color based on coverage level.
                    if total_coverage < 70.0:
                        self.coverage_total_summary_label.configure(
                            foreground='red')
                    elif total_coverage < 80.0:
                        self.coverage_total_summary_label.configure(
                            foreground='orange')
                    elif total_coverage < 90.0:
                        self.coverage_total_summary_label.configure(
                            foreground='blue')
                    elif total_coverage < 99.9:
                        self.coverage_total_summary_label.configure(
                            foreground='cyan')
                    else:
                        self.coverage_total_summary_label.configure(
                            foreground='green')

                    # Refresh the file display
                    current_file = self.code._filename
                    if current_file:
                        self.code._filename = None
                        self.show_file(current_file)

                    loaded = True
                else:
                    retry = tkMessageBox.askretrycancel(
                        message=
                        "Couldn't find coverage data file. Have you generated coverage data? Is the .coverage in your current working directory",
                        title='No coverage data found')
            except Exception as e:
                retry = tkMessageBox.askretrycancel(
                    message=
                    "Couldn't load coverage data -- data file may be corrupted (Error was: %s)"
                    % e,
                    title='Problem loading coverage data')

        return loaded

    ######################################################
    # TK Main loop
    ######################################################

    def mainloop(self):
        self.root.mainloop()

    ######################################################
    # TK Command handlers
    ######################################################

    def cmd_quit(self):
        "Quit the program"
        self.root.quit()

    def cmd_refresh(self, event=None):
        "Refresh the coverage data"
        self.load_coverage()

    def cmd_duvet_page(self):
        "Show the Duvet project page"
        webbrowser.open_new('http://pybee.org/duvet')

    def cmd_duvet_github(self):
        "Show the Duvet GitHub repo"
        webbrowser.open_new('http://github.com/pybee/duvet')

    def cmd_duvet_docs(self):
        "Show the Duvet 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('https://duvet.readthedocs.io/en/v%s/' %
                                VERSION)
        else:
            webbrowser.open_new('https://duvet.readthedocs.io/')

    def cmd_beeware_page(self):
        "Show the BeeWare project page"
        webbrowser.open_new('http://pybee.org/')

    ######################################################
    # Handlers for GUI actions
    ######################################################

    def on_file_selected(self, event):
        "When a file is selected, highlight the file and line"
        if event.widget.selection():
            filename = event.widget.selection()[0]

            # Display the file in the code view
            if os.path.isfile(filename):
                self.show_file(filename=filename)
            else:
                self.code.filename = None
    def _create_text_tab(self, nb):
        # populate the third frame with other widgets
        self.pw = PanedWindow(nb, name='pw')
        self.pw.pack(fill='both', expand=True)

        lF = LabelFrame(self.pw, text="Slider")
        fr1 = Frame(lF)
        fr1.grid(row=0, column=0)
        from_ = -5
        to = 105
        value = 19
        step = 11
        fontSize = 9
        scvar = IntVar()
        #scRange=self.any_number_range(from_,to,step)
        #scLen = len(scRange[1]) * (fontSize + 10)

        self.sc = TtkScale(fr1,
                           from_=from_,
                           to=to,
                           variable=scvar,
                           orient='vertical',
                           length=200,
                           showvalue=True,
                           command=lambda s: scvar.set('%d' % float(s)),
                           tickinterval=5,
                           resolution=5)
        #self.sc = Scale(fr1, from_=from_, to=to, variable=scvar,
        #orient='vertical',length=scLen,
        #command=lambda s: scvar.set('%d' % float(s) ))
        self.sc.set(value)
        #l1 = Label(fr1,textvariable=scvar,width=5)
        l1 = Spinbox(fr1, from_=from_, to=to, textvariable=scvar, width=4)
        l1.grid(row=0, column=0, pady=2)
        self.sc.grid(row=0, column=1, pady=5, padx=40)
        fr = Frame(fr1)
        fr.grid(row=0, column=2)
        #for ix,sR in enumerate(scRange[1]):
        #lb = Label(fr, text=sR, font=('Courier New', str(fontSize)))
        #lb.grid(row=ix, column=1)

        schvar = IntVar()
        a = -5
        b = 105
        #schRange = self.any_number_range(a,b,s=11)
        #schLen = Font().measure(schRange[0])
        self.sch = TtkScale(lF,
                            from_=a,
                            to=b,
                            length=200,
                            variable=schvar,
                            orient='horizontal',
                            showvalue=True,
                            command=lambda s: schvar.set('%d' % float(s)),
                            tickinterval=5,
                            resolution=5)
        #self.sch = Scale(lF, from_=a, to=b, length=schLen, variable=schvar,
        #orient='horizontal',
        #command=lambda s: schvar.set('%d' % float(s) ))
        self.sch.set(23)
        #l2 = Label(lF,textvariable=schvar)
        l2 = Spinbox(lF, from_=a, to=b, textvariable=schvar, width=4)
        l2.grid(row=1, column=1, pady=2)
        self.sch.grid(row=2, column=1, pady=40, padx=5, sticky='nw')
        #l3 = Label(lF,text=schRange[0], font=('Courier New', str(fontSize)))
        #l3.grid(row=3,column=1,pady=2)
        self.sch.bind("<ButtonRelease-1>", self.show_x)
        self.pw.add(lF)

        lF1 = LabelFrame(self.pw, text="Progress", name='lf')
        pb1var = IntVar()
        pb2var = IntVar()
        self.pbar = Progressbar(lF1,
                                variable=pb1var,
                                length=150,
                                mode="indeterminate",
                                name='pb1',
                                orient='horizontal')
        self.pb2 = Progressbar(lF1,
                               variable=pb2var,
                               mode='indeterminate',
                               name='pb2',
                               orient='vertical')
        self.pbar["value"] = 25
        self.pbar.grid(row=1, column=0, padx=5, pady=5, sticky='nw')
        self.pb2.grid(row=1, column=1, padx=5, pady=5, sticky='nw')
        l3 = Label(lF1, textvariable=pb1var)
        l3.grid(row=0, column=0, pady=2, sticky='nw')
        l4 = Label(lF1, textvariable=pb2var)
        l4.grid(row=0, column=1, pady=2, sticky='nw')
        start = Button(lF1,
                       text='Start Progress',
                       command=lambda: self._do_bars('start'))
        stop = Button(lF1,
                      text='Stop Progress',
                      command=lambda: self._do_bars('stop'))
        start.grid(row=2, column=0, padx=5, pady=5, sticky='nw')
        stop.grid(row=3, column=0, padx=5, pady=5, sticky='nw')
        self.pw.add(lF1)

        # add to notebook (underline = index for short-cut character)
        nb.add(self.pw, text='Sliders & Others', underline=0)
class NotebookDemo:
    def __init__(self, fr):

        self.fr = fr
        self.st0 = Style()
        self.style = ts.ThemedStyle()  # Style()
        self._create_demo_panel()  # run this before allBtns
        self.allBtns = self.ttkbut + self.cbs[1:] + self.rb

    def _create_demo_panel(self):
        demoPanel = Frame(self.fr, name="demo")
        demoPanel.pack(side='top', fill='both', expand='y')

        # create the notebook
        self.nb = nb = Notebook(demoPanel, name="nb")

        # extend bindings to top level window allowing
        #   CTRL+TAB - cycles thru tabs
        #   SHIFT+CTRL+TAB - previous tab
        #   ALT+K - select tab using mnemonic (K = underlined letter)
        nb.enable_traversal()
        nb.bind("<<NotebookTabChanged>>", self._on_tab_changed)
        nb.pack(fill='both', expand='y', padx=2, pady=3)
        self._create_descrip_tab(nb)
        self._create_treeview_tab(nb)
        self._create_text_tab(nb)

    def _create_descrip_tab(self, nb):
        # frame to hold contents
        frame = Frame(nb, name='descrip')

        # widgets to be displayed on 'Description' tab
        # position and set resize behaviour

        frame.rowconfigure(1, weight=1)
        frame.columnconfigure((0, 1), weight=1, uniform=1)
        lf = LabelFrame(frame, text='Animals')
        lf.pack(pady=2, side='left', fill='y')
        themes = [
            'cat', 'dog', 'horse', 'elephant', 'crocodile', 'bat',
            'grouse\nextra line made longer'
        ]
        self.ttkbut = []
        for t in themes:
            b = Button(lf, text=t)
            b.pack(pady=2)
            self.ttkbut.append(b)

        lF2 = LabelFrame(frame, text="Theme Combobox")
        lF2.pack(anchor='nw')
        themes = list(sorted(self.style.get_themes()))
        themes.insert(0, "Pick a theme")
        self.cb = cb = Combobox(lF2,
                                values=themes,
                                state="readonly",
                                height=10)
        cb.set(themes[0])
        cb.bind('<<ComboboxSelected>>', self.change_style)
        cb.grid(row=0, column=0, sticky='nw', pady=5)

        lF3 = LabelFrame(frame, text="Entry")
        lF3.pack(anchor='ne')
        self.en = Entry(lF3)
        self.en.grid(row=0, column=0, sticky='ew', pady=5, padx=5)

        lf1 = LabelFrame(frame, text='Checkbuttons')
        lf1.pack(pady=2, side='left', fill='y')

        # control variables
        self.enabled = IntVar()
        self.cheese = IntVar()
        self.tomato = IntVar()
        self.basil = IntVar()
        self.oregano = IntVar()
        # checkbuttons
        self.cbOpt = Checkbutton(lf1,
                                 text='Enabled',
                                 variable=self.enabled,
                                 command=self._toggle_opt)
        cbCheese = Checkbutton(text='Cheese',
                               variable=self.cheese,
                               command=self._show_vars)
        cbTomato = Checkbutton(text='Tomato',
                               variable=self.tomato,
                               command=self._show_vars)
        sep1 = Separator(orient='h')
        cbBasil = Checkbutton(text='Basil',
                              variable=self.basil,
                              command=self._show_vars)
        cbOregano = Checkbutton(text='Oregano',
                                variable=self.oregano,
                                command=self._show_vars)
        sep2 = Separator(orient='h')

        self.cbs = [
            self.cbOpt, sep1, cbCheese, cbTomato, sep2, cbBasil, cbOregano
        ]
        for opt in self.cbs:
            if opt.winfo_class() == 'TCheckbutton':
                opt.configure(onvalue=1, offvalue=0)
                opt.setvar(opt.cget('variable'), 0)

            opt.pack(in_=lf1,
                     side='top',
                     fill='x',
                     pady=2,
                     padx=5,
                     anchor='nw')

        lf2 = LabelFrame(frame, text='Radiobuttons', labelanchor='n')
        lf2.pack(pady=2, side='left', fill='y')

        self.rb = []
        self.happiness = StringVar()
        for s in ['Great', 'Good', 'OK', 'Poor', 'Awful']:
            b = Radiobutton(lf2,
                            text=s,
                            value=s,
                            variable=self.happiness,
                            command=lambda s=s: self._show_vars())
            b.pack(anchor='nw', side='top', fill='x', pady=2)
            self.rb.append(b)

        right = LabelFrame(frame, text='Control Variables')
        right.pack(pady=2, side='left', fill='y')

        self.vb0 = Label(right, font=('Courier', 10))
        self.vb1 = Label(right, font=('Courier', 10))
        self.vb2 = Label(right, font=('Courier', 10))
        self.vb3 = Label(right, font=('Courier', 10))
        self.vb4 = Label(right, font=('Courier', 10))
        self.vb5 = Label(right, font=('Courier', 10))

        self.vb0.pack(anchor='nw', pady=3)
        self.vb1.pack(anchor='nw', pady=3)
        self.vb2.pack(anchor='nw', pady=3)
        self.vb3.pack(anchor='nw', pady=3)
        self.vb4.pack(anchor='nw', pady=3)
        self.vb5.pack(anchor='nw', pady=3)

        self._show_vars()
        # add to notebook (underline = index for short-cut character)
        nb.add(frame, text='Description', underline=0, padding=2)

    # =========================================================================
    def _create_treeview_tab(self, nb):
        # Populate the second pane. Note that the content doesn't really matter
        # tree = None
        self.backg = ["white", '#f0f0ff']
        tree_columns = ("country", "capital", "currency")
        tree_data = [("Argentina", "Buenos Aires", "ARS"),
                     ("Australia", "Canberra", "AUD"),
                     ("Brazil", "Brazilia", "BRL"),
                     ("Canada", "Ottawa", "CAD"), ("China", "Beijing", "CNY"),
                     ("France", "Paris", "EUR"), ("Germany", "Berlin", "EUR"),
                     ("India", "New Delhi", "INR"), ("Italy", "Rome", "EUR"),
                     ("Japan", "Tokyo", "JPY"),
                     ("Mexico", "Mexico City", "MXN"),
                     ("Russia", "Moscow", "RUB"),
                     ("South Africa", "Pretoria", "ZAR"),
                     ("United Kingdom", "London", "GBP"),
                     ("United States", "Washington, D.C.", "USD")]

        #test_length = font.Font(family="Times", size=12, weight="bold").measure('Test')
        #fact = int(test_length / 30 * 20.45) # 30 is the length of Test in Idle
        fact = font.Font(font="TkDefaultFont").metrics('linespace')

        self.st0.configure('fact.Treeview',
                           rowheight=fact,
                           font=font.nametofont("TkDefaultFont"))

        container = Frame(nb)
        container.grid(sticky='nsew')  #(fill='both', expand=True)
        self.tree = Treeview(container,
                             columns=tree_columns,
                             show="headings",
                             style='fact.Treeview')
        vsb = Scrollbar(container, orient="vertical", command=self.tree.yview)
        hsb = Scrollbar(container,
                        orient="horizontal",
                        command=self.tree.xview)
        self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)
        self.tree.grid(column=0, row=0, sticky='nsew', in_=container)
        vsb.grid(column=1, row=0, sticky='ns', in_=container)
        hsb.grid(column=0, row=1, sticky='ew', in_=container)

        container.grid_columnconfigure(0, weight=1)
        container.grid_rowconfigure(0, weight=1)

        for col in tree_columns:
            self.tree.heading(
                col,
                text=col.title(),
                command=lambda c=col: self.sortby(self.tree, c, 0))
            # XXX tkFont.Font().measure expected args are incorrect according
            #     to the Tk docs
            self.tree.column(col,
                             width=Font().measure(col.title()),
                             stretch=False)

        for ix, item in enumerate(tree_data):
            itemID = self.tree.insert('', 'end', values=item)
            self.tree.item(itemID, tags=itemID)
            self.tree.tag_configure(itemID, background=self.backg[ix % 2])

            # adjust columns lengths if necessary
            for indx, val in enumerate(item):
                ilen = Font().measure(val)
                if self.tree.column(tree_columns[indx], width=None) < ilen:
                    self.tree.column(tree_columns[indx], width=ilen)

        sg = Sizegrip(container)
        sg.grid(sticky='e')

        nb.add(container, text='Treeview', underline=0, padding=2)

    # =========================================================================
    def _create_text_tab(self, nb):
        # populate the third frame with other widgets
        self.pw = PanedWindow(nb, name='pw')
        self.pw.pack(fill='both', expand=True)

        lF = LabelFrame(self.pw, text="Slider")
        fr1 = Frame(lF)
        fr1.grid(row=0, column=0)
        from_ = -5
        to = 105
        value = 19
        step = 11
        fontSize = 9
        scvar = IntVar()
        #scRange=self.any_number_range(from_,to,step)
        #scLen = len(scRange[1]) * (fontSize + 10)

        self.sc = TtkScale(fr1,
                           from_=from_,
                           to=to,
                           variable=scvar,
                           orient='vertical',
                           length=200,
                           showvalue=True,
                           command=lambda s: scvar.set('%d' % float(s)),
                           tickinterval=5,
                           resolution=5)
        #self.sc = Scale(fr1, from_=from_, to=to, variable=scvar,
        #orient='vertical',length=scLen,
        #command=lambda s: scvar.set('%d' % float(s) ))
        self.sc.set(value)
        #l1 = Label(fr1,textvariable=scvar,width=5)
        l1 = Spinbox(fr1, from_=from_, to=to, textvariable=scvar, width=4)
        l1.grid(row=0, column=0, pady=2)
        self.sc.grid(row=0, column=1, pady=5, padx=40)
        fr = Frame(fr1)
        fr.grid(row=0, column=2)
        #for ix,sR in enumerate(scRange[1]):
        #lb = Label(fr, text=sR, font=('Courier New', str(fontSize)))
        #lb.grid(row=ix, column=1)

        schvar = IntVar()
        a = -5
        b = 105
        #schRange = self.any_number_range(a,b,s=11)
        #schLen = Font().measure(schRange[0])
        self.sch = TtkScale(lF,
                            from_=a,
                            to=b,
                            length=200,
                            variable=schvar,
                            orient='horizontal',
                            showvalue=True,
                            command=lambda s: schvar.set('%d' % float(s)),
                            tickinterval=5,
                            resolution=5)
        #self.sch = Scale(lF, from_=a, to=b, length=schLen, variable=schvar,
        #orient='horizontal',
        #command=lambda s: schvar.set('%d' % float(s) ))
        self.sch.set(23)
        #l2 = Label(lF,textvariable=schvar)
        l2 = Spinbox(lF, from_=a, to=b, textvariable=schvar, width=4)
        l2.grid(row=1, column=1, pady=2)
        self.sch.grid(row=2, column=1, pady=40, padx=5, sticky='nw')
        #l3 = Label(lF,text=schRange[0], font=('Courier New', str(fontSize)))
        #l3.grid(row=3,column=1,pady=2)
        self.sch.bind("<ButtonRelease-1>", self.show_x)
        self.pw.add(lF)

        lF1 = LabelFrame(self.pw, text="Progress", name='lf')
        pb1var = IntVar()
        pb2var = IntVar()
        self.pbar = Progressbar(lF1,
                                variable=pb1var,
                                length=150,
                                mode="indeterminate",
                                name='pb1',
                                orient='horizontal')
        self.pb2 = Progressbar(lF1,
                               variable=pb2var,
                               mode='indeterminate',
                               name='pb2',
                               orient='vertical')
        self.pbar["value"] = 25
        self.pbar.grid(row=1, column=0, padx=5, pady=5, sticky='nw')
        self.pb2.grid(row=1, column=1, padx=5, pady=5, sticky='nw')
        l3 = Label(lF1, textvariable=pb1var)
        l3.grid(row=0, column=0, pady=2, sticky='nw')
        l4 = Label(lF1, textvariable=pb2var)
        l4.grid(row=0, column=1, pady=2, sticky='nw')
        start = Button(lF1,
                       text='Start Progress',
                       command=lambda: self._do_bars('start'))
        stop = Button(lF1,
                      text='Stop Progress',
                      command=lambda: self._do_bars('stop'))
        start.grid(row=2, column=0, padx=5, pady=5, sticky='nw')
        stop.grid(row=3, column=0, padx=5, pady=5, sticky='nw')
        self.pw.add(lF1)

        # add to notebook (underline = index for short-cut character)
        nb.add(self.pw, text='Sliders & Others', underline=0)

    #=========================================================================
    def _toggle_opt(self):
        # state of the option buttons controlled
        # by the state of the Option frame label widget
        if self.enabled.get() == 1:
            self.sc.state(['!disabled'])
            self.sch.state(['!disabled'])
            self.cb.state(['!disabled'])
            self.en.state(['!disabled'])
            self.pbar.state(['!disabled'])
            self.pb2.state(['!disabled'])
        else:
            self.sc.state(['disabled'])
            self.sch.state(['disabled'])
            self.cb.state(['disabled'])
            self.en.state(['disabled'])
            self.pbar.state(['disabled'])
            self.pb2.state(['disabled'])

        for opt in self.allBtns:
            if opt.winfo_class() != 'TSeparator':
                if self.cbOpt.instate(('selected', )):
                    opt['state'] = '!disabled'  # enable option
                    self.nb.tab(1, state='normal')
                else:
                    opt['state'] = 'disabled'
                    self.nb.tab(1, state='disabled')
        self._show_vars()

    def _show_vars(self):
        # set text for labels in var_panel to include the control
        # variable name and current variable value
        self.vb0['text'] = '{:<11} {:<8}'.format('enabled:',
                                                 self.enabled.get())
        self.vb1['text'] = '{:<11} {:<8}'.format('cheese:', self.cheese.get())
        self.vb2['text'] = '{:<11} {:<8}'.format('tomato:', self.tomato.get())
        self.vb3['text'] = '{:<11} {:<8}'.format('basil:', self.basil.get())
        self.vb4['text'] = '{:<11} {:<8}'.format('oregano:',
                                                 self.oregano.get())
        self.vb5['text'] = '{:<11} {:<8}'.format('happiness:',
                                                 self.happiness.get())

    def sortby(self, tree, col, descending):
        """Sort tree contents when a column is clicked on."""
        # grab values to sort
        data = [(tree.set(child, col), child)
                for child in tree.get_children('')]

        # reorder data
        data.sort(reverse=descending)
        for indx, item in enumerate(data):
            tree.move(item[1], '', indx)

        # switch the heading so that it will sort in the opposite direction
        tree.heading(col,
                     command=lambda col=col: self.sortby(
                         tree, col, int(not descending)))
        # reconfigure tags after ordering
        list_of_items = tree.get_children('')
        for i in range(len(list_of_items)):
            tree.tag_configure(list_of_items[i], background=self.backg[i % 2])

    def any_number_range(self, a, b, s=1):
        """ Generate consecutive values list between two numbers with optional
        step (default=1)."""
        if (a == b):
            return a
        else:
            mx = max(a, b)
            mn = min(a, b)
            result = []
            output = ''
            # inclusive upper limit. If not needed, delete '+1' in the line
            #below
            while (mn < mx + 1):
                # if step is positive we go from min to max
                if s > 0:
                    result.append(mn)
                    mn += s
                # if step is negative we go from max to min
                if s < 0:
                    result.append(mx)
                    mx += s
                # val
            maxLen = 0
            output = ""
            for ix, res in enumerate(result[:-1]):  # last value ignored
                if len(str(res)) > maxLen:
                    maxLen = len(str(res))
            if maxLen == 1:
                # converts list to string
                output = ' '.join(str(i) for i in result)
            else:
                for ix, res in enumerate(result):
                    if maxLen == 2:
                        if len(str(res)) == 1:
                            output = output + str(res) + " " * maxLen
                        elif len(str(res)) == 2:
                            output = output + str(res) + " "
                        else:
                            output = output + str(res)

            return output, result

    def _do_bars(self, op):
        pbar = self.pbar.nametowidget('.fr.demo.nb.pw.lf.pb1')
        pb2 = self.pb2.nametowidget('.fr.demo.nb.pw.lf.pb2')

        if op == 'start':
            pbar.start()
            pb2.start()
        else:
            pbar.stop()
            pb2.stop()

    def change_style(self, event=None):
        """set the Style to the content of the Combobox"""
        content = self.cb.get()
        try:
            self.style.theme_use(content)
            fact = font.Font(font="TkDefaultFont").metrics('linespace')
            self.st0.configure('font.Treeview',
                               rowheight=fact,
                               font=font.nametofont("TkDefaultFont"))
        except TclError as err:
            messagebox.showerror('Error', err)
        else:
            root.title(content)

    def change_theme(self, theme):
        window = ttktheme.ThemedTk()
        window.set_theme(theme)
        root.title(theme)

    def _on_tab_changed(self, event):
        event.widget.update_idletasks()

        tab = event.widget.nametowidget(event.widget.select())
        event.widget.configure(height=tab.winfo_reqheight(),
                               width=tab.winfo_reqwidth())
Esempio n. 13
0
    def __init__(self, master, a_copier, a_supp, a_supp_avant_cp, original,
                 sauvegarde):
        Toplevel.__init__(self, master)
        self.geometry("%ix%i" %
                      (self.winfo_screenwidth(), self.winfo_screenheight()))
        self.rowconfigure(1, weight=1)
        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)
        self.title("Confirmation")

        self.a_copier = a_copier
        self.a_supp = a_supp
        self.a_supp_avant_cp = a_supp_avant_cp

        h = max(len(a_supp), len(a_copier))

        style = Style(self)
        style.configure("text.TFrame", background="white", relief="sunken")

        Label(self,
              text="Synchronisation de %s vers %s" %
              (original, sauvegarde)).grid(row=0,
                                           columnspan=2,
                                           padx=10,
                                           pady=10)
        paned = PanedWindow(self, orient='horizontal')
        paned.grid(row=1, columnspan=2, sticky="eswn", padx=(10, 4), pady=4)
        paned.columnconfigure(0, weight=1)
        paned.columnconfigure(1, weight=1)
        paned.rowconfigure(1, weight=1)
        frame_copie = Frame(paned)
        frame_copie.columnconfigure(0, weight=1)
        frame_copie.rowconfigure(1, weight=1)
        paned.add(frame_copie, weight=1)
        Label(frame_copie, text="À copier :").grid(row=0,
                                                   columnspan=2,
                                                   padx=(10, 4),
                                                   pady=4)
        f_copie = Frame(frame_copie, style="text.TFrame", borderwidth=1)
        f_copie.columnconfigure(0, weight=1)
        f_copie.rowconfigure(0, weight=1)
        f_copie.grid(row=1, column=0, sticky="ewsn")
        txt_copie = Text(f_copie,
                         height=h,
                         wrap="none",
                         highlightthickness=0,
                         relief="flat")
        txt_copie.grid(row=0, column=0, sticky="eswn")
        scrollx_copie = Scrollbar(frame_copie,
                                  orient="horizontal",
                                  command=txt_copie.xview)
        scrolly_copie = Scrollbar(frame_copie,
                                  orient="vertical",
                                  command=txt_copie.yview)
        scrollx_copie.grid(row=2, column=0, sticky="ew")
        scrolly_copie.grid(row=1, column=1, sticky="ns")
        txt_copie.configure(yscrollcommand=scrolly_copie.set,
                            xscrollcommand=scrollx_copie.set)
        txt_copie.insert("1.0", "\n".join(a_copier))
        txt_copie.configure(state="disabled")

        frame_supp = Frame(paned)
        frame_supp.columnconfigure(0, weight=1)
        frame_supp.rowconfigure(1, weight=1)
        paned.add(frame_supp, weight=1)
        Label(frame_supp, text="À supprimer :").grid(row=0,
                                                     columnspan=2,
                                                     padx=(4, 10),
                                                     pady=4)
        f_supp = Frame(frame_supp, style="text.TFrame", borderwidth=1)
        f_supp.columnconfigure(0, weight=1)
        f_supp.rowconfigure(0, weight=1)
        f_supp.grid(row=1, column=0, sticky="ewsn")
        txt_supp = Text(f_supp,
                        height=h,
                        wrap="none",
                        highlightthickness=0,
                        relief="flat")
        txt_supp.grid(row=0, column=0, sticky="eswn")
        scrollx_supp = Scrollbar(frame_supp,
                                 orient="horizontal",
                                 command=txt_supp.xview)
        scrolly_supp = Scrollbar(frame_supp,
                                 orient="vertical",
                                 command=txt_supp.yview)
        scrollx_supp.grid(row=2, column=0, sticky="ew")
        scrolly_supp.grid(row=1, column=1, sticky="ns")
        txt_supp.configure(yscrollcommand=scrolly_supp.set,
                           xscrollcommand=scrollx_supp.set)
        txt_supp.insert("1.0", "\n".join(a_supp))
        txt_supp.configure(state="disabled")

        Button(self, command=self.ok, text="Ok").grid(row=3,
                                                      column=0,
                                                      sticky="e",
                                                      padx=(10, 4),
                                                      pady=(4, 10))
        Button(self, text="Annuler", command=self.destroy).grid(row=3,
                                                                column=1,
                                                                sticky="w",
                                                                padx=(4, 10),
                                                                pady=(4, 10))
        self.grab_set()
Esempio n. 14
-2
    def __init__(self, title):
        root = Tk()
        root.title(title)
        root.focus_set()
        root.rowconfigure(0, weight=0)
        root.columnconfigure(0, weight=1)
        root.rowconfigure(1, weight=1)
        self._root = root

        self.menubar = Frame(root)
        self.menubar.grid(row=0, column=0, sticky=(W, E))
        self.menubar['takefocus'] = False

        quit_button = Button(self.menubar, text='Quit', command=self.quit)
        quit_button.grid(row=0, column=0)

        self._menucolumn = 1
        self.views = list()

        self.paned_win = PanedWindow(root, orient=HORIZONTAL)
        self.paned_win.grid(row=1, column=0, sticky=(N, S, W, E))

        self._query = None
        self._accept_func = None

        self.sidebar_views = dict()
        self.sidebar_count = 0
        self.sidebar = PanedWindow(self.paned_win)
        self.paned_win.add(self.sidebar, weight=1)
        
        self.tabs = Notebook(self.paned_win)
        self.tabs.enable_traversal()
        self.paned_win.add(self.tabs, weight=5)
        self.root = self.tabs