예제 #1
0
class KRCCModule:
  __metaclass__ = ABCMeta

  def __init__(self):
    self._terminate = BooleanVar(False)
    self._id = StringVar(False)

  @property
  def terminate(self):
    return self._terminate.get()

  @terminate.setter
  def terminate(self, value):
    self._terminate.set(value)

  @property
  def id(self):
    return self._id.get()

  @id.setter
  def id(self, value):
    self._id.set(value)

  @abstractproperty
  def name(self):
    pass

  @abstractmethod
  def run(self):
    pass
예제 #2
0
 def test_invalid_value_domain(self):
     false = 0 if self.root.wantobjects() else "0"
     v = BooleanVar(self.root, name="name")
     with self.assertRaises(TclError):
         v.set("value")
     self.assertEqual(self.root.globalgetvar("name"), false)
     self.root.globalsetvar("name", "value")
     with self.assertRaises(ValueError):
         v.get()
     self.root.globalsetvar("name", "1.0")
     with self.assertRaises(ValueError):
         v.get()
예제 #3
0
 def test_set(self):
     true = 1 if self.root.wantobjects() else "1"
     false = 0 if self.root.wantobjects() else "0"
     v = BooleanVar(self.root, name="name")
     v.set(True)
     self.assertEqual(self.root.globalgetvar("name"), true)
     v.set("0")
     self.assertEqual(self.root.globalgetvar("name"), false)
     v.set(42)
     self.assertEqual(self.root.globalgetvar("name"), true)
     v.set(0)
     self.assertEqual(self.root.globalgetvar("name"), false)
     v.set("on")
     self.assertEqual(self.root.globalgetvar("name"), true)
예제 #4
0
class Preferences(Frame):
    def __init__(self, client):
        # Basic setup
        super(Preferences, self).__init__()
        self.client = client

        # Setup the variables used
        self.echo_input = BooleanVar()
        self.echo_input.set(self.client.config['UI'].getboolean('echo_input'))
        self.echo_input.trace("w", self.echo_handler)
        self.logging = BooleanVar()
        self.logging.set(self.client.config['logging'].getboolean('log_session'))
        self.logging.trace('w', self.logging_handler)
        self.log_dir = self.client.config['logging']['log_directory']

        # Build the actual window and widgets
        prefs = Toplevel(self)
        prefs.wm_title("Preferences")
        echo_input_label = Label(prefs, text="Echo Input:")
        logging_label = Label(prefs, text='Log to file:')
        echo_checkbox = Checkbutton(prefs, variable=self.echo_input)
        logging_checkbox = Checkbutton(prefs, variable=self.logging)
        logging_button_text = 'Choose file...' if self.log_dir == "" else self.log_dir
        logging_button = Button(prefs, text=logging_button_text, command=self.logging_pick_location)

        # Pack 'em in.
        echo_input_label.grid(row=0, column=0)
        echo_checkbox.grid(row=0, column=1)
        logging_label.grid(row=1, column=0)
        logging_checkbox.grid(row=1, column=1)
        logging_button.grid(row=1, column=2)

    def logging_pick_location(self):
        location = askdirectory(initialdir="%UserProfile%\Documents\\")
        self.client.config['logging']['log_directory'] = location
        self.write_config()

    def echo_handler(self, arg1, arg2, mode):
        pprint(self.echo_input.get())
        self.client.config['UI']['echo_input'] = 'yes' if self.echo_input.get() else 'no'
        self.write_config()

    def logging_handler(self, arg1, arg2, mode):
        self.client.config['logging']['log_session'] = 'yes' if self.logging.get else 'no'
        self.write_config()

    def write_config(self, file='config.ini'):
        self.client.config.write(open(file, 'w'))
예제 #5
0
파일: plastey.py 프로젝트: esilotesham/vr
class Plastey(Tk):

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def __init__(self, *args, **kwargs):
        Tk.__init__(self, *args, **kwargs)

        # Set window title
        self.wm_title('Plastey Configurator')

        # Create GUI driven variables
        self._mode = BooleanVar()
        self._base = BooleanVar()
        self._comm = BooleanVar()
        self._pass = StringVar()
        self._addressed = StringVar()
        self._connected = StringVar()
        self._this_host = StringVar()
        self._this_port = StringVar()
        self._other_host = StringVar()
        self._other_port = StringVar()

        # Create GUI
        self._build_gui()

        # Set default values for GUI driven variables
        self._mode.set(MODE_SINGLE_PLAYER)
        self._base.set(BASE_OPENED_GEOMETRY)
        self._comm.set(COMM_SOCKET_SERVER)
        self._pass.set('')
        self._addressed.set(
            ADDR_HAVE_ADDRESS if check(COMM_THIS_HOST) else ADDR_NO_ADDRESS)
        self._connected.set(CONN_NOT_CONNECTED)
        self._this_host.set(COMM_THIS_HOST)
        self._this_port.set(COMM_THIS_PORT)
        self._other_host.set(COMM_THIS_HOST)
        self._other_port.set(COMM_OTHER_PORT)

        # Follow changes on password
        self._pass.trace('w', self._on_bind_address)

        # Create folder structures if they don't exists yet
        makedirs(FILE_TEMPORARY_FOLDER, exist_ok=True)
        makedirs(FILE_PERMANENT_FOLDER, exist_ok=True)
        makedirs(FILE_TEMP_SAVE_FOLDER, exist_ok=True)
        makedirs(FILE_AUTO_SAVE_FOLDER, exist_ok=True)
        #makedirs(FILE_TEMP_STATE_FOLDER, exist_ok=True)
        #makedirs(FILE_TEMP_FEEDS_FOLDER, exist_ok=True)

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _build_gui(self):
        # Create GUI sections
        row = 0
        col = 0

        # Warning text
        Label(master=self, text=WARN_TEXT, anchor=WEST,
              justify=CENTER).grid(row=row,
                                   column=col,
                                   sticky=NORTH_WEST,
                                   rowspan=16)

        # Set column spacing
        self.columnconfigure(index=col, pad=GUI_SECTION_PAD_X)
        row = 0
        col += 1

        # Game mode options
        Label(master=self, text='Game Mode:').grid(row=row,
                                                   column=col,
                                                   sticky=WEST)
        row += 1
        Radiobutton(master=self,
                    text='Single Player',
                    value=MODE_SINGLE_PLAYER,
                    variable=self._mode).grid(row=row, column=col, sticky=WEST)
        row += 1
        Radiobutton(master=self,
                    text='Multi Player',
                    value=MODE_MULTI_PLAYER,
                    variable=self._mode).grid(row=row, column=col, sticky=WEST)
        row += 1

        # Base object modes
        Label(master=self, text='Base Object:').grid(row=row,
                                                     column=col,
                                                     sticky=WEST)
        row += 1
        Radiobutton(master=self,
                    text='Plane mesh',
                    value=BASE_OPENED_GEOMETRY,
                    variable=self._base).grid(row=row, column=col, sticky=WEST)
        row += 1
        Radiobutton(master=self,
                    text='Sphere mesh',
                    value=BASE_CLOSED_GEOMETRY,
                    variable=self._base).grid(row=row, column=col, sticky=WEST)
        row += 1

        # Start oculus-daemon
        Label(master=self, text='Daemons:').grid(row=row,
                                                 column=col,
                                                 sticky=WEST)
        row += 1
        Button(master=self,
               text='Start OVRD',
               command=self._on_start_oculus_daemon).grid(row=row,
                                                          column=col,
                                                          sticky=WEST)

        # Set column spacing
        self.columnconfigure(index=col, pad=GUI_SECTION_PAD_X)
        row = 0
        col += 1

        # Multiplayer mode options
        Label(master=self, text='Multi Player Options:').grid(row=row,
                                                              column=col,
                                                              sticky=WEST,
                                                              columnspan=2)
        row += 1

        Label(master=self, text='This role:').grid(row=row,
                                                   column=col,
                                                   sticky=WEST)
        Radiobutton(master=self,
                    text='Server',
                    value=COMM_SOCKET_SERVER,
                    variable=self._comm).grid(row=row,
                                              column=col + 1,
                                              sticky=WEST)
        row += 1
        Radiobutton(master=self,
                    text='Client',
                    value=COMM_SOCKET_CLIENT,
                    variable=self._comm).grid(row=row,
                                              column=col + 1,
                                              sticky=WEST)
        row += 1

        Label(master=self, text='This host:').grid(row=row,
                                                   column=col,
                                                   sticky=WEST)
        Entry(master=self, textvariable=self._this_host).grid(row=row,
                                                              column=col + 1,
                                                              sticky=WEST)
        row += 1
        Label(master=self, text='This port:').grid(row=row,
                                                   column=col,
                                                   sticky=WEST)
        Entry(master=self, textvariable=self._this_port).grid(row=row,
                                                              column=col + 1,
                                                              sticky=WEST)
        row += 1

        Label(master=self, text='Other host:').grid(row=row,
                                                    column=col,
                                                    sticky=WEST)
        Entry(master=self, textvariable=self._other_host).grid(row=row,
                                                               column=col + 1,
                                                               sticky=WEST)
        row += 1
        Label(master=self, text='Other port:').grid(row=row,
                                                    column=col,
                                                    sticky=WEST)
        Entry(master=self, textvariable=self._other_port).grid(row=row,
                                                               column=col + 1,
                                                               sticky=WEST)
        row += 1

        Button(master=self, text='Bind address',
               command=self._on_ask_password).grid(row=row,
                                                   column=col,
                                                   sticky=WEST + EAST)
        Label(master=self, textvariable=self._addressed).grid(row=row,
                                                              column=col + 1,
                                                              sticky=WEST)
        row += 1
        Button(master=self,
               text='Connect machines',
               command=self._on_bind_address).grid(row=row,
                                                   column=col,
                                                   sticky=WEST + EAST)
        Label(master=self, textvariable=self._connected).grid(row=row,
                                                              column=col + 1,
                                                              sticky=WEST)

        # Set column spacing
        self.columnconfigure(index=col + 1, pad=GUI_SECTION_PAD_X)
        row = 0
        col += 2

        # Controller buttons
        Label(master=self, text='Controllers:').grid(row=row,
                                                     column=col,
                                                     sticky=WEST)
        row += 1
        Button(master=self, text='Start game',
               command=self._on_start_game).grid(row=row,
                                                 column=col,
                                                 sticky=WEST + EAST)
        row += 1
        Button(master=self, text='Restart game',
               command=self._on_restart_game).grid(row=row,
                                                   column=col,
                                                   sticky=WEST + EAST)
        row += 1
        Button(master=self, text='Stop game',
               command=self._on_stop_game).grid(row=row,
                                                column=col,
                                                sticky=WEST + EAST)
        row += 1
        Button(master=self, text='Save last mesh',
               command=self._on_save_mesh).grid(row=row,
                                                column=col,
                                                sticky=WEST + EAST)
        row += 1
        Button(master=self, text='Load last mesh',
               command=self._on_load_mesh).grid(row=row,
                                                column=col,
                                                sticky=WEST + EAST)
        row += 1
        Button(master=self, text='Save log file',
               command=self._on_save_log).grid(row=row,
                                               column=col,
                                               sticky=WEST + EAST)
        row += 1

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_ask_password(self, *args, **kwargs):
        # Create a password-dialog
        self._dialog = Password(self._pass)

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_start_oculus_daemon(self, *args, **kwargs):
        print('starting daemon...')

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_bind_address(self, *args, **kwargs):
        # Check for status and if address is not bound
        if not check(COMM_THIS_HOST):
            # Bind address
            try:
                setup(self._this_host, user_pass=self._pass.get())
            except CommunicationSetupError as exception:
                Report(exception.error)
            # Check status and report to user
            self._addressed.set(ADDR_HAVE_ADDRESS
                                if check(COMM_THIS_HOST) else ADDR_NO_ADDRESS)

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_connect(self, *args, **kwargs):
        pass

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_start_game(self, *args, **kwargs):
        # HACK: Is this really the best option we have, to get into fullscreen,
        #       other than using the blender's fullscreen option, which will
        #       unfortunately resize the display's resolution??? :(
        window_command = ['sleep 1']
        window_command.append('wmctrl -r :ACTIVE: '
                              '-e 0,{},{},{},{}'.format(
                                  DRAW_DISPLAY_X, DRAW_DISPLAY_Y,
                                  DRAW_RESOLUTION_X, DRAW_RESOLUTION_Y))
        if DRAW_FULL_SCREEN:
            window_command.append('wmctrl -r :ACTIVE: -b add,fullscreen')

        Popen(args=' && '.join(window_command),
              shell=True,
              stdin=PIPE,
              stderr=PIPE,
              universal_newlines=True)

        # Store subprocess, for further communication
        self._pipe = Popen(args='./plastey',
                           stdin=PIPE,
                           stdout=PIPE,
                           stderr=PIPE,
                           universal_newlines=True)

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_restart_game(self, *args, **kwargs):
        self._pipe.stdin.write('hello-world\n')
        #if not self._locked:
        #    self._locked = True
        #    with open(FILE_STATE_RESTART, mode='w') as file:
        #        file.write('')
        #    Thread(name   = 'feedbackd-restart',
        #           target = self._get_feedback_to_clean_up).start()

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_stop_game(self, *args, **kwargs):
        #if not self._locked:
        #    self._locked = True
        #    with open(FILE_STATE_SHUT_DOWN, mode='w') as file:
        #        file.write('')
        #    Thread(name   = 'feedbackd-shutdown',
        #           target = self._get_feedback_to_clean_up).start()
        self._pipe.communicate('hello-world\n')

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_save_mesh(self, *args, **kwargs):
        pass
        #if self._pipe.poll():
        #    print('saving inside game')
        #else:
        #    print('save last auto-saved')

        #print('parent says: hey there, daemon!\n')
        #self._pipe.stdin.write('hey there, daemon!\n')

        #self._pipe.stdin.close()
        #try:
        #    self._pipe.communicate('hey there, daemon!\n', timeout=0.1)
        ## Hack: since communicate waits for the subprocess to terminate, the
        ##       timeout value is necessary, however, after the timeout, the app
        ##       won't terminate either. One solution should be
        ##       self._pipe.stdin.write instead of the communicate method, but
        ##       unfortunately the process's stdin.read/input are not getting
        ##       anything.. is it because the value set to shell=True?
        #except TimeoutExpired:
        #    return

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_load_mesh(self, *args, **kwargs):
        pass

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_save_log(self, *args, **kwargs):
        pass

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def run(self):
        self.mainloop()
예제 #6
0
파일: gui.py 프로젝트: Sidnoea/pokeBridge
def overwriteWindow(root):
    '''Creates the window for deciding to overwrite or not.'''

    def toggle(*args):    
        setState(choice.get(), 'disabled', [gen2Label, gen3Label,
                                            gen2Button, gen3Button,
                                            gen2Entry, gen3Entry])
        setState(not choice.get(), 'disabled', [warningLabel])

        if not choice.get() and (gen2Text.get() == '' or gen3Text.get() == ''):
            navFrame.disable('next', True)
        else:
            navFrame.disable('next', False)

    def gen2Dialog():
        askSave = filedialog.asksaveasfilename
        file = askSave(title='Gen II Save File', initialdir=root.dir,
                       filetypes=[('GB Save', '.sav'), ('All Files', '.*')],
                       defaultextension='.sav')
        if file != '':
            gen2Text.set(file)
            gen2Entry.after_idle(gen2Entry.xview_moveto, 1)
            root.dir = getDir(file)

    def gen3Dialog():
        askSave = filedialog.asksaveasfilename
        file = askSave(title='Gen III Save File', initialdir=root.dir,
                       filetypes=[('GBA Save', '.sav'), ('All Files', '.*')],
                       defaultextension='.sav')
        if file != '':
            gen3Text.set(file)
            gen3Entry.after_idle(gen3Entry.xview_moveto, 1)
            root.dir = getDir(file)

    def nextPage():
        global newGen2, newGen3, oldGen2, oldGen3

        if choice.get():
            newGen2 = oldGen2
            newGen3 = oldGen3
        else:
            newGen2 = gen2Entry.get()
            newGen3 = gen3Entry.get()

        root.nextPage()

    baseFrame = ttk.Frame(root)
    baseFrame.rowconfigure(0, weight=1)
    baseFrame.columnconfigure(0, weight=1)
    
    
    mainFrame = ttk.Frame(baseFrame, padding=MAIN_PAD)
    mainFrame.grid(row=0, column=0, sticky='ns')
    mainFrame.rowconfigure(0, weight=2)
    mainFrame.rowconfigure(3, weight=1)

    instrText = 'Select whether to overwrite the original save files, or to create new save files.'
    instrLabel = ttk.Label(mainFrame, text=instrText)
    instrLabel.grid(row=0, column=0)


    choiceFrame = ttk.Frame(mainFrame)
    choiceFrame.grid(row=1, column=0)

    choice = BooleanVar(value=True)
    choice1Radio = ttk.Radiobutton(choiceFrame, text='Overwrite',
                                   variable=choice, command=toggle,
                                   value=True)
    choice1Radio.grid(row=0, column=0, pady=5, sticky='w')

    warningText = 'WARNING! Once new data is created, this program can not recover old save data.'
    warningLabel = ttk.Label(choiceFrame, text=warningText, wraplength=300)
    warningLabel.grid(row=1, column=0, pady=5)
    
    choice2Radio = ttk.Radiobutton(choiceFrame, text='Do not overwrite',
                                   variable=choice, command=toggle,
                                   value=False)
    choice2Radio.grid(row=2, column=0, pady=5, sticky='w')


    pickerFrame = ttk.Frame(mainFrame)
    pickerFrame.grid(row=2, column=0)

    gen2Label = ttk.Label(pickerFrame, text='New Gen II file:')
    gen2Label.grid(row=0, column=0, columnspan=2)
    
    gen2Button = ttk.Button(pickerFrame, text='To...', command=gen2Dialog)
    gen2Button.grid(row=1, column=0, sticky='e', padx=5, pady=5)

    gen2Text = StringVar(pickerFrame)
    gen2Text.trace('w', toggle)
    gen2Entry = ttk.Entry(pickerFrame, textvariable=gen2Text, state='readonly')
    gen2Entry.grid(row=1, column=1, sticky='w', padx=5, pady=5)

    gen3Label = ttk.Label(pickerFrame, text='New Gen III file:')
    gen3Label.grid(row=2, column=0, columnspan=2)
    
    gen3Button = ttk.Button(pickerFrame, text='To...', command=gen3Dialog)
    gen3Button.grid(row=3, column=0, sticky='e', padx=5, pady=5)

    gen3Text = StringVar(pickerFrame)
    gen3Text.trace('w', toggle)
    gen3Entry = ttk.Entry(pickerFrame, textvariable=gen3Text, state='readonly')
    gen3Entry.grid(row=3, column=1, sticky='w', padx=5, pady=5)
    #todo: make sure user doesn't put the same file for both entries


    fillerFrame = ttk.Frame(mainFrame)
    fillerFrame.grid(row=3, column=0, sticky='ns')


    navFrame = Nav(baseFrame, root.prevPage, nextPage)
    navFrame.grid(row=1, column=0, sticky='we')

    if debug:
        gen2Text.set('C:/Users/Sidnoea/Documents/GitHub/pokeBridge/New Gen 2.sav')
        gen3Text.set('C:/Users/Sidnoea/Documents/GitHub/pokeBridge/New Gen 3.sav')
        choice.set(False)

    toggle()

    return (baseFrame, 'Overwrite?', {'sticky':'nsew'})
예제 #7
0
class PortSelector(Frame):
    def __init__(self, root, parent):
        settings = parent.settings('port_selector')
        Frame.__init__(self, root, borderwidth=2, relief="groove", height=10)
        self.parent = parent
        self.autoconnect = BooleanVar()
        self.autoconnect.set(settings['autoconnect'])
        self.debug = BooleanVar()
        self.debug.set(settings['debug'])

        self.selected_port = StringVar(name='selected_port')

        port_select_label = Label(self, text="Port:", anchor="e", width=10)
        port_select_label.grid(row=0, column=0)
        self.port_select = ttk.Combobox(self,
                                        state="readonly",
                                        textvariable=self.selected_port,
                                        postcommand=self.update_portlist)
        self.update_portlist(settings['port'])
        self.port_select.bind('<<ComboboxSelected>>', self.port_changed)
        self.port_select.grid(row=0, column=1)

        self.port_connect = Button(self,
                                   text="Connect",
                                   command=self.connect,
                                   width=12)
        self.port_connect.grid(row=0, column=2)

        self.port_autoconnect = Checkbutton(self,
                                            variable=self.autoconnect,
                                            command=self.port_changed,
                                            text="Autoconnect")
        self.port_autoconnect.grid(row=1, column=1, columnspan=3, sticky="W")

        # self.port_debug = Checkbutton(self, variable=self.debug, command=self.port_changed,text="Debug")
        # self.port_debug.grid(row=1,column=2,columnspan=3,sticky="W")

        # self.port_descriptor_label = Label(self,text=" Desc:",anchor="e",width=10)
        # self.port_descriptor_label.grid(row=2,column=0)

        # self.port_descriptor = Label(self, text="-",justify="left")
        # self.port_descriptor.grid(row=2,column=1,columnspan=3,sticky="W")

        # linfo = Label(self,text='Info:',anchor="e",width=10)
        # linfo.grid(row=3,column=0,sticky="N")
        # self.info = Label(self,text='-',anchor="w",justify='left')
        # self.info.grid(row=3,column=1,columnspan=3,sticky="W")

        self.grid_columnconfigure(0, minsize=10)
        self.grid_columnconfigure(1, weight=1)
        self.grid_columnconfigure(2, pad=10)
        self.grid_rowconfigure(0, pad=10)

    def __call__(self):
        return {
            'port': self.port_select.get(),
            'autoconnect': self.autoconnect.get(),
            'debug': self.debug.get()
        }

    def update_portlist(self, port=None):
        self.ports = []
        ports = []
        if sys.platform.startswith('win'):
            for p in list_ports.comports():
                self.ports.append(p)
                ports.append(p.device)
        self.port_select['values'] = ports
        if port is None: return
        if port in ports:
            self.port_select.set(port)

    def port_changed(self, e=None):
        self.parent.settings('port_selector', self())

    def connect(self):
        if self.parent.console.connect(self.port_select.get()):
            self.connected()
        else:
            self.parent.console.disconnect()
            self.disconnected()

    def connected(self):
        self.port_connect['text'] = 'Disconnect'
        self.port_select['state'] = 'disabled'

    def disconnected(self):
        self.port_connect['text'] = 'Connect'
        self.port_select['state'] = 'readonly'
예제 #8
0
class RulesInput():
    """
    Class to manage gui and logic for entry fields of rules
    in Parameters frame
    """
    def __init__(self, parent_class):
        """
        Initialize parent_frame to the provided class to hold self.frame
        self.frame contains all the elements
        self.entries is a list of dynamically generated entries
        """
        self.parent_class = parent_class
        # frame in parent Parameters class
        self.frame = Frame(parent_class.frame)
        self.preview_canvas = None  # canvas to preview curve
        self.entries = []  # list of dictionaries, each dictionary
        # contains the keys for frame, and its children
        self.add_button = None
        self.sub_button = None
        self.radio_angle_var = BooleanVar(
            self.frame)  # initially set to radians
        self.radio_angle_var.set(True)
        self.init_preview_canvas()
        self.init_info_labels()
        self.init_add_entry_button()
        self.init_sub_entry_button()
        # self.init_extract_rules_button()
        self.frame.grid(row=7, column=0, columnspan=3, sticky='nw', pady=10)

    def create_entry_dictionary(self):
        """
        Creates and returns a dictionary which contains references
        to a frame and entries in it
        keys: ["frame", "ent_len", "ent_angle", "chk_is_flip",
        "chk_is_rev", "flip_state","reverse_state"]
        """
        vcmd = (self.frame.register(self.validate_float), '%P')
        entry_frame = Frame(self.frame)
        ent_length = Entry(entry_frame,
                           validate='key',
                           width=8,
                           validatecommand=vcmd)
        ent_angle = Entry(entry_frame,
                          validate='key',
                          width=8,
                          validatecommand=vcmd)
        is_reversed_state = BooleanVar(entry_frame)
        is_flipped_state = BooleanVar(entry_frame)
        chkbtn_is_reversed = Checkbutton(entry_frame,
                                         text='reverse',
                                         var=is_reversed_state)
        chkbtn_is_flipped = Checkbutton(entry_frame,
                                        text='flip',
                                        var=is_flipped_state)

        ent_angle.pack(side=LEFT)
        ent_length.pack(side=LEFT)
        chkbtn_is_flipped.pack(side=LEFT)
        chkbtn_is_reversed.pack(side=LEFT)
        entry_frame.grid(row=len(self.entries) + 3, columnspan=4)
        entry_dict = {
            "frame": entry_frame,
            "ent_len": ent_length,
            "ent_angle": ent_angle,
            "chk_is_flip": chkbtn_is_flipped,
            "chk_is_rev": chkbtn_is_reversed,
            "flip_state": is_flipped_state,
            "reverse_state": is_reversed_state
        }
        return entry_dict

    def init_add_entry_button(self):
        """
        Initialize the button which adds frames for entry of each rule
        """
        def add_entry():
            """
            create a new entry and add to self.entries
            """
            new_entry = self.create_entry_dictionary()
            self.entries.append(new_entry)
            self.render_preview()

        self.add_button = Button(self.frame, text='+', command=add_entry)
        self.add_button.grid(row=1, column=2)

    def init_sub_entry_button(self):
        """
        Initialize the button to remove entry fields
        """
        def sub_entry():
            """
            Pop and destroy the last entry from self.entries
            """
            if self.entries != []:
                self.entries.pop()["frame"].destroy()
            self.render_preview()

        self.sub_button = Button(self.frame, text='-', command=sub_entry)
        self.sub_button.grid(row=1, column=3)

    def validate_float(self, p_str):
        """
        Validate if input is a valid floating point number
        """
        # may validate only '[+-].' which needs to be handled later
        float_pattern = r"^[\+\-]?([0-9]*[.])?[0-9]*$"
        if re.search(float_pattern, p_str) or p_str == "":
            return True
        return False

    def extract_rules(self):
        """
        Extract rules from the input fields to a list
        """
        def get_float_value(entry_string):
            """
            Get the float value out of entry strings
            (function to handle corner cases)
            """
            if entry_string in ['', '.', '+.', '-.', '+', '-']:
                return 0.0
            return float(entry_string)

        extracted_rules = []
        for entry in self.entries:
            if self.radio_angle_var.get(
            ):  # if true, means radians, extract as is
                ent_angle = get_float_value(entry["ent_angle"].get())
            else:
                ent_angle = get_float_value(entry["ent_angle"].get(
                )) * RAD_FAC  # convert degree to radians
            ent_angle = ent_angle % (2 * PI)
            ent_len = get_float_value(entry["ent_len"].get())
            is_reversed = entry["reverse_state"].get()
            is_flipped = entry["flip_state"].get()
            if ent_angle or ent_len:
                # user entered something, otherwise nothing changed
                extracted_rules.append(
                    (ent_angle, ent_len, is_flipped, is_reversed))
        return extracted_rules

    def fill_entries_from_rules(self, rules):
        """
        Fill in the entries in GUI for user feedback
        """
        for rule in rules:
            angle, length, is_flipped, is_reversed = rule
            new_entry = self.create_entry_dictionary()
            # clear and insert angle
            new_entry['ent_angle'].delete(0, END)
            if self.radio_angle_var.get():  # if angle in radians
                new_entry['ent_angle'].insert(0, str(angle))
            else:
                new_entry['ent_angle'].insert(0, str(angle * DEG_FAC))
            # clear and insert length
            new_entry['ent_len'].delete(0, END)
            new_entry['ent_len'].insert(0, str(length))
            # set booleans
            new_entry['reverse_state'].set(is_reversed)
            new_entry['flip_state'].set(is_flipped)

            self.entries.append(new_entry)


#     def init_extract_rules_button(self):
#         """
#         Test button to check extracted rules
#         """
#         def print_extracted():
#             """
#             Print the extracted rules to stdout
#             """
#             print("Extracted:")
#             print(self.extract_rules())
#
#         self.test_button = Button(
#             self.frame, text="extract", command=print_extracted)
#         self.test_button.pack()

    def init_preview_canvas(self):
        """
        Canvas to draw the base curve from rules and give
        preview to the user
        """
        self.preview_canvas = Canvas(self.frame, width=200, height=200)
        self.preview_canvas.grid(row=0, columnspan=4, sticky=W)

    def form_base_curve(self, rules):
        """
        Form the base curve from extracted rules for previewing
        Resized to fit into the preview canvas
        """
        curve = [(0, 0)]
        for theta, scale_fac, _, _ in rules:
            last_x, last_y = curve[-1]
            curve.append((last_x + scale_fac * cos(theta),
                          last_y + scale_fac * sin(theta)))

        min_x = min(point[0] for point in curve)
        min_y = min(point[1] for point in curve)
        scale_y = max(point[1] - min_y for point in curve)
        scale_x = max(point[0] - min_x for point in curve)
        if scale_x == 0 or scale_y == 0:
            return curve
        canvas_width = self.preview_canvas.winfo_width()
        canvas_height = self.preview_canvas.winfo_height()
        to_scale = min(canvas_width / scale_x, canvas_height / scale_y) * 0.8
        curve = [((point[0] - min_x) * to_scale + canvas_width / 10,
                  (point[1] - min_y) * to_scale + canvas_height / 10)
                 for point in curve]
        return curve

    def render_preview(self):
        """
        Render the preview on canvas on calling the function
        Desired to be called by some update function
        """
        # Not the best way to do it but the curve size is of constant
        # order, <20 segments, so it wouldnt create much difference
        extracted_rules = self.extract_rules()
        self.set_rules_in_curve(extracted_rules)
        # set the rules in the parent curve dynamically
        curve = self.form_base_curve(extracted_rules)
        self.preview_canvas.delete("all")
        if len(curve) > 1:  # draw only if there are more than one points
            self.preview_canvas.create_line(curve, arrow=LAST)

    def init_info_labels(self):
        """
        Initialize the labels providing info about input fields
        """
        Radiobutton(self.frame,
                    variable=self.radio_angle_var,
                    value=False,
                    text="Degrees").grid(row=1, column=0)
        Radiobutton(self.frame,
                    variable=self.radio_angle_var,
                    value=True,
                    text="Radians").grid(row=1, column=1)
        Label(self.frame, text="Angle").grid(row=2, column=0, sticky=W)
        Label(self.frame, text="Length").grid(row=2, column=1, sticky=W)

    def set_rules_in_curve(self, rules):
        """
        Set the rules entries received into the rules of Curve
        class
        """
        self.parent_class.parent_class.classes["fractal"].set_rules(rules)
예제 #9
0
class Checkbox(object):
    """
    A utility class to represent a custom checkbox with helper methods.
    
    Parameters
    ----------
    text : `str`
        The text label for the checkbox.
    cfg : `dict`
        A dictionary representing of widgets with `key` being the key in the
        cfg for this widget.
    key : `str`
        The key for this widget in `cfg`. 
    
    Attributes
    ----------
    checkbox : `Checkbox`
        A tk checkbox widget.
    enabled : `bool`
        Boolean indicating if this widget is enabled.
    value : `BooleanVar`
        The tk variable linked to the checkbox.
    text : `str`
        The text label for the checkbox
    cfg : `dict`
        A dictionary representing of widgets with `key` being the key in the
        cfg for this widget.
    key : `str`
        The key for this widget in `cfg`. 
    
    Methods
    -------
    body
        Place the required elements using the grid layout method.
        Returns the number of rows taken by this element.
    validate
        Validate the checkbox selection. Returns True, always.
    apply
        If enabled, sets the configuration for `key` as the current
        checkbox selection.   
    enable
        Enables the checkbox widget from interaction.
    disable
        Disables the checkbox widget from interaction.
    """

    def __init__(self, text, cfg, key):
        self.checkbox = None
        self.enabled = True

        self.value = BooleanVar()
        self.text = text
        self.cfg = cfg
        self.key = key
        try:
            if self.cfg[self.key] not in (True, False):
                self.value.set(False)
            else:
                self.value.set(self.cfg[self.key])
        except KeyError:
            self.value.set(False)  # default to False

    def body(self, master, row, columns=DEFAULT_COLUMNS, **kwargs):
        """
        Place the required elements using the grid layout method.
        Returns the number of rows taken by this element.
        
        Parameters
        ----------
        master : A tk widget or window.
        row : `int`
            The row variable to use during packing/grid
        columns : `int`
            The columnspan to use during packing/grid
        kwargs : `dict`
            Keyword arguements to pass to packing/grid. Currently ignored.
            
        Returns
        -------
        `int`
            Returns the number of rows taken by this element.
        """
        self.checkbox = Checkbutton(master, text=self.text, variable=self.value)
        self.checkbox.grid(row=row, column=0, columnspan=columns, sticky="w")
        return 1

    def validate(self):
        """
        Validate the checkbox selection.
        """
        return True

    def apply(self):
        """
        If enabled, sets the configuration for `key` as the current
        checkbox selection.        
        """
        if self.enabled:
            self.cfg[self.key] = self.value.get()
        else:
            self.cfg[self.key] = None

    def enable(self):
        """
        Set the state of the checkbox widget to not disabled.
        """
        self.enabled = True
        self.checkbox.state(["!disabled"])

    def disable(self):
        """
        Set the state of the checkbox widget to disabled.
        """
        self.enabled = False
        self.checkbox.state(["disabled"])
예제 #10
0
class FrameSpreadsheetDataset(FrameCustomFileDataset):
    """
        Holds an instance of, and visually represents, a spreadsheet dataset.
        See qal.dataset.spreadsheet.SpreadsheetDataset
    """

    def __init__(self, _master, _dataset=None, _relief=None, _is_destination=None):
        super(FrameSpreadsheetDataset, self).__init__(_master, _dataset, _relief, _is_destination=_is_destination)

        if _dataset is None:
            self.dataset = SpreadsheetDataset()

    def on_select(self):
        """Brings up a selector dialog, prompting the user to select a file,
        the relative path if the file is then saved to the filename property.
        Also, the base path is set.
        """
        self.select_file(_default_extension=".xlsx", _file_types=[('.xlsx files', '.xlsx'), ('all files', '.*')])

    def init_widgets(self):
        # file selector
        self.btn_file_select = Button(self, text="Select file", command=self.on_select)
        self.btn_file_select.grid(column=0, row=0, columnspan=2)

        # filename
        self.filename, self.e_filename, self.l_filename = make_entry(self, "File name: ", 1)


        # delimiter
        self.delimiter, self.e_delimiter, self.l_delimiter = make_entry(self, "Delimiter: ", 2)

        # has_header
        self.l_has_header = ttk.Label(self, text="Has header: ")
        self.l_has_header.grid(column=0, row=3, sticky=W)
        self.has_header = BooleanVar()
        self.e_has_header = ttk.Checkbutton(self, variable=self.has_header)
        self.e_has_header.grid(column=1, row=3, sticky=W)

        # sheet_name
        self.sheet_name, self.e_sheet_name, self.l_sheet_name = make_entry(self, "Sheet name: ", 4)

        # x_offset
        self.x_offset, self.e_x_offset, self.l_x_offset = make_entry(self, "X offset: ", 5)


        # y_offset
        self.y_offset, self.e_y_offset, self.l_y_offset = make_entry(self, "Y offset: ", 6)


    def read_from_dataset(self):
        super(FrameSpreadsheetDataset, self).read_from_dataset()

        self.filename.set(empty_when_none(self.dataset.filename))
        self.has_header.set(bool_to_binary_int(self.dataset.has_header))
        self.sheet_name.set(empty_when_none(self.dataset.sheet_name))
        self.x_offset.set(empty_when_none(self.dataset.x_offset))
        self.y_offset.set(empty_when_none(self.dataset.y_offset))


    def write_to_dataset(self):
        super(FrameSpreadsheetDataset, self).write_to_dataset()

        if self.dataset is None:
            self.dataset = SpreadsheetDataset()

        self.dataset.filename = self.filename.get()
        self.dataset.delimiter = self.delimiter.get()
        self.dataset.has_header = binary_int_to_bool(self.has_header.get())

        self.dataset.sheet_name = self.sheet_name.get()
        if self.x_offset.get() == "":
            self.dataset.x_offset = None
        else:
            self.dataset.x_offset = int(self.x_offset.get())

        if self.y_offset.get() == "":
            self.dataset.y_offset = None
        else:
            self.dataset.y_offset = int(self.y_offset.get())

    def reload(self):
        self.notify_task("Load spreadsheet " + self.dataset.filename, 10)
        self.dataset.load()
        self.notify_task("Loaded spreadsheet " + self.dataset.filename + ".", 100)

    def get_possible_references(self, _force=None):

        if not self.dataset.field_names or _force == True:
            self.reload()

        self.references = self.dataset.field_names

        return self.dataset.field_names
예제 #11
0
class CopyToMoveTo:
    """
        Minimalist file manager intended to be used independently
        or alongside Windows Explorer
    """
    def __init__(self, root):
        """
            Setup window geometry, init settings, define widgets + layout
        """
        self.master = root
        self.master.title("CopyTo-MoveTo")
        self.master.iconbitmap(f"{dirname(__file__)}/icon.ico")

        if system() != "Windows":
            self.master.withdraw()
            messagebox.showwarning(
                "Incompatible platform",
                "CopyTo-MoveTo currently supports Windows platforms only.")
            raise SystemExit

        #Settings:
        self.settings_show_hidden = BooleanVar()
        self.settings_include_files = BooleanVar(value=True)
        self.settings_ask_overwrite = BooleanVar()
        self.settings_ask_overwrite.trace("w", self.settings_exclusives)
        self.settings_rename_dupes = BooleanVar(value=True)
        self.settings_rename_dupes.trace("w", self.settings_exclusives)
        self.settings_multiselect = BooleanVar(value=True)
        self.settings_select_dirs = BooleanVar(value=True)
        self.settings_select_dirs.trace("w", self.settings_mutuals)
        self.settings_select_files = BooleanVar(value=True)
        self.settings_select_files.trace("w", self.settings_mutuals)
        self.settings_geometry = None

        self.appdata_dir = getenv("APPDATA") + "/CopyTo-MoveTo"
        self.appdata_path = self.appdata_dir + "/settings.json"
        self.settings = self.init_settings()

        if self.settings:
            self.settings_geometry = self.settings["geometry"]
            self.settings_show_hidden.set(self.settings["show_hidden"])
            self.settings_include_files.set(self.settings["include_files"])
            self.settings_ask_overwrite.set(self.settings["ask_overwrite"])
            self.settings_rename_dupes.set(self.settings["rename_dupes"])
            self.settings_multiselect.set(self.settings["multiselect"])
            self.settings_select_dirs.set(self.settings["select_dirs"])
            self.settings_select_files.set(self.settings["select_files"])

        self.dialog_showing = BooleanVar()
        self.help_showing = BooleanVar()
        self.about_showing = BooleanVar()

        self.master.protocol("WM_DELETE_WINDOW", self.master_close)
        self.master.bind("<Control-w>", self.master_close)

        #Geometry:
        self.master.minsize(width=450, height=200)

        if self.settings_geometry:
            self.master.geometry(self.settings_geometry)
            self.master.update()
        else:
            self.master.geometry("600x400")
            self.master.update_idletasks()
            (width_offset, height_offset) = Ufd.get_offset(self.master)
            self.master.geometry(f"+{width_offset}+{height_offset}")
            self.master.update_idletasks()

        # Menu:
        self.main_menu = Menu(self.master)
        self.master.config(menu=self.main_menu)

        self.file_menu = Menu(self.main_menu, tearoff=0)
        self.settings_menu = Menu(self.main_menu, tearoff=0)
        self.main_menu.add_cascade(label="File", menu=self.file_menu)
        self.main_menu.add_cascade(label="Settings", menu=self.settings_menu)

        self.file_menu.add_command(label="Open Source(s)",
                                   accelerator="Ctrl+O",
                                   command=lambda: self.show_ufd(source=True))
        self.master.bind("<Control-o>",
                         lambda event: self.show_ufd(source=True))

        self.file_menu.add_command(label="Open Destination(s)",
                                   accelerator="Ctrl+K+O",
                                   command=lambda: self.show_ufd(source=False))
        self.master.bind("<Control-k>o",
                         lambda event: self.show_ufd(source=False))

        self.file_menu.add_separator()
        self.file_menu.add_command(label="Help / Commands",
                                   command=self.show_help)
        self.file_menu.add_command(label="About", command=self.show_about)

        #Settings menu:
        self.settings_menu.add_checkbutton(label="Show Hidden Files & Folders",
                                           variable=self.settings_show_hidden,
                                           onvalue=True,
                                           offvalue=False)

        self.settings_menu.add_checkbutton(
            label="Include Files in Tree",
            variable=self.settings_include_files,
            onvalue=True,
            offvalue=False)

        self.settings_menu.add_separator()

        self.settings_menu.add_checkbutton(
            label="Ask Overwrite",
            variable=self.settings_ask_overwrite,
            onvalue=True,
            offvalue=False)

        self.settings_menu.add_checkbutton(label="Rename Duplicates",
                                           variable=self.settings_rename_dupes,
                                           onvalue=True,
                                           offvalue=False)

        self.settings_menu.add_separator()

        self.settings_menu.add_checkbutton(label="Multiselect",
                                           variable=self.settings_multiselect,
                                           onvalue=True,
                                           offvalue=False)

        self.settings_menu.add_checkbutton(label="Select Folders",
                                           variable=self.settings_select_dirs,
                                           onvalue=True,
                                           offvalue=False)

        self.settings_menu.add_checkbutton(label="Select Files",
                                           variable=self.settings_select_files,
                                           onvalue=True,
                                           offvalue=False)

        self.main_menu.add_separator()

        #Menu commands:
        self.main_menu.add_command(label="Swap Selected",
                                   command=self.swap_selected)
        self.master.bind("<Control-s>", lambda event: self.swap_selected())

        self.main_menu.add_command(label="Clear Selected",
                                   command=self.clear_selected)
        self.master.bind("<Control-x>", lambda event: self.clear_selected())

        self.main_menu.add_command(label="Clear All", command=self.clear_all)
        self.master.bind("<Control-Shift-X>", lambda event: self.clear_all())

        self.main_menu.add_separator()

        self.main_menu.add_command(label="COPY",
                                   command=lambda: self._submit(copy=True))
        self.master.bind("<Control-Shift-Return>",
                         lambda event: self._submit(copy=True))

        self.main_menu.add_command(label="MOVE",
                                   command=lambda: self._submit(copy=False))
        self.master.bind("<Control-Return>",
                         lambda event: self._submit(copy=False))

        # Body:
        self.paneview = PanedWindow(self.master,
                                    sashwidth=7,
                                    bg="#cccccc",
                                    bd=0,
                                    orient="vertical")

        self.top_pane = PanedWindow(self.paneview)
        self.bottom_pane = PanedWindow(self.paneview)
        self.paneview.add(self.top_pane)
        self.paneview.add(self.bottom_pane)

        self.label_source = Label(self.top_pane, text="Source(s):")
        self.label_dest = Label(self.bottom_pane, text="Destination(s):")

        self.y_scrollbar_source = Scrollbar(self.top_pane, orient="vertical")
        self.x_scrollbar_source = Scrollbar(self.top_pane, orient="horizontal")
        self.y_scrollbar_dest = Scrollbar(self.bottom_pane, orient="vertical")
        self.x_scrollbar_dest = Scrollbar(self.bottom_pane,
                                          orient="horizontal")

        self.list_box_source = Listbox(
            self.top_pane,
            selectmode="extended",
            yscrollcommand=self.y_scrollbar_source.set,
            xscrollcommand=self.x_scrollbar_source.set)

        self.list_box_dest = Listbox(self.bottom_pane,
                                     selectmode="extended",
                                     yscrollcommand=self.y_scrollbar_dest.set,
                                     xscrollcommand=self.x_scrollbar_dest.set)

        self.x_scrollbar_source.config(command=self.list_box_source.xview)
        self.y_scrollbar_source.config(command=self.list_box_source.yview)
        self.x_scrollbar_dest.config(command=self.list_box_dest.xview)
        self.y_scrollbar_dest.config(command=self.list_box_dest.yview)

        # Layout:
        self.master.rowconfigure(0, weight=1)
        self.master.columnconfigure(0, weight=1)

        self.top_pane.rowconfigure(1, weight=1)
        self.top_pane.columnconfigure(0, weight=1)
        self.bottom_pane.rowconfigure(1, weight=1)
        self.bottom_pane.columnconfigure(0, weight=1)

        self.paneview.paneconfigure(self.top_pane, minsize=100)
        self.paneview.paneconfigure(self.bottom_pane, minsize=100)

        self.paneview.grid(row=0, column=0, sticky="nsew")

        self.label_source.grid(row=0, column=0, sticky="w")
        self.list_box_source.grid(row=1, column=0, sticky="nsew")
        self.y_scrollbar_source.grid(row=1, column=1, sticky="ns")
        self.x_scrollbar_source.grid(row=2, column=0, sticky="ew")

        self.label_dest.grid(row=0, column=0, sticky="w", columnspan=2)
        self.list_box_dest.grid(row=1, column=0, sticky="nsew")
        self.y_scrollbar_dest.grid(row=1, column=1, sticky="ns")
        self.x_scrollbar_dest.grid(row=2, column=0, sticky="ew")

    def __str__(self):
        """Return own address"""

        return f"CopyTo-MoveTo @ {hex(id(self))}"

    def init_settings(self):
        """Called on startup, loads, parses, and returns json settings."""

        if exists(self.appdata_path):
            with open(self.appdata_path, "r") as settings_file:
                settings_json = settings_file.read()

            settings = loads(settings_json)
            return settings
        else:
            return None

    def settings_exclusives(self, *args):
        """
            Callback assigned to settings that are mutually exclusive, 
            to prevent logical/runtime errors or unexpected behavior.
        """

        if args[0] == "PY_VAR2":
            if self.settings_ask_overwrite.get() == 1:
                self.settings_rename_dupes.set(0)
                return

        elif args[0] == "PY_VAR3":
            if self.settings_rename_dupes.get() == 1:
                self.settings_ask_overwrite.set(0)
                return

    def settings_mutuals(self, *args):
        """
            Prevent select folders & select files from being disabled concurrently

            If both are unselected, reselect the one we didn't just deselect on.
        """

        if self.settings_select_dirs.get() == 0 \
        and self.settings_select_files.get() == 0:

            if args[0] == "PY_VAR5":
                self.settings_select_files.set(1)

            elif args[0] == "PY_VAR6":
                self.settings_select_dirs.set(1)

    def master_close(self, event=None):
        """
            Similar to utils.toplevel_close().
            writes settings to the disk as json.
        """

        settings = {
            "geometry": self.master.geometry(),
            "show_hidden": self.settings_show_hidden.get(),
            "include_files": self.settings_include_files.get(),
            "ask_overwrite": self.settings_ask_overwrite.get(),
            "rename_dupes": self.settings_rename_dupes.get(),
            "multiselect": self.settings_multiselect.get(),
            "select_dirs": self.settings_select_dirs.get(),
            "select_files": self.settings_select_files.get(),
        }

        settings_json = dumps(settings)

        if not exists(self.appdata_dir):
            mkdir(self.appdata_dir)

        with open(self.appdata_path, "w+") as settings_file:
            settings_file.write(settings_json)

        if self.dialog_showing.get() == 1:
            self.ufd.cancel()

        self.master.destroy()

    def toplevel_close(self, dialog, boolean):
        """
            This callback flips the value for a given toplevel_showing boolean
            to false, before disposing of the toplevel.
        """

        boolean.set(0)
        dialog.destroy()

    def swap_selected(self):
        """Swap list entries between source & destination"""

        source_selection = list(self.list_box_source.curselection())
        dest_selection = list(self.list_box_dest.curselection())

        for i in reversed(source_selection):
            item = self.list_box_source.get(i)
            self.list_box_source.delete(i)
            self.list_box_dest.insert("0", item)

        for i in reversed(dest_selection):
            item = self.list_box_dest.get(i)
            self.list_box_dest.delete(i)
            self.list_box_source.insert("0", item)

    def clear_selected(self):
        """Removes selected (highlighted) item(s) from a given listbox"""

        source_selection = list(self.list_box_source.curselection())
        dest_selection = list(self.list_box_dest.curselection())

        if source_selection:
            for i in reversed(source_selection):
                self.list_box_source.delete(i)

            self.list_box_source.selection_set(source_selection[0])

        if dest_selection:
            for i in reversed(dest_selection):
                self.list_box_dest.delete(i)

            self.list_box_dest.selection_set(dest_selection[0])

    def clear_all(self):
        """Clears both listboxes in the main UI, resetting the form."""

        self.list_box_source.delete(0, "end")
        self.list_box_dest.delete(0, "end")

    def handled(fn):
        """Filesystem operations are wrapped here for error handling"""
        @wraps(fn)
        def inner(self, *args, **kwargs):
            try:
                fn(self, *args, **kwargs)
                return True
            except (PermissionError, FileNotFoundError) as err:
                self.skipped_err.append(f"{err.args[1]}:\n" +
                                        (" => ".join(args)))
                return False

        return inner

    @handled
    def _copy(self, path, destination):
        """Wrapper for shutil.copy2() || shutil.copytree()"""

        if isfile(path):
            copy2(path, destination)
        else:
            copytree(path, destination)

    @handled
    def _move(self, path, destination):
        """Wrapper for shutil.move()"""

        move(path, destination)

    @handled
    def _delete(self, path):
        """Wrapper for os.remove() || shutil.rmtree()"""

        if isfile(path):
            remove(path)
        elif isdir(path):
            rmtree(path)

    def disabled_ui(fn):
        """Menubar is disabled during operations"""
        @wraps(fn)
        def inner(self, *args, **kwargs):
            self.main_menu.entryconfig("File", state="disabled")
            self.main_menu.entryconfig("Settings", state="disabled")
            self.main_menu.entryconfig("Clear Selected", state="disabled")
            self.main_menu.entryconfig("Clear All", state="disabled")
            self.main_menu.entryconfig("COPY", state="disabled")
            self.main_menu.entryconfig("MOVE", state="disabled")

            fn(self, *args, **kwargs)

            self.main_menu.entryconfig("File", state="normal")
            self.main_menu.entryconfig("Settings", state="normal")
            self.main_menu.entryconfig("Clear Selected", state="normal")
            self.main_menu.entryconfig("Clear All", state="normal")
            self.main_menu.entryconfig("COPY", state="normal")
            self.main_menu.entryconfig("MOVE", state="normal")

        return inner

    def _submit(self, copy):
        """Thread/wrapper for submit() so we don't block the UI during operations"""

        self.thread = Thread(target=self.submit, args=(copy, ), daemon=True)
        self.thread.start()

    @disabled_ui
    def submit(self, copy):
        """
            Move or copy each item in the origin list to the path in the
            destination list. Supports no more than one destination directory
            where copy == False.

            Ask Overwrite and Rename Dupes will alter the way we handle 
            existing data standing in the way. By default, duplicates are 
            renamed with an index. A messagebox can complain to the user
            if shutil raises a PermissionError, and the operation is skipped.
        """

        if (self.list_box_dest.size() > 1) and not copy:
            messagebox.showwarning(
                "Invalid Operation",
                "Move operation only supports a single destination directory.")
            return

        sources = self.list_box_source.get(0, "end")
        destinations = self.list_box_dest.get(0, "end")

        self.skipped_err = []

        for j, destination in enumerate(destinations):

            if isfile(destination):
                self.skipped_err.append(f"Invalid destination: {destination}")
                continue

            for i, source in enumerate(sources):
                self.progress(i, j)

                (_, filename) = split(source)
                future_destination = join(destination + sep, filename)

                if exists(future_destination):
                    if not self.settings_ask_overwrite.get() \
                    and not self.settings_rename_dupes.get():

                        if not self._delete(future_destination):
                            continue

                    if self.settings_ask_overwrite.get():

                        if self.ask_overwrite(future_destination):
                            if not self._delete(future_destination):
                                continue

                        else:
                            continue

                    if self.settings_rename_dupes.get():
                        future_destination = self.name_dupe(future_destination)

                if copy:
                    if not self._copy(source, future_destination):
                        continue
                else:
                    if not self._move(source, future_destination):
                        continue

        self.list_box_source.delete(0, "end")
        self.list_box_dest.delete(0, "end")

        if self.skipped_err:
            messagebox.showerror(title="Error(s)",
                                 message="\n\n".join(self.skipped_err))

    @staticmethod
    def name_dupe(path):
        """
            Renames the file or directory until it doesn't exist
            in the destination with that name anymore, by appending
            the filename with an index wrapped in parenthesis.
            (Windows platforms)
            file.txt => file (1).txt => file (2).txt
        """

        if system() != "Windows":
            raise OSError("For use with Windows filesystems.")

        path_ = path
        (root, filename) = split(path_)

        if isdir(path_):
            title = filename
            ext = None
        else:
            (title, ext) = splitext(filename)

        filecount = 0
        while exists(path_):
            filecount += 1
            new_title = title + " (" + str(filecount) + ")"
            if ext:
                new_title = new_title + ext
            path_ = join(root, new_title)

        return path_

    def ask_overwrite(self, future_destination):
        """Messagebox result returned as truth value"""

        return messagebox.askyesno(
            title="Path Conflict",
            message=f"Overwrite:\n\n{future_destination}?\n\n" \
            f"YES - Overwrite\nNO - Skip"
        )

    def progress(self, i, j):
        """
            Visualize operands in GUI during operations

            i = current source operand index
            j = current destination operand index
        """

        for y, _ in enumerate(self.list_box_source.get(0, "end")):
            if y != i:
                self.list_box_source.itemconfigure(y,
                                                   bg="#FFFFFF",
                                                   fg="#000000")
            else:
                self.list_box_source.itemconfigure(y,
                                                   bg="#cccccc",
                                                   fg="#000000")

        for x, _ in enumerate(self.list_box_dest.get(0, "end")):
            if x != j:
                self.list_box_dest.itemconfigure(x, bg="#FFFFFF", fg="#000000")
            else:
                self.list_box_dest.itemconfigure(x, bg="#cccccc", fg="#000000")

        self.master.update()

    #Toplevels:
    def show_about(self):
        """
            Displays a static dialog that doesn't allow additional
            instances of itself to be created while showing.
        """

        if self.about_showing.get() == 0:
            self.about_showing.set(1)

            try:
                with open(f"{dirname(__file__)}/about.txt", "r") as aboutfile:
                    about_info = aboutfile.read()
            except FileNotFoundError:
                messagebox.showerror("Error", "File not found")
                self.about_showing.set(0)
                return

            else:
                self.about = Toplevel()
                self.about.title("About")
                self.about.iconbitmap(f"{dirname(__file__)}/icon.ico")

                self.about.geometry("600x400")
                self.about.resizable(0, 0)
                self.about.update_idletasks()
                (width_offset, height_offset) = Ufd.get_offset(self.about)
                self.about.geometry(f"+{width_offset-75}+{height_offset-75}")
                self.about.update_idletasks()

                self.about_message = Label(
                    self.about,
                    text=about_info,
                    justify="left",
                    wraplength=(self.about.winfo_width() - 25))

                self.about_message.grid(sticky="nsew")

                self.about.protocol(
                    "WM_DELETE_WINDOW", lambda: self.toplevel_close(
                        self.about, self.about_showing))

    def show_help(self):
        """
            Displays a scrollable dialog that doesn't allow additional
            instances of itself to be created while showing.
        """

        if self.help_showing.get() == 0:
            self.help_showing.set(1)

            try:
                with open(f"{dirname(__file__)}/help.txt", "r") as helpfile:
                    help_info = helpfile.read()
            except FileNotFoundError:
                messagebox.showerror("Error", "File not found")
                self.help_showing.set(0)
                return

            else:
                self.help_window = Toplevel()
                self.help_window.title("Help")
                self.help_window.iconbitmap(f"{dirname(__file__)}/icon.ico")

                self.help_window.geometry("500x300")
                self.help_window.update_idletasks()
                (width_offset,
                 height_offset) = Ufd.get_offset(self.help_window)
                self.help_window.geometry(
                    f"+{width_offset+75}+{height_offset-75}")
                self.help_window.update_idletasks()

                self.message_y_scrollbar = Scrollbar(self.help_window,
                                                     orient="vertical")

                self.help_text = Text(
                    self.help_window,
                    wrap="word",
                    yscrollcommand=self.message_y_scrollbar.set)

                self.help_window.rowconfigure(0, weight=1)
                self.help_window.columnconfigure(0, weight=1)

                self.help_text.grid(row=0, column=0, sticky="nsew")
                self.message_y_scrollbar.grid(row=0, column=1, sticky="nse")

                self.message_y_scrollbar.config(command=self.help_text.yview)

                self.help_text.insert("end", help_info)
                self.help_text.config(state="disabled")

                self.help_window.protocol(
                    "WM_DELETE_WINDOW", lambda: self.toplevel_close(
                        self.help_window, self.help_showing))

    def show_ufd(self, source=True):
        """ Display Ufd w/ appropriate kwargs => Populate GUI w/ result"""

        if self.dialog_showing.get() == 0:
            self.dialog_showing.set(1)

            self.ufd = Ufd(title="Add Items",
                           show_hidden=self.settings_show_hidden.get(),
                           include_files=self.settings_include_files.get(),
                           multiselect=self.settings_multiselect.get(),
                           select_dirs=self.settings_select_dirs.get(),
                           select_files=self.settings_select_files.get(),
                           unix_delimiter=False,
                           stdout=False)

            for result in self.ufd():
                if source:
                    self.list_box_source.insert("end", result)
                else:
                    self.list_box_dest.insert("end", result)

            self.dialog_showing.set(0)
예제 #12
0
class Application:
    def __init__(self):
        self.root = Tk()
        self.root.title("docx-merge %s" % __version__)

        # Template document (.docx)

        frame = Frame(self.root)
        frame.pack(side="top", fill="x", padx=5, pady=5)

        label = Label(frame, text="Template document (.docx):", justify="left")
        label.pack(side="top", fill="x")

        self.template = Text(frame, height=1)
        self.template.pack(side="left", fill="x")

        Button(frame, text="Browse",
               command=self.on_browse_template).pack(side="right")

        # CSV data (.csv)

        frame = Frame(self.root)
        frame.pack(side="top", fill="x", padx=5, pady=5)

        label = Label(frame, text="CSV data (.csv):", justify="left")
        label.pack(side="top", fill="x")

        self.data = Text(frame, height=1)
        self.data.pack(side="left", fill="x")

        Button(frame, text="Browse",
               command=self.on_browse_data).pack(side="right")

        # Filename pattern

        frame = Frame(self.root)
        frame.pack(side="top", fill="x", padx=5, pady=5)

        label = Label(frame, text="Filename pattern:", justify="left")
        label.pack(side="top")

        self.pattern = Text(frame, height=1)
        self.pattern.pack(side="top", fill="x")

        # --

        self.notification = StringVar()
        self.notification.set("")

        self.convert = BooleanVar()
        self.convert.set(False)

        frame = Frame(self.root)
        frame.pack(side="top", fill="x", padx=5, pady=5)

        Label(frame, textvariable=self.notification,
              justify="left").pack(side="left", fill="x")

        Button(frame, text="Process",
               command=self.on_process).pack(side="right", padx=5)

        Checkbutton(
            frame,
            text="Convert to PDF",
            variable=self.convert,
            onvalue=True,
            offvalue=False,
        ).pack(side="right")

        # Autofill

        self.pattern.insert("insert", "{{ARCHITECTE}}-{{FACTURE}}.docx")

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

    def notify(self, text=""):
        self.notification.set(text)

    def on_browse_template(self):
        filename = filedialog.LoadFileDialog(self.root, title="Browse").go(
            pattern="*.docx", dir_or_file=os.path.expanduser("~"))

        if not filename:
            return

        self.template.delete("0.1", "end")
        self.template.insert("insert", filename)

        self.notify()

    def on_browse_data(self):
        filename = filedialog.LoadFileDialog(self.root, title="Browse").go(
            pattern="*.csv", dir_or_file=os.path.expanduser("~"))

        if not filename:
            return

        self.data.delete("0.1", "end")
        self.data.insert("insert", filename)

        self.notify()

    def on_process(self):
        template = self.template.get("1.0", "end").strip()
        data = self.data.get("1.0", "end").strip()
        pattern = self.pattern.get("1.0", "end").strip()

        convert = self.convert.get()

        if not template or not data or not pattern:
            return

        try:
            path = merge(template, data, pattern, convert=convert)
        except Exception as e:
            self.notify("Error: %s" % str(e))

            raise e

        self.notify("Done in %s" % path)
예제 #13
0
파일: gui.py 프로젝트: LGMOak/Bounty-RLBot
    def run(self):
        root = Tk()

        icon_path = path.join(path.dirname(path.abspath(__file__)),
                              "./logo.png")
        root.iconphoto(True, PhotoImage(file=icon_path))

        root.title("Lukkkim/Bounty-RLBot")

        root.geometry("255x250")

        title = ttk.Label(root,
                          text=f"{self.agent.name} framework by VirxERLU")
        title.pack()

        author = ttk.Label(root, text=f"Bounty by Lukim (Lukkkim/Bounty-RLBot")
        author.pack()

        # Disable driving

        drive_bool = BooleanVar()
        drive_bool.set(self.agent.disable_driving)

        def set_drive():
            self.agent.disable_driving = drive_bool.get()

        drive_btn = ttk.Checkbutton(root,
                                    text='Disable driving',
                                    variable=drive_bool,
                                    command=set_drive)
        drive_btn.pack()

        # Debugging

        debug_bool = BooleanVar()
        debug_bool.set(self.agent.debugging)

        def set_debug():
            self.agent.debugging = debug_bool.get()

        debug_btn = ttk.Checkbutton(root,
                                    text='Debugging',
                                    variable=debug_bool,
                                    command=set_debug)
        debug_btn.pack()

        # Debug 2D

        debug_2d_bool = BooleanVar()
        debug_2d_bool.set(self.agent.debug_2d_bool)

        def set_debug_2d():
            self.agent.debug_2d_bool = debug_2d_bool.get()

        debug_2d = ttk.Checkbutton(root,
                                   text='Debug 2D',
                                   variable=debug_2d_bool,
                                   command=set_debug_2d)
        debug_2d.pack()

        # Location

        show_coords_bool = BooleanVar()
        show_coords_bool.set(self.agent.show_coords)

        def set_show_coords():
            self.agent.show_coords = show_coords_bool.get()

        show_coords_btn = ttk.Checkbutton(root,
                                          text='Show Car Info (2D/Lines)',
                                          variable=show_coords_bool,
                                          command=set_show_coords)
        show_coords_btn.pack()

        # Debug 3D

        debug_3d_bool = BooleanVar()
        debug_3d_bool.set(self.agent.debug_3d_bool)

        def set_debug_3d():
            self.agent.debug_3d = debug_3d_bool.get()

        debug_3d = ttk.Checkbutton(root,
                                   text='Debug 3D',
                                   variable=debug_3d_bool,
                                   command=set_debug_3d)
        debug_3d.pack()

        # Debug Stack

        debug_stack_bool = BooleanVar()
        debug_stack_bool.set(self.agent.debug_stack_bool)

        def set_debug_stack():
            self.agent.debug_stack_bool = debug_stack_bool.get()

        debug_stack = ttk.Checkbutton(root,
                                      text='Debug Stack (3D)',
                                      variable=debug_stack_bool,
                                      command=set_debug_stack)
        debug_stack.pack()

        # Debug Lines

        debug_lines_bool = BooleanVar()
        debug_lines_bool.set(self.agent.debug_lines)

        def set_debug_lines():
            self.agent.debug_lines = debug_lines_bool.get()

        debug_lines = ttk.Checkbutton(root,
                                      text='Debug Lines',
                                      variable=debug_lines_bool,
                                      command=set_debug_lines)
        debug_lines.pack()

        # Debug ball prediction

        debug_ball_path_bool = BooleanVar()
        debug_ball_path_bool.set(self.agent.debug_ball_path)

        def set_debug_ball_path():
            self.agent.debug_ball_path = debug_ball_path_bool.get()

        debug_ball_path = ttk.Checkbutton(root,
                                          text='Debug Ball Path (Lines)',
                                          variable=debug_ball_path_bool,
                                          command=set_debug_ball_path)
        debug_ball_path.pack()

        # Debug ball prediction precision

        debug_ball_path_precision_str = StringVar()
        debug_ball_path_precision_str.set(
            "Precision: " + str(self.agent.debug_ball_path_precision))
        debug_ball_path_precision_label = ttk.Label(
            root, textvariable=debug_ball_path_precision_str)
        debug_ball_path_precision_label.pack()

        def set_debug_ball_path_precision(value):
            value = round(float(value))
            self.agent.debug_ball_path_precision = value
            debug_ball_path_precision_str.set("Precision: " + str(value))

        debug_ball_path_precision = ttk.Scale(
            root,
            orient=HORIZONTAL,
            from_=2,
            to=20,
            command=set_debug_ball_path_precision)
        debug_ball_path_precision.set(self.agent.debug_ball_path_precision)
        debug_ball_path_precision.pack()

        self.stop = root.destroy

        try:
            root.mainloop()
        except Exception:
            print_exc()
예제 #14
0
class App:
    def __init__(self, master):
        frame = Frame(master)
        frame.pack()

        self.process = None

        self.pitch = BooleanVar()
        self.checkPitch = Checkbutton(frame,
                                      text="Use Pitch Shift",
                                      variable=self.pitch,
                                      command=self.pitchTabManagement)
        self.checkPitch.grid(row=0, column=0, columnspan=3)

        self.pitchValue = DoubleVar()
        self.pitchslider = Scale(frame,
                                 from_=-2000,
                                 to=2000,
                                 length=500,
                                 orient=HORIZONTAL,
                                 variable=self.pitchValue,
                                 showvalue=0)
        self.pitchslider.grid(row=1, column=1)
        self.entryLabel = Label(frame, text="Pitch:")
        self.entryLabel.grid(row=1, column=0)
        self.pitchTxt = Entry(frame, textvariable=self.pitchValue)
        self.pitchTxt.grid(row=1, column=2)

        self.flanger = BooleanVar()
        self.checkFlanger = Checkbutton(frame,
                                        text="Use Flanger Effect",
                                        variable=self.flanger,
                                        command=self.flangerTabManagement)
        self.checkFlanger.grid(row=2, column=0, columnspan=3)

        self.delayValue = DoubleVar()
        self.delaylbl = Label(frame, text="Delay:")
        self.delaylbl.grid(row=3, column=0)
        self.delayslider = Scale(frame,
                                 from_=0,
                                 to=30,
                                 length=500,
                                 orient=HORIZONTAL,
                                 variable=self.delayValue,
                                 showvalue=0)
        self.delayslider.grid(row=3, column=1)
        self.delayTxt = Entry(frame, textvariable=self.delayValue)
        self.delayTxt.grid(row=3, column=2)

        self.depthValue = DoubleVar()
        self.depthlbl = Label(frame, text="Depth:")
        self.depthlbl.grid(row=4, column=0)
        self.depthslider = Scale(frame,
                                 from_=0,
                                 to=10,
                                 length=500,
                                 orient=HORIZONTAL,
                                 variable=self.depthValue,
                                 showvalue=0)
        self.depthslider.grid(row=4, column=1)
        self.depthTxt = Entry(frame, textvariable=self.depthValue)
        self.depthTxt.grid(row=4, column=2)

        self.regenValue = DoubleVar()
        self.regenlbl = Label(frame, text="Regen:")
        self.regenlbl.grid(row=5, column=0)
        self.regenslider = Scale(frame,
                                 from_=-95,
                                 to=95,
                                 length=500,
                                 orient=HORIZONTAL,
                                 variable=self.regenValue,
                                 showvalue=0)
        self.regenslider.grid(row=5, column=1)
        self.regenTxt = Entry(frame, textvariable=self.regenValue)
        self.regenTxt.grid(row=5, column=2)

        self.widthValue = DoubleVar()
        self.widthlbl = Label(frame, text="Width:")
        self.widthlbl.grid(row=6, column=0)
        self.widthslider = Scale(frame,
                                 from_=0,
                                 to=100,
                                 length=500,
                                 orient=HORIZONTAL,
                                 variable=self.widthValue,
                                 showvalue=0)
        self.widthslider.grid(row=6, column=1)
        self.widthTxt = Entry(frame, textvariable=self.widthValue)
        self.widthTxt.grid(row=6, column=2)

        self.speedValue = DoubleVar()
        self.speedlbl = Label(frame, text="Speed:")
        self.speedlbl.grid(row=7, column=0)
        self.speedslider = Scale(frame,
                                 from_=0.1,
                                 to=10.,
                                 length=500,
                                 orient=HORIZONTAL,
                                 resolution=0.1,
                                 showvalue=0,
                                 variable=self.speedValue)
        self.speedslider.grid(row=7, column=1)
        self.speedTxt = Entry(frame, textvariable=self.speedValue)
        self.speedTxt.grid(row=7, column=2)

        self.flangerShape = StringVar()
        self.flangerShape.set("sine")
        self.shapelbl = Label(frame, text="Shape:")
        self.shapelbl.grid(row=8, column=0)
        self.shapesine = Radiobutton(frame,
                                     text="Sine",
                                     variable=self.flangerShape,
                                     value="sine")
        self.shapesine.grid(row=8, column=1)
        self.shapetri = Radiobutton(frame,
                                    text="Triangle",
                                    variable=self.flangerShape,
                                    value="triangle")
        self.shapetri.grid(row=8, column=2)

        self.phaseValue = DoubleVar()
        self.phaselbl = Label(frame, text="Phase:")
        self.phaselbl.grid(row=9, column=0)
        self.phaseslider = Scale(frame,
                                 from_=0,
                                 to=100,
                                 length=500,
                                 orient=HORIZONTAL,
                                 variable=self.phaseValue,
                                 showvalue=0)
        self.phaseslider.grid(row=9, column=1)
        self.phaseTxt = Entry(frame, textvariable=self.phaseValue)
        self.phaseTxt.grid(row=9, column=2)

        self.interpolation = StringVar()
        self.interpolation.set("linear")
        self.interplbl = Label(frame, text="Interpolation:")
        self.interplbl.grid(row=10, column=0)
        self.intlin = Radiobutton(frame,
                                  text="Linear",
                                  variable=self.interpolation,
                                  value="linear")
        self.intlin.grid(row=10, column=1)
        self.intquad = Radiobutton(frame,
                                   text="Quadratic",
                                   variable=self.interpolation,
                                   value="quadratic")
        self.intquad.grid(row=10, column=2)

        self.gain = BooleanVar()
        self.checkGain = Checkbutton(frame,
                                     text="Enable Gain",
                                     variable=self.gain,
                                     command=self.gainTabManagement)
        self.checkGain.grid(row=11, column=0, columnspan=3)

        self.gainValue = DoubleVar()
        self.gainLabel = Label(frame, text="Volume Gain:")
        self.gainLabel.grid(row=12, column=0)
        self.gainSlider = Scale(frame,
                                from_=-3.0,
                                to=3.0,
                                length=500,
                                orient=HORIZONTAL,
                                variable=self.gainValue,
                                showvalue=0,
                                resolution=0.1)
        self.gainSlider.grid(row=12, column=1)
        self.txtGain = Entry(frame, textvariable=self.gainValue)
        self.txtGain.grid(row=12, column=2)

        self.startBtn = Button(frame, text="Start SoX", command=self.start_sox)
        self.startBtn.grid(row=13, column=0)

        self.stopBtn = Button(frame, text="Stop SoX", command=self.stop_sox)
        self.stopBtn.config(state=DISABLED)
        self.stopBtn.grid(row=14, column=0)

        self.loadBtn = Button(frame, text="Load Preset", command=self.load)
        self.loadBtn.grid(row=13, column=1)

        self.saveBtn = Button(frame, text="Save Preset", command=self.save)
        self.saveBtn.grid(row=14, column=1)

        self.status = Label(frame,
                            text="SoX not started, waiting for user operation")
        self.status.grid(row=15, column=0, columnspan=3)

        self.pitchcontrols = [self.pitchslider, self.pitchTxt]

        self.flangercontrols = [
            self.delayslider, self.delayTxt, self.depthslider, self.depthTxt,
            self.regenslider, self.regenTxt, self.widthslider, self.widthTxt,
            self.speedslider, self.speedTxt, self.shapetri, self.shapesine,
            self.phaseslider, self.phaseTxt, self.intlin, self.intquad
        ]
        self.gaincontrols = [self.txtGain, self.gainSlider]

        self.toDisableList = self.pitchcontrols + self.flangercontrols\
            + self.gaincontrols

        self.pitchTabManagement()
        self.flangerTabManagement()
        self.gainTabManagement()

    def load(self):
        messagebox.showwarning(
            "Attention",
            "This feature uses Python's pickle module, which is weak to arbitrary code execution.\nNever load settings from an untrusted source, it might break your system!"
        )
        f = filedialog.askopenfile(filetypes=[("Python3 Pickle", "*.pickle")],
                                   mode="rb")
        if f is None:
            return
        self.pitch.set(pickle.load(f))
        self.pitchValue.set(pickle.load(f))
        self.flanger.set(pickle.load(f))
        self.delayValue.set(pickle.load(f))
        self.depthValue.set(pickle.load(f))
        self.regenValue.set(pickle.load(f))
        self.widthValue.set(pickle.load(f))
        self.speedValue.set(pickle.load(f))
        self.flangerShape.set(pickle.load(f))
        self.phaseValue.set(pickle.load(f))
        self.interpolation.set(pickle.load(f))
        self.gain.set(pickle.load(f))
        self.gainValue.set(pickle.load(f))
        f.close()
        self.pitchTabManagement()
        self.flangerTabManagement()
        self.gainTabManagement()

    def save(self):
        f = filedialog.asksaveasfile(mode="wb",
                                     defaultextension="*.pickle",
                                     filetypes=[("Python3 Pickle", "*.pickle")
                                                ])
        if f is None:
            return
        pickle.dump(self.pitch.get(), f)
        pickle.dump(self.pitchValue.get(), f)
        pickle.dump(self.flanger.get(), f)
        pickle.dump(self.delayValue.get(), f)
        pickle.dump(self.depthValue.get(), f)
        pickle.dump(self.regenValue.get(), f)
        pickle.dump(self.widthValue.get(), f)
        pickle.dump(self.speedValue.get(), f)
        pickle.dump(self.flangerShape.get(), f)
        pickle.dump(self.phaseValue.get(), f)
        pickle.dump(self.interpolation.get(), f)
        pickle.dump(self.gain.get(), f)
        pickle.dump(self.gainValue.get(), f)
        f.close()

    def pitchTabManagement(self):
        if self.pitch.get():
            for item in self.pitchcontrols:
                item.config(state=NORMAL)
        else:
            for item in self.pitchcontrols:
                item.config(state=DISABLED)

    def flangerTabManagement(self):
        if self.flanger.get():
            for item in self.flangercontrols:
                item.config(state=NORMAL)
        else:
            for item in self.flangercontrols:
                item.config(state=DISABLED)

    def gainTabManagement(self):
        if self.gain.get():
            for item in self.gaincontrols:
                item.config(state=NORMAL)
        else:
            for item in self.gaincontrols:
                item.config(state=DISABLED)

    def createSink(self):
        try:
            Popen([
                "pactl", "load-module", "module-null-sink",
                "sink_name=Voice_Changer",
                "sink_properties=device.description=Voice_Changer"
            ])
            self.createSinkBtn.config(state=DISABLED)
            self.startBtn.config(state=NORMAL)
            self.status.config(
                text=
                "Sink seems to have been created successfully, now you can try using the software"
            )
        except:
            self.status.config(
                text=
                "There has been an error creating the Sink, call a Computer Expert"
            )

    def start_sox(self):
        sinkList = Popen(["pacmd", "list-sinks"], stdout=PIPE).communicate()
        sinkPresent = b"Voice_Changer" in sinkList[0]
        if not sinkPresent:
            self.createSink()
        try:
            modules = []
            if self.pitch.get():
                print("Pitch Shift Enabled")
                modules += ["pitch", str(self.pitchValue.get())]
            if self.flanger.get():
                print("Flanger Enabled")
                modules += [
                    "flanger",
                    str(self.delayValue.get()),
                    str(self.depthValue.get()),
                    str(self.regenValue.get()),
                    str(self.widthValue.get()),
                    str(self.speedValue.get()),
                    str(self.flangerShape.get()),
                    str(self.phaseValue.get()),
                    str(self.interpolation.get())
                ]
            if self.gain.get():
                print("Gain Enabled")
                modules += ["gain", str(self.gainValue.get())]
            self.process = Popen([
                "sox", "-t", "pulseaudio", "default", "-t", "pulseaudio",
                "Voice_Changer"
            ] + modules)
            self.status.config(
                text=
                "SoX Started, make sure to configure pavucontrol accordingly")
            self.startBtn.config(state=DISABLED)
            self.stopBtn.config(state=NORMAL)
            for item in self.toDisableList:
                item.config(state=DISABLED)
        except:
            self.status.config(
                text=
                "There has been an error starting SoX, check your system configuration"
            )

    def stop_sox(self):
        self.process.kill()
        self.startBtn.config(state=NORMAL)
        self.stopBtn.config(state=DISABLED)
        for item in self.toDisableList:
            item.config(state=NORMAL)
        self.status.config(
            text="SoX Stopped, now you can change your settings and restart")
예제 #15
0
    string_browning.set('Browning Index = ' + str(browning))
    string_hue.set('Hue Angle = ' + str(hue))
    entry_l.configure(validate='key')
    entry_a.configure(validate='key')
    entry_b.configure(validate='key')
    entry_browning.configure(validate='key')
    entry_hue.configure(validate='key')
    window.update()


set_lab_values([0.0, 0.0, 0.0])

# Creating buttons
print('Creating buttons...')
remove_img_bg = BooleanVar()
remove_img_bg.set(False)
check_remove_bg = Checkbutton(frame_settings,
                              text='Remove background?',
                              var=remove_img_bg,
                              background='#ffffff',
                              foreground='#000000',
                              font=('Arial', 12))
check_remove_bg.pack(side='top', anchor='center')
check_remove_bg.toggle()


def choose_file():
    # Asking for filename
    update_status('Asking for filename...')
    window.update()
    filename = filedialog.askopenfilename(initialdir='~/Pictures')
예제 #16
0
#------------------------------------------------------------------------------

if __name__ == "__main__":
    Z = 18
    path1 = os.path.dirname(sys.argv[0]) + '/'

    sim = Tk()
    sim.title('Plasma diagnostics')
    #sim.iconbitmap(r'atom.ico')                                                 #Optional .ico (does not work in my Ubuntu)

    kexc_var = BooleanVar()
    kion_var = BooleanVar()
    klion_var = BooleanVar()
    kllion_var = BooleanVar()
    total_var = BooleanVar()
    total_var.set(True)  #Consider all

    #Database loader
    db = dbloader(path1, Z, kexc_var.get(), kion_var.get(), klion_var.get(),
                  kllion_var.get(), total_var.get())
    if db == None: sys.exit()  #Does not open without a transition database
    #Database assignment
    kexc_var.set(db[0])
    kion_var.set(db[1])
    klion_var.set(db[2])
    kllion_var.set(db[3])
    total_var.set(db[4])
    (hw_trans, cs_K_exc, cs_K_ion, cs_KL_ion, cs_KLL_ion, cs_K_exc_exists,
     cs_K_ion_exists, cs_KL_ion_exists, cs_KLL_ion_exists) = db[5:]

    tf_var = StringVar()
예제 #17
0
class TrimWindow:
    def __init__(self, root):
        self.window = tk.Toplevel(root)

        audio.TRIMMED_AUDIO = audio.get_audio()[0]
        self.start_marker_position = 0.0
        self.end_marker_position = (len(audio.TRIMMED_AUDIO) + 1.) / audio.SAMPLE_RATE
        self.start_marker_edit = BooleanVar()
        self.start_marker_edit.set('false')
        self.end_marker_edit = BooleanVar()
        self.end_marker_edit.set('false')

        self.frame = tk.Frame(self.window)
        self.frame.grid()
        self.start_marker_button = \
            tk.Button(self.frame, text="Move start marker", relief="raised", command=self.toggle_start_marker_button)
        self.start_marker_button.grid(row=0, column=0, padx=5, pady=5)
        self.end_marker_button = \
            tk.Button(self.frame, text="Move end marker", relief="raised", command=self.toggle_end_marker_button)
        self.end_marker_button.grid(row=0, column=1, padx=5, pady=5)

        self.plot_canvas, self.plot_figure, self.plot_axes = self.get_matplotlib_canvas()
        self.plot_canvas.get_tk_widget().grid(row=1, columnspan=2, column=0, padx=5, pady=5)

        self.trim_button = \
            tk.Button(self.frame, text="Trim to markers", command=self.trim_audio)
        self.trim_button.grid(row=2, column=0, padx=5, pady=5)
        self.accept_button = tk.Button(self.frame, text="OK", command=self.replace_audio)
        self.accept_button.grid(row=2, column=1, padx=5, pady=5)

        self.update_plot()

        self.window.update()

        self.window.grab_set()
        self.window.protocol("WM_DELETE_WINDOW", self.kill_trim_window)

    def get_matplotlib_canvas(self):
        f = Figure(figsize=(7, 2), dpi=100)
        ax = f.add_subplot(111)
        ax.get_yaxis().set_visible(False)
        f.patch.set_facecolor(self.frame["background"])
        canvas = FigureCanvasTkAgg(f, self.frame)
        canvas.draw()
        canvas.mpl_connect('button_press_event', self.on_plot_click)
        return canvas, f, ax

    def update_plot(self):
        self.plot_axes.clear()
        self.draw_audio_plot(audio.TRIMMED_AUDIO, audio.SAMPLE_RATE)
        self.draw_start_marker()
        self.draw_end_marker()
        self.plot_canvas.draw()

    def on_plot_click(self, event):
        print('start:' + str(self.start_marker_edit.get()))
        print('end:' + str(self.end_marker_edit.get()))
        if self.start_marker_edit.get():
            if event.xdata > self.end_marker_position - 0.01:
                self.start_marker_position = self.end_marker_position - 1
            else:
                self.start_marker_position = event.xdata
        if self.end_marker_edit.get():
            if event.xdata < self.start_marker_position + 0.01:
                self.end_marker_position = self.start_marker_position + 1
            else:
                self.end_marker_position = event.xdata
        self.update_plot()

    def draw_start_marker(self):
        self.plot_axes.axvline(x=self.start_marker_position, color='green')

    def draw_end_marker(self):
        self.plot_axes.axvline(x=self.end_marker_position, color='red')

    def draw_audio_plot(self, signal, sr):
        libdisplay.waveplot(signal, sr, x_axis='time', ax=self.plot_axes)

    def toggle_start_marker_button(self):
        if self.start_marker_button.config('relief')[-1] == 'sunken':
            self.start_marker_button.config(relief="raised")
            self.start_marker_edit.set('false')
        else:
            if self.end_marker_button.config('relief')[-1] == 'sunken':
                self.end_marker_button.config(relief="raised")
                self.end_marker_edit.set('false')
            self.start_marker_button.config(relief="sunken")
            self.start_marker_edit.set('true')

    def toggle_end_marker_button(self):
        if self.end_marker_button.config('relief')[-1] == 'sunken':
            self.end_marker_button.config(relief="raised")
            self.end_marker_edit.set('false')
        else:
            if self.start_marker_button.config('relief')[-1] == 'sunken':
                self.start_marker_button.config(relief="raised")
                self.start_marker_edit.set('false')
            self.end_marker_button.config(relief="sunken")
            self.end_marker_edit.set('true')

    def trim_audio(self):
        audio.trim_audio(self.start_marker_position, self.end_marker_position)
        self.start_marker_position = 0.0
        self.end_marker_position = (len(audio.TRIMMED_AUDIO) + 1.) / audio.SAMPLE_RATE
        self.update_plot()

    def replace_audio(self):
        audio.replace_audio()

    def kill_trim_window(self):
        global trim_window

        trim_window = None
        self.window.destroy()
예제 #18
0
class FrameMapping(FrameCustomItem):
    """Holds and visualizes a Map between two columns of different datasets"""
    row_index = None

    is_key = None
    src_reference = None
    src_datatype = None
    src_cast_to = None
    dest_table = None
    curr_data = None
    curr_raw_data = None
    mapping = None

    preview = None
    dest_reference = None

    def __init__(self, _master, _mapping = None,
                 _on_get_source_references = None,
                 _on_get_destination_references = None,
                 _on_select = None):
        super(FrameMapping, self).__init__(_master)


        # Add monitored variables.
        self.is_key = BooleanVar()
        self.src_reference = StringVar()
        self.src_datatype = StringVar()
        self.curr_data = StringVar()

        self.result_cast_to = StringVar()
        self.preview = StringVar()

        self.dest_reference = StringVar()

        self.on_get_source_references = _on_get_source_references
        self.on_get_destination_references = _on_get_destination_references

        self.on_select = _on_select
        self.init_widgets()

        self.mapping = _mapping



        if _mapping is not None:
            self.mapping_to_gui()


    def mapping_to_gui(self):

        self.src_reference.set(str(empty_when_none(self.mapping.src_reference)))
        self.dest_reference.set(str(empty_when_none(self.mapping.dest_reference)))
        self.src_datatype.set(self.mapping.src_datatype)
        self.is_key.set(bool_to_binary_int(self.mapping.is_key))

    def gui_to_mapping(self):

        self.mapping.src_reference = self.src_reference.get()
        self.mapping.dest_reference = self.dest_reference.get()

        self.mapping.is_key = binary_int_to_bool(self.is_key.get())

    def reload_references(self):
        self.cb_source_ref['values'] = self.get_source_references()
        self.cb_dest_ref['values'] = self.get_destination_references()


    def get_source_references(self, _force = None):
        if self.on_get_source_references:
            return self.on_get_source_references(_force)

    def get_destination_references(self, _force = None):
        if self.on_get_destination_references:
            return self.on_get_destination_references( _force)


    def on_change_source_ref(self, *args):
        # reload dataset.
        pass


    def init_widgets(self):

        """Init all widgets"""

        # Source reference
        self.cb_source_ref = ttk.Combobox(self, textvariable=self.src_reference, state='normal')
        self.cb_source_ref['values'] = self.get_source_references()
        self.cb_source_ref.pack(side=LEFT, fill=X, expand=1)


        # Data type label
        self.l_data_type = ttk.Label(self, textvariable=self.src_datatype, width=8)
        self.src_datatype.set("Not set")

        self.l_data_type.pack(side=LEFT)

        # Dest reference
        self.cb_dest_ref = ttk.Combobox(self, textvariable=self.dest_reference, state='normal')
        self.cb_dest_ref['values'] = self.get_destination_references()
        self.cb_dest_ref.pack(side=RIGHT, fill=X, expand=1)

        # Is key field
        self.cb_is_key = ttk.Checkbutton(self, variable=self.is_key)
        self.cb_is_key.pack(side=RIGHT)

        # Current data
        self.l_data = ttk.Label(self, textvariable=self.curr_data)
        self.curr_data.set("No data")
        self.l_data.pack(side=RIGHT, fill=X, padx=5)
예제 #19
0
    def __init__(self, master, par=False):
        """
        GUI for selecting default parameters - will write parameters to file \
        of users choosing.

        :type master: Tk
        :param master: Tkinter window
        :type par: EQcorrscanParameters
        :param par: Default parameters to start-up with.
        """
        from tkinter import Label, Button, Entry, DoubleVar, StringVar, IntVar
        from tkinter import BooleanVar, OptionMenu, Checkbutton
        import tkMessageBox
        from eqcorrscan.utils import parameters
        from obspy import UTCDateTime
        import warnings

        # Set the default par, only if they don't already exist.
        if not par:
            par = parameters.EQcorrscanParameters([''], 2, 10, 4, 100, 2,
                                                  '1900-01-01', '2300-01-01',
                                                  '', 'seishub', 4, False, '',
                                                  'jpg', False, 8, 'MAD', 6)
        # Callback functions for all variables (ugly)

        def update_template_names(*args):
            par.template_names = [name.strip() for name in
                                  template_names.get().split(',')]
            template_names.set(', '.join(par.template_names))

        def update_lowcut(*args):
            par.lowcut = lowcut.get()
            lowcut.set(par.lowcut)

        def update_highcut(*args):
            par.highcut = highcut.get()
            if par.highcut >= 0.5 * par.samp_rate:
                msg = ('Highcut must be less than the Nyquist, setting to ' +
                       str((par.samp_rate / 2.0) - 1))
                tkMessageBox.showwarning(title="Nyquist error",
                                         message=msg)
                par.highcut = (par.samp_rate / 2.0) - 1
            highcut.set(par.highcut)

        def update_filt_order(*args):
            par.filt_order = filt_order.get()
            filt_order.set(par.filt_order)

        def update_samp_rate(*args):
            par.samp_rate = samp_rate.get()
            if par.highcut >= 0.5 * par.samp_rate:
                msg = ('Highcut must be less than the Nyquist, setting to ' +
                       str((par.samp_rate / 2.0) - 1))
                tkMessageBox.showwarning(title="Nyquist error",
                                         message=msg)
                par.highcut = (par.samp_rate / 2.0) - 1
                highcut.set(par.highcut)
            samp_rate.set(par.samp_rate)

        def update_debug(*args):
            par.debug = debug.get()
            debug.set(par.debug)

        def update_startdate(*args):
            par.startdate = UTCDateTime(startdate.get())
            startdate.set(str(par.startdate))

        def update_enddate(*args):
            par.enddate = UTCDateTime(enddate.get())
            enddate.set(str(par.enddate))

        def update_archive(*args):
            par.archive = archive.get()
            archive.set(par.archive)

        def update_arc_type(*args):
            par.arc_type = arc_type.get()
            arc_type.set(par.arc_type)

        def update_cores(*args):
            par.cores = cores.get()
            cores.set(par.cores)

        def update_plotvar(*args):
            par.plotvar = plotvar.get()
            plotvar.set(par.plotvar)

        def update_plot_format(*args):
            par.plot_format = plot_format.get()
            plot_format.set(par.plot_format)

        def update_tempdir(*args):
            par.tempdir = tempdir.get()
            tempdir.set(par.tempdir)

        def update_threshold(*args):
            par.threshold = threshold.get()
            threshold.set(par.threshold)

        def update_threshold_type(*args):
            par.threshold_type = threshold_type.get()
            threshold_type.set(par.threshold_type)

        def update_plotdir(*args):
            par.plotdir = plotdir.get()
            plotdir.set(par.plotdir)

        def update_trigger_interval(*args):
            par.trigger_interval = trigger_interval.get()
            trigger_interval.set(par.trigger_interval)
        # Set some grid parameters
        nrows = 25
        ncolumns = 3
        self.master = master
        master.title("EQcorrscan parameter setup")
        self.label = Label(master, text="Alpha GUI for default setup")
        self.label.grid(column=0, columnspan=ncolumns, row=0)

        # Set up parameter input
        self.t_names_label = Label(master, text="Template names", anchor='e')
        self.t_names_label.grid(column=0, row=1, sticky='e')
        template_names = StringVar()
        template_names.set(', '.join(par.template_names))
        self.t_names_box = Entry(master, bd=2, textvariable=template_names)
        self.t_names_box.grid(column=1, row=1)
        template_names.trace("w", update_template_names)
        self.t_names_lookup = Button(master, text="Lookup",
                                     command=lambda: self.get_template_names(par))
        self.t_names_lookup.grid(column=2, row=1)

        self.lowcut_label = Label(master, text="Lowcut (Hz)", anchor='e')
        self.lowcut_label.grid(column=0, row=2, sticky='e')
        lowcut = DoubleVar()
        lowcut.set(par.lowcut)
        self.lowcut_box = Entry(master, bd=2, textvariable=lowcut)
        self.lowcut_box.grid(column=1, row=2)
        lowcut.trace("w", update_lowcut)

        self.highcut_label = Label(master, text="Highcut (Hz)", anchor='e')
        self.highcut_label.grid(column=0, row=3, sticky='e')
        highcut = DoubleVar()
        highcut.set(par.highcut)
        self.highcut_box = Entry(master, bd=2, textvariable=highcut)
        self.highcut_box.grid(column=1, row=3)
        highcut.trace("w", update_highcut)

        self.filt_order_label = Label(master, text="Filter order")
        self.filt_order_label.grid(column=0, row=4, sticky='e')
        filt_order = DoubleVar()
        filt_order.set(par.filt_order)
        self.filt_order_box = Entry(master, bd=2, textvariable=filt_order)
        self.filt_order_box.grid(column=1, row=4)
        filt_order.trace("w", update_filt_order)

        self.samp_rate_label = Label(master, text="Sample rate (Hz)")
        self.samp_rate_label.grid(column=0, row=5, sticky='e')
        samp_rate = DoubleVar()
        samp_rate.set(par.samp_rate)
        self.samp_rate_box = Entry(master, bd=2, textvariable=samp_rate)
        self.samp_rate_box.grid(column=1, row=5)
        samp_rate.trace("w", update_samp_rate)

        self.debug_label = Label(master, text="Debug")
        self.debug_label.grid(column=0, row=6, sticky='e')
        debug = IntVar()
        debug.set(par.debug)
        self.debug_box = Entry(master, bd=2, textvariable=debug)
        self.debug_box.grid(column=1, row=6)
        debug.trace("w", update_debug)

        self.startdate_label = Label(master, text="Start date (yyyy-mm-dd)")
        self.startdate_label.grid(column=0, row=6, sticky='e')
        startdate = StringVar()
        startdate.set(par.startdate)
        self.startdate_box = Entry(master, bd=2, textvariable=startdate)
        self.startdate_box.grid(column=1, row=6)
        startdate.trace("w", update_startdate)

        self.enddate_label = Label(master, text="End date (yyyy-mm-dd)")
        self.enddate_label.grid(column=0, row=8, sticky='e')
        enddate = StringVar()
        enddate.set(par.enddate)
        self.enddate_box = Entry(master, bd=2, textvariable=enddate)
        self.enddate_box.grid(column=1, row=8)
        enddate.trace("w", update_enddate)

        self.archive_label = Label(master, text="Archive")
        self.archive_label.grid(column=0, row=9, sticky='e')
        archive = StringVar()
        archive.set(par.archive)
        self.archive_box = Entry(master, bd=2, textvariable=archive)
        self.archive_box.grid(column=1, row=9)
        archive.trace("w", update_archive)
        self.archive_lookup = Button(master, text="Lookup",
                                     command=lambda: self.get_archive(par))
        self.archive_lookup.grid(column=2, row=9)


        self.arc_type_label = Label(master, text="Archive type")
        self.arc_type_label.grid(column=0, row=10, sticky='e')
        arc_type = StringVar()
        arc_type.set(par.arc_type)
        self.arc_type_box = OptionMenu(master, arc_type,
                                       "seishub", "fdsn", "day_vols")
        self.arc_type_box.grid(column=1, row=10, sticky='w,e')
        arc_type.trace("w", update_arc_type)

        self.cores_label = Label(master, text="Number of cores")
        self.cores_label.grid(column=0, row=11, sticky='e')
        cores = IntVar()
        cores.set(par.cores)
        self.cores_box = Entry(master, bd=2, textvariable=cores)
        self.cores_box.grid(column=1, row=11)
        cores.trace("w", update_cores)

        self.plotvar_label = Label(master, text="Plotting on/off")
        self.plotvar_label.grid(column=0, row=12, sticky='e')
        plotvar = BooleanVar()
        plotvar.set(par.plotvar)
        self.plotvar_box = Checkbutton(master, text='Plot on', var=plotvar,
                                       onvalue=True, offvalue=False)
        self.plotvar_box.grid(column=1, row=12)
        plotvar.trace("w", update_plotvar)

        self.plotdir_label = Label(master, text="Plot directory")
        self.plotdir_label.grid(column=0, row=13, sticky='e')
        plotdir = StringVar()
        plotdir.set(par.plotdir)
        self.plotdir_box = Entry(master, bd=2, textvariable=plotdir)
        self.plotdir_box.grid(column=1, row=13)
        plotdir.trace("w", update_plotdir)
        self.plotdir_lookup = Button(master, text="Lookup",
                                     command=lambda: self.get_plotdir(par))
        self.plotdir_lookup.grid(column=2, row=13)

        self.plot_format_label = Label(master, text="Plot format")
        self.plot_format_label.grid(column=0, row=14, sticky='e')
        plot_format = StringVar()
        plot_format.set(par.plot_format)
        self.plot_format_box = OptionMenu(master, plot_format,
                                          "jpg", "eps", "pdf", "png")
        self.plot_format_box.grid(column=1, row=14, sticky='w,e')
        plot_format.trace("w", update_plot_format)

        self.tempdir_label = Label(master, text="Temporary directory")
        self.tempdir_label.grid(column=0, row=15, sticky='e')
        tempdir = StringVar()
        tempdir.set(par.tempdir)
        self.tempdir_box = Entry(master, bd=2, textvariable=tempdir)
        self.tempdir_box.grid(column=1, row=15)
        tempdir.trace("w", update_tempdir)
        self.tempdir_lookup = Button(master, text="Lookup",
                                     command=lambda: self.get_tempdir(par))
        self.tempdir_lookup.grid(column=2, row=15)

        self.threshold_label = Label(master, text="Threshold")
        self.threshold_label.grid(column=0, row=16, sticky='e')
        threshold = DoubleVar()
        threshold.set(par.threshold)
        self.threshold_box = Entry(master, bd=2, textvariable=threshold)
        self.threshold_box.grid(column=1, row=16)
        threshold.trace("w", update_threshold)

        self.threshold_type_label = Label(master, text="Threshold type")
        self.threshold_type_label.grid(column=0, row=17, sticky='e')
        threshold_type = StringVar()
        threshold_type.set(par.threshold_type)
        self.threshold_type_box = OptionMenu(master, threshold_type,
                                             "MAD", "absolute", "av_chan_corr")
        self.threshold_type_box.grid(column=1, row=17, sticky='w,e')
        threshold_type.trace("w", update_threshold_type)

        self.trigger_interval_label = Label(master,
                                            text="Minimum trigger " +
                                            "interval (s)")
        self.trigger_interval_label.grid(column=0, row=18, sticky='e')
        trigger_interval = DoubleVar()
        trigger_interval.set(par.trigger_interval)
        self.trigger_interval_box = Entry(master, bd=2,
                                          textvariable=trigger_interval)
        self.trigger_interval_box.grid(column=1, row=18)
        trigger_interval.trace("w", update_trigger_interval)

        # End of user editable section, now we have read/write buttons
        self.read_button = Button(master, text="Read parameters",
                                  command=lambda: self.read_par(master))
        self.read_button.grid(column=0, row=nrows-2, sticky='w,e')

        self.write_button = Button(master, text="Write parameters",
                                   command=lambda: self.write_par(par))
        self.write_button.grid(column=1, row=nrows-2, sticky='w,e')
예제 #20
0
class ReplicatorMain(VerticalScrolledFrame):
    """The main class for the GUI of the application"""

    merge = None
    """This is the merge object of the application, it holds all settings for the merge operation"""
    filename = None
    """The name of the file containing the merge definition"""
    fr_src_dataset = None
    """The fram of the source dataset, contains a FrameCustomDataset descendant"""
    fr_dest_dataset = None
    """The fram of the source dataset, contains a FrameCustomDataset descendant"""
    suppress_errors = None
    """Do not show any errors"""
    _row_index = None
    """The current row in the dataset"""
    curr_mapping_frame = None
    """The currently selected mapping frame"""

    def __init__(self, _merge=None, _filename=None, *args, **kw):

        self.parent = Tk()

        # Init oneself

        super(ReplicatorMain, self).__init__(self.parent, bd=1, relief=SUNKEN, *args, **kw)
        self.grid(stick=(E, W, N, S))

        self.suppress_errors = None

        self.merge = _merge
        self.filename = _filename

        self.fr_src_dataset = None
        self.fr_dest_dataset = None

        self.grid()
        self.ip_address = StringVar()
        self._row_index = 0
        self.init_GUI()

        if _filename is not None and _merge is not None:
            # _merge._load_datasets()
            self._merge_to_gui()


        self.parent.columnconfigure(0, weight=1)
        self.parent.rowconfigure(0, weight=1)
        self.resize()

        self.parent.mainloop()

    def resize(self):
        """
        Resize the window, set the width what the internal windows need.
        """
        self._canvas.update_idletasks()
        self.fr_top_right.update_idletasks()
        self._canvas.config(width=self.interior.winfo_reqwidth() + 1, height=self.interior.winfo_reqheight())

    def on_dataset_columns_change(self, *args):
        # Columns have changed; force reload columns from structure
        self.fr_src_dataset.get_possible_references(True)
        self.fr_dest_dataset.get_possible_references(True)
        for curr_mapping in self.g_mappings.items:
            curr_mapping.fr_item.reload_references()


    def notify_task(self, _task, _progress):
        """Override as this is the top widget"""
        self.fr_Status_Bar.update_task(_task, _progress)

    def notify_messagebox(self, _title, _message, _kind=None):
        """Override as this is the top class, default is error."""
        if self.suppress_errors is None:
            if _kind == "message":
                messagebox.showinfo(_title, _message)
            elif _kind == "warning":
                messagebox.showwarning(_title, _message)
            else:
                messagebox.showerror(_title, _message)

    def on_post_merge_sql(self, *args):
        # Show post-merge-SQL dialog
        _wdw = Toplevel()
        _wdw.geometry('+400+400')
        _wdw.e = TextExtension(_wdw, textvariable=self.post_execute_sql)
        _wdw.e.pack()
        _wdw.e.focus_set()
        _wdw.transient(self.parent)
        _wdw.grab_set()
        self.parent.wait_window(_wdw)
        _wdw.e.unhook()
        del (_wdw)


    def on_src_connect(self, *args):
        """Event handler for when the source connection is set"""
        self.fr_mapping.src_dal = self.fr_dataset_src.dal

    def on_dest_connect(self, *args):
        """Event handler for when the destination connection is set"""
        self.fr_mapping.dest_dal = self.fr_dataset_dest.dal

    def init_GUI(self):
        """Init main application GUI"""
        print("Initializing GUI...", end="")

        self.parent.title("Optimal Sync - Move that data - a part of Optimal BPM")
        self.interior.notify_task = self.notify_task
        self.interior.notify_messagebox = self.notify_messagebox

        self.fr_top = BPMFrame(self.interior)
        self.fr_top.pack(side=TOP, fill=BOTH, expand=1)

        self.fr_top_left = BPMFrame(self.fr_top)
        self.fr_top_left.pack(side=LEFT, fill=BOTH, expand=1)

        self.fr_rw = BPMFrame(self.fr_top_left)
        self.fr_rw.pack(side=TOP, fill=X)

        self.btn_Load_json_json = ttk.Button(self.fr_rw, text="Load", command=self.on_load_json)
        self.btn_Load_json_json.pack(side=LEFT)
        self.btn_Save_json = ttk.Button(self.fr_rw, text="Save", command=self.on_save_json)
        self.btn_Save_json.pack(side=LEFT)
        self.fr_subnet_sql = BPMFrame(self.fr_rw)
        self.l_ip = ttk.Label(self.fr_subnet_sql, text="IP(for subnet scan):")
        self.l_ip.pack(side=LEFT)
        self.ip_address.set("192.168.0.1")
        self.e_ip_address = ttk.Entry(self.fr_subnet_sql, textvariable=self.ip_address)
        self.e_ip_address.pack(side=RIGHT)
        self.fr_subnet_sql.pack(side=RIGHT)

        # datasets

        self.fr_datasets = BPMFrame(self.fr_top_left)
        self.fr_datasets.pack(side=TOP)

        self.sel_src_dataset_type = Selector(_master=self.fr_datasets,
                                             _values=('RDBMS', 'XPath', 'Flatfile', 'Spreadsheet'),
                                             _caption="Sources dataset type:",
                                             _onchange=self.on_src_dataset_type_change)
        self.sel_src_dataset_type.grid(column=0, row=0, sticky=W)

        self.sel_dest_dataset_type = Selector(_master=self.fr_datasets,
                                              _values=('RDBMS', 'XPath', 'Flatfile', 'Spreadsheet'),
                                              _caption="Destination dataset type:",
                                              _onchange=self.on_dest_dataset_type_change)
        self.sel_dest_dataset_type.grid(column=1, row=0, sticky=W)


        # Mappings

        self.fr_mapping_header = BPMFrame(self.fr_top_left)
        self.fr_mapping_header.pack(side=TOP)

        self.l_mapping = ttk.Label(self.fr_mapping_header, text="Mappings:")
        self.l_mapping.pack(side=TOP)

        self.fr_mapping_header_nav = BPMFrame(self.fr_mapping_header)
        self.fr_mapping_header_nav.pack(side=BOTTOM)

        self.btn_first = Button(self.fr_mapping_header_nav, text="<<", command=self.on_first)
        self.btn_first.pack(side=LEFT)
        self.btn_prev = Button(self.fr_mapping_header_nav, text="<", command=self.on_prev)
        self.btn_prev.pack(side=LEFT)

        self.btn_reload = Button(self.fr_mapping_header_nav, text="Reload data", command=self.on_reload_data)
        self.btn_reload.pack(side=LEFT)

        self.btn_next = Button(self.fr_mapping_header_nav, text=">", command=self.on_next)
        self.btn_next.pack(side=LEFT)
        self.btn_last = Button(self.fr_mapping_header_nav, text=">>", command=self.on_last)
        self.btn_last.pack(side=LEFT)

        self.g_mappings = FrameList(self.fr_top_left, _detail_key_text="Transformations >>", bd=1, relief=SUNKEN)
        self.g_mappings.pack(side=TOP, fill=X)
        self.g_mappings.on_delete = self.mappings_do_on_delete
        self.g_mappings.on_move_up = self.mappings_do_on_move_up
        self.g_mappings.on_move_down = self.mappings_do_on_move_down
        self.g_mappings.on_detail = self.mappings_do_on_detail

        self.btn_append_mapping = Button(self.fr_top_left, text="Append mapping", command=self.on_append_mapping)
        self.btn_append_mapping.pack(side=TOP)

        # Transformation
        self.fr_top_right = BPMFrame(self.fr_top)
        self.fr_top_right.pack(side=RIGHT, fill=Y)

        self.l_transformations = ttk.Label(self.fr_top_right, text="Transformations")
        self.l_transformations.pack(side=TOP)

        self.g_transformations = FrameList(self.fr_top_right, bd=1, relief=SUNKEN)
        self.g_transformations.pack(fill=BOTH, expand=1)
        self.g_transformations.on_delete = self.transformations_do_on_delete
        self.g_transformations.on_move_up = self.transformations_do_on_move_up
        self.g_transformations.on_move_down = self.transformations_do_on_move_down

        self.fr_append_transformation = ttk.Frame(self.fr_top_right)
        self.fr_append_transformation.pack(side=BOTTOM)

        self.btn_append_transformation = Button(self.fr_append_transformation, text="Append Transformation",
                                                command=self.on_append_transformation)
        self.btn_append_transformation.pack(side=LEFT)

        self.transformation_append_type = StringVar()
        self.sel_transformation_append_type = ttk.Combobox(self.fr_append_transformation,
                                                           textvariable=self.transformation_append_type,
                                                           state='readonly')
        self.sel_transformation_append_type['values'] = ["Replace", "Replace regex", "Cast", "If empty", "Trim"]
        self.sel_transformation_append_type.current(0)
        self.sel_transformation_append_type.pack(side=LEFT, fill=X)

        # Merge preview
        self.fr_Preview = ttk.Frame(self.fr_top_left)
        self.fr_Preview.pack(side=TOP, fill=BOTH, expand=1)

        self.fr_merge_actions = ttk.Frame(self.fr_Preview)
        self.fr_merge_actions.pack(side=TOP, fill=X)

        self.btn_execute_preview = Button(self.fr_merge_actions, text="Preview merge", command=self.on_preview_merge)
        self.btn_execute_preview.pack(side=LEFT)
        self.btn_execute_preview = Button(self.fr_merge_actions, text="Commit merge", command=self.on_commit_merge)
        self.btn_execute_preview.pack(side=LEFT)

        # Update
        self.merge_update = BooleanVar()
        self.e_merge_update = ttk.Checkbutton(self.fr_merge_actions, variable=self.merge_update)
        self.e_merge_update.pack(side=RIGHT)
        self.l_merge_update = ttk.Label(self.fr_merge_actions, text="Update: ")
        self.l_merge_update.pack(side=RIGHT)

        # Insert

        self.merge_insert = BooleanVar()
        self.e_merge_insert = ttk.Checkbutton(self.fr_merge_actions, variable=self.merge_insert)
        self.e_merge_insert.pack(side=RIGHT)
        self.l_merge_insert = ttk.Label(self.fr_merge_actions, text="Insert: ")
        self.l_merge_insert.pack(side=RIGHT)

        # Delete
        self.merge_delete = BooleanVar()
        self.e_merge_delete = ttk.Checkbutton(self.fr_merge_actions, variable=self.merge_delete)
        self.e_merge_delete.pack(side=RIGHT)
        self.l_merge_delete = ttk.Label(self.fr_merge_actions, text="Delete: ")
        self.l_merge_delete.pack(side=RIGHT)

        # Set post-merge SQL
        self.post_execute_sql = StringVar()
        self.btn_Post_Merge_SQL = ttk.Button(self.fr_merge_actions, text="Set post-merge SQL",
                                             command=self.on_post_merge_sql)
        self.btn_Post_Merge_SQL.pack(side=RIGHT, padx=30)

        # Preview
        self.gr_preview = ttk.Treeview(self.fr_Preview, columns=('size', 'modified'))
        self.gr_preview.pack(side=TOP, fill=BOTH, expand=1)
        self.gr_preview.bind("<<TreeviewSelect>>", self.on_preview_selected)
        self.preview_detail = StringVar()
        self.e_previev_detail = ttk.Entry(self.fr_Preview, textvariable=self.preview_detail)
        self.e_previev_detail.pack(side=BOTTOM, fill=X, expand=0)

        self.fr_bottom = BPMFrame(self.interior)
        self.fr_bottom.pack(side=BOTTOM, fill=X)

        self.fr_Status_Bar = Status_Bar(self.fr_bottom)
        self.fr_Status_Bar.pack(fill=X)

        print("done.")

    # #########################################################################
    # This section contains functions handling the entire merge(load/save/GUI)
    # #########################################################################

    def _merge_to_gui(self):
        """
        Populate the GUI from the merge class.
        """
        if self.fr_src_dataset is not None:
            self.fr_src_dataset.destroy()
        _src_type = self.dataset_instance_to_dataset_type(self.merge.source)
        self.sel_src_dataset_type.set_but_do_not_propagate(_src_type)
        self.fr_src_dataset = self.dataset_frame_factory(_dataset=self.merge.source, _is_destination=False)
        self.fr_src_dataset.grid(column=0, row=1)

        if self.fr_dest_dataset is not None:
            self.fr_dest_dataset.destroy()

        _dest_type = self.dataset_instance_to_dataset_type(self.merge.destination)
        self.sel_dest_dataset_type.set_but_do_not_propagate(_dest_type)
        self.fr_dest_dataset = self.dataset_frame_factory(_dataset=self.merge.destination, _is_destination=False)
        self.fr_dest_dataset.grid(column=1, row=1)

        self.mappings_to_gui()

        self.merge_insert.set(bool_to_binary_int(self.merge.insert))
        self.merge_delete.set(bool_to_binary_int(self.merge.delete))
        self.merge_update.set(bool_to_binary_int(self.merge.update))
        if self.merge.post_execute_sql is None:
            self.post_execute_sql.set("")
        else:
            self.post_execute_sql.set(self.merge.post_execute_sql)

        # Hereafter, update column list when they change
        self.fr_src_dataset.on_columns_change = self.on_dataset_columns_change
        self.fr_dest_dataset.on_columns_change = self.on_dataset_columns_change

    def _gui_to_merge(self):
        """Copy the data from the GUI to the merge object"""
        self.fr_src_dataset.write_to_dataset()
        self.merge.source = self.fr_src_dataset.dataset
        self.fr_dest_dataset.write_to_dataset()
        self.merge.destination = self.fr_dest_dataset.dataset

        self.gui_to_mappings()

        self.merge.insert = binary_int_to_bool(self.merge_insert.get())
        self.merge.delete = binary_int_to_bool(self.merge_delete.get())
        self.merge.update = binary_int_to_bool(self.merge_update.get())
        self.merge.post_execute_sql = self.post_execute_sql.get()

    def load_json(self, _filename):
        """Load an JSON into the merge object, and populate the GUI"""
        with open(_filename, "r") as _f:
            _json = json.load(_f)

        self.filename = _filename

        self.notify_task('Loading transformation..', 0)
        self.merge = Merge(_json=_json, _base_path=os.path.dirname(_filename))
        try:
            self.merge._load_datasets()
        except Exception as e:
            self.notify_messagebox("Error loading data", str(e))
            # Supress the following errors. There is no real errors that matters.
            self.suppress_errors = True
        self._merge_to_gui()
        self.suppress_errors = None
        self.notify_task('Loading transformation..done', 100)
        self.resize()


    def on_save_json(self, *args):
        """Triggered when save-button is clicked.
        Displays a save dialog, fetches GUI data into merge, and saves as JSON into the selected file."""
        self.notify_task('Saving..', 0)
        _filename = filedialog.asksaveasfilename(initialfile= self.filename, defaultextension=".json",
                                                 filetypes=[('JSON files', '.json'), ('all files', '.*')],
                                                 title="Choose location")
        if _filename:
            self._gui_to_merge()
            self.notify_task('Saving(Generating JS)..', 0)
            _json = self.merge.as_json()
            self.notify_task('Saving(Writing file)..', 50)
            with open (_filename, "w") as _f:
                json.dump(_json, fp=_f, sort_keys=True, indent=4)

            self.notify_task('Saving..done.', 100)
        else:
            self.notify_task('Saving cancelled.', 0)


    def on_load_json(self, *args):
        """Triggered when load-button is clicked.
        Displays a load dialog, clears the GUI, populates the merge and uppdates the GUI"""
        _filename = filedialog.askopenfilename(defaultextension=".json",
                                               filetypes=[('JSON files', '.json'), ('all files', '.*')],
                                               title="Choose file")
        if _filename:
            self.g_transformations.clear()
            self.g_mappings.clear()
            self.clear_preview()
            self.curr_mapping_frame = None
            self._row_index = 0
            self.load_json(_filename)

    def check_prerequisites_for_reload(self):
        """Can a reload be made using the current settings? If not, display cause in status field"""

        if self.fr_src_dataset is None:
            self.notify_task("Cannot reload: Source dataset must be specified.", 0)
            return False
        elif self.fr_dest_dataset is None:
            self.notify_task("Cannot reload: Destination dataset must be specified.", 0)
            return False
        _tmp = self.fr_src_dataset.check_reload()
        if _tmp:
            self.notify_task("Cannot reload source: " + _tmp, 0)
            return False
        _tmp = self.fr_dest_dataset.check_reload()
        if _tmp:
            self.notify_task("Cannot reload destination: " + _tmp, 0)
            return False
        else:
            return True


    def update_data(self, _refresh=None):
        """
        Reload all data into the GUI
        :param _refresh: Force reload of datasets
        :return:
        """

        if self.check_prerequisites_for_reload() is False:
            return

        self.notify_task("", 0)
        if len(self.merge.source.data_table) == 0 or _refresh:
            # Update settings
            self._gui_to_merge()

            # Update XPath references especially, since it addresses an XML structure, not a dataset.
            if isinstance(self.merge.source, XpathDataset):
                self.merge.source.field_xpaths = []
                self.merge.source.field_names = []
                for _curr_mapping_idx in range(0, len(self.g_mappings.items)):
                    self.merge.source.field_xpaths.append(
                        self.g_mappings.items[_curr_mapping_idx].fr_item.src_reference.get())
                    self.merge.source.field_names.append(
                        self.g_mappings.items[_curr_mapping_idx].fr_item.src_reference.get())

            self.merge.source.load()
        # Reset identity values
        self.reset_substitions_identity()
        # Is there any data?
        if len(self.merge.source.data_table) > 0:
            # Try to retain the approximate position in the table.
            if self._row_index < 0:
                self._row_index = 0
            elif self._row_index > len(self.merge.source.data_table) - 1:
                self._row_index = len(self.merge.source.data_table) - 1
            # Loop through mappings, update data and perform transformations
            # TODO: This certainly doesn't seem to belong here, should be extracted
            for _curr_mapping_idx in range(0, len(self.g_mappings.items)):
                _curr_frame = self.g_mappings.items[_curr_mapping_idx].fr_item
                _curr_frame.hide_error()
                _src_ref = _curr_frame.src_reference.get()
                try:
                    if isinstance(self.merge.source, XpathDataset):
                        _col_idx = self.merge.source.field_xpaths.index(_src_ref)
                    else:
                        _col_idx = self.merge.source.field_names.index(_src_ref)
                except ValueError:
                    _col_idx = -1

                if _col_idx > -1:
                    _curr_frame.curr_raw_data = self.merge.source.data_table[self._row_index][_col_idx]
                    try:
                        perform_transformations(_input=_curr_frame.curr_raw_data,
                                                _transformations=_curr_frame.mapping.transformations)
                    except Exception as e:
                        self.notify_task(
                            'Error in one of the transformations, mapping: ' + _src_ref + " error: " + str(e), 0)

                    _curr_frame.curr_data.set(str(_curr_frame.curr_raw_data))

                else:
                    _curr_frame.show_error(_msg="No mapping")
                    _curr_frame.curr_data.set("")

                    try:
                        _curr_frame.curr_raw_data = perform_transformations(_input=None,
                                                                            _transformations=
                                                                            _curr_frame.mapping.transformations)
                    except Exception as e:
                        self.notify_task(
                            'Error in one of the transformations, mapping: ' + _curr_frame.dest_reference.get() +
                            " error: " + str(e), 0)

                    _curr_frame.curr_data.set(str(_curr_frame.curr_raw_data))

                self.g_mappings.items[_curr_mapping_idx].fr_item.reload_references()


    # #########################################################
    # The following events deals with navigating the active dataset
    ##########################################################
    def on_prev(self):
        """Triggered when the "<"-button is pressed."""
        self._row_index -= 1
        self.update_data()

    def on_next(self):
        """Triggered when the ">"-button is pressed."""
        self._row_index += 1
        self.update_data()

    def on_reload_data(self):
        """Triggered when the "Reload data"-button is pressed."""
        self.update_data(_refresh=True)

    def on_first(self):
        """Triggered when the "<<"-button is pressed."""
        self._row_index = 0
        self.update_data()

    def on_last(self):
        """Triggered when the ">>!-button is pressed."""
        if len(self.merge.source.data_table) == 0:
            self.merge.source.load()
        self._row_index = len(self.merge.source.data_table) - 1
        self.update_data()

    def dataset_instance_to_dataset_type(self, _dataset):
        """
        Identify an instance of a dataset and return a string description.
        Used in the dataset type selector.
        :param _dataset: The dataset to identify
        """
        if isinstance(_dataset, RDBMSDataset):
            return "RDBMS"
        elif isinstance(_dataset, XpathDataset):
            return "XPATH"
        elif isinstance(_dataset, FlatfileDataset):
            return "FLATFILE"
        elif isinstance(_dataset, SpreadsheetDataset):
            return "SPREADSHEET"
        else:
            raise Exception("Internal error, unsupported dataset instance type: " + str(_dataset))

    def dataset_frame_factory(self, _dataset=None, _dataset_type=None, _is_destination=False):
        """
        This is a factory function for creating matching frames(visual property editors) for the dataset classes.
        :param _dataset: The dataset, if existing.
        :param _dataset_type: The dataset type string representation ("RDBMS", and so on)
        """
        if _dataset:
            _dataset_type = self.dataset_instance_to_dataset_type(_dataset)

        if _dataset_type == "RDBMS":
            _tmp = FrameRDBMSDataset(self.fr_datasets, _dataset=_dataset, _relief=SUNKEN,
                                     _is_destination=_is_destination)
            _tmp.subnet_ip = self.ip_address
        elif _dataset_type == "FLATFILE":
            _tmp = FrameFlatfileDataset(self.fr_datasets, _dataset=_dataset, _relief=SUNKEN,
                                        _is_destination=_is_destination)
        elif _dataset_type == "XPATH":
            _tmp = FrameXPathDataset(self.fr_datasets, _dataset=_dataset, _relief=SUNKEN,
                                     _is_destination=_is_destination)
        elif _dataset_type == "SPREADSHEET":
            _tmp = FrameSpreadsheetDataset(self.fr_datasets, _dataset=_dataset, _relief=SUNKEN,
                                           _is_destination=_is_destination)
        else:
            raise Exception("Internal error, unsupported dataset type: " + str(_dataset_type))
        if self.filename is not None:
            _tmp.base_path = os.path.dirname(self.filename)
        return _tmp


    def on_src_dataset_type_change(self, _current_value):
        """
        Triggered when a user selects a different dataset type for the source dataset
        :param _current_value: A string describing what dataset type has been selected.
        """
        if self.fr_src_dataset is not None:
            self.fr_src_dataset.destroy()
        self.fr_src_dataset = self.dataset_frame_factory(_dataset_type=_current_value.upper(), _is_destination=False)
        self.merge.source = self.fr_src_dataset.dataset
        self.fr_src_dataset.grid(column=0, row=1)

    def on_dest_dataset_type_change(self, _current_value):
        """
        Triggered when a user selects a different dataset type for the destination dataset
        :param _current_value: A string describing what dataset type has been selected.
        """
        if self.fr_dest_dataset is not None:
            self.fr_dest_dataset.destroy()
        self.fr_dest_dataset = self.dataset_frame_factory(_dataset_type=_current_value.upper(), _is_destination=True)
        self.merge.destination = self.fr_dest_dataset.dataset
        self.fr_dest_dataset.grid(column=1, row=1)

    def get_source_references(self, _force=None):
        """
        Returns the possible field references from the source dataset
        :param _force: If True, forces a reload of the underlying dataset.
        """
        if self.fr_src_dataset is not None:
            try:
                return self.fr_src_dataset.get_possible_references(_force)
            except Exception as e:
                self.notify_messagebox(_title="Failed refreshing source references", _message="Error: " + str(e),
                                       _kind="warning")
                return []


    def get_destination_references(self, _force=None):
        """
        Returns the possible field references from the destination dataset
        :param _force: If True, forces a reload of the underlying dataset.
        """
        if self.fr_dest_dataset is not None:
            try:
                return self.fr_dest_dataset.get_possible_references(_force)
            except Exception as e:
                self.notify_messagebox(_title="Failed refreshing destination references", _message="Error: " + str(e),
                                       _kind="warning")
                return []


    ##########################################################
    # This section contains functions handling field mappings
    ##########################################################
    def mappings_to_gui(self):
        """Populates the GUI from the mappings list of the merge object"""

        self.g_mappings.clear()
        for _curr_mapping in self.merge.mappings:
            _new_item = self.g_mappings.append_item()
            _new_item.make_item(_class=FrameMapping, _mapping=_curr_mapping,
                                _on_get_source_references=self.get_source_references,
                                _on_get_destination_references=self.get_destination_references)


    def gui_to_mappings(self):
        """Gathers data from GUI into the mappings list of the merge object"""

        self.gui_to_transformations()
        for _curr_mapping in self.g_mappings.items:
            _curr_mapping.fr_item.gui_to_mapping()

        self.merge._mappings_to_fields(self.merge.source, _use_dest=False)
        self.merge._mappings_to_fields(self.merge.destination, _use_dest=True)


    def mappings_do_on_delete(self, _g_mappings, _item_frame):
        """Triggered if the "del"-button has been clicked"""
        self.merge.mappings.remove(_item_frame.fr_item.mapping)

    def mappings_do_on_move_up(self, _g_mappings, _item_frame):
        """Triggered if the up arrow-button has been clicked"""
        _curr_idx = self.merge.mappings.index(_item_frame.fr_item.mapping)
        self.merge.mappings.insert(_curr_idx - 1, self.merge.mappings.pop(_curr_idx))

    def mappings_do_on_move_down(self, _g_mappings, _item_frame):
        """Triggered if the down arrow-button has been clicked"""
        _curr_idx = self.merge.mappings.index(_item_frame.fr_item.mapping)
        self.merge.mappings.insert(_curr_idx + 1, self.merge.mappings.pop(_curr_idx))

    def on_append_mapping(self, *args):
        """Triggered if the "Append mapping"-button has been clicked."""
        _new_mapping = Mapping()
        self.merge.mappings.append(_new_mapping)
        _new_item = self.g_mappings.append_item()
        _new_item.make_item(_class=FrameMapping, _mapping=_new_mapping,
                            _on_get_source_references=self.get_source_references,
                            _on_get_destination_references=self.get_destination_references)


    def mappings_do_on_detail(self, _g_mappings, _item_frame):
        self.notify_task("", 0)
        if self.curr_mapping_frame:
            self.gui_to_transformations()
        self.g_transformations.clear()
        for _curr_transformation in _item_frame.fr_item.mapping.transformations:

            _frame_class = self._transformation_frame_class_lookup(_curr_transformation)
            if _frame_class:
                _new_item = self.g_transformations.append_item()
                _new_item.make_item(_class=_frame_class, _transformation=_curr_transformation)
        _item_frame['background'] = "dark grey"

        try:
            if _item_frame.fr_item.curr_raw_data is not None:
                perform_transformations(_input=_item_frame.fr_item.curr_raw_data,
                                        _transformations=_item_frame.fr_item.mapping.transformations)
        except Exception as e:
            self.notify_task(
                'Error in one of the transformations, mapping: ' + _item_frame.fr_item.mapping.src_reference + " error: " + str(
                    e), 0)

        if self.curr_mapping_frame:
            try:
                self.curr_mapping_frame['background'] = self['background']
            except Exception as e:
                raise Exception("Error setting background to: " + self['background'] + ":" + str(e))
        self.curr_mapping_frame = _item_frame

    ##########################################################
    # This section contains functions handling transformations
    ##########################################################
    def gui_to_transformations(self):
        """Gathers data from GUI into the transformation objects"""

        for _curr_transformation in self.g_transformations.items:
            _curr_transformation.fr_item.gui_to_transformation()


    def _transformation_frame_class_lookup(self, _transformation=None, _type=None):
        if _type is None:
            _type, _desc = transformation_to_type(_transformation)

        if _type == "Cast":
            return FrameTransformationCast
        if _type == "Trim":
            return FrameTransformationTrim
        if _type == "If empty":
            return FrameTransformationIfEmpty
        if _type == "Replace":
            return FrameTransformationReplace
        if _type == "Replace regex":
            return FrameTransformationReplaceRegex
        else:
            return None
            #raise Exception("Internal error, unsupported transformation type: " + str(_transformation_type))

    def transformations_do_on_delete(self, _g_transformations, _item_frame):
        self.curr_mapping_frame.fr_item.mapping.transformations.remove(_item_frame.fr_item.transformation)

    def transformations_do_on_move_up(self, _g_transformations, _item_frame):
        _curr_transformations = self.curr_mapping_frame.fr_item.mapping.transformations
        _curr_idx = _curr_transformations.index(_item_frame.fr_item.transformation)
        _curr_transformations.insert(_curr_idx - 1,
                                     _curr_transformations.pop(
                                         _curr_idx))

    def transformations_do_on_move_down(self, _g_transformations, _item_frame):
        _curr_transformations = self.curr_mapping_frame.fr_item.mapping.transformations
        _curr_idx = _curr_transformations.index(_item_frame.fr_item.transformation)
        _curr_transformations.insert(_curr_idx + 1,
                                     _curr_transformations.pop(
                                         _curr_idx))

    def on_append_transformation(self, *args):
        if self.curr_mapping_frame is not None:
            _new_transformation = type_to_transformation(self.sel_transformation_append_type.get())(
                _substitution=self.curr_mapping_frame.fr_item.mapping.substitution)
            self.curr_mapping_frame.fr_item.mapping.transformations.append(_new_transformation)
            _frame_class = self._transformation_frame_class_lookup(_new_transformation)
            if _frame_class:
                _new_item = self.g_transformations.append_item()
                _new_item.make_item(_class=_frame_class, _transformation=_new_transformation)

    def clear_transformation_events(self):
        for _curr_mapping in self.merge.mappings:
            for _curr_transformation in _curr_mapping.transformations:
                _curr_transformation.on_done = None

    ############################################################
    # This section contains functions handling the merge preview
    ############################################################

    def clear_preview(self):
        for _curr_item in self.gr_preview.get_children():
            self.gr_preview.delete(_curr_item)

    def reset_substitions_identity(self):
        """Reset substitions"""

        for _curr_mapping in self.merge.mappings:
            _curr_mapping.substitution.set_identity(0)

    def on_preview_merge(self, *args):
        self.do_merge(_commit=False)

    def on_commit_merge(self, *args):
        if askokcancel(title="Warning: committing merge", message="This will commit actual changes to the destination, "
                                                                  "do you want to proceed?") is True:
            self.do_merge(_commit=True)

    def do_merge(self, _commit=False):
        self._gui_to_merge()
        self.update_data(_refresh=True)
        self.merge.destination_log_level = DATASET_LOGLEVEL_DETAIL
        # Clear GUI events
        self.clear_transformation_events()
        self.merge.clear_log()
        try:
            _data_table, _log, _deletes, _inserts, _updates = self.merge.execute(_commit=_commit)
        except Exception as e:
            self.notify_messagebox("Error while merging", str(e))
            return

        # Call columns src/dest field names if they differ

        if len(self.merge.key_fields) > 0:
            _key_field = self.merge.key_fields[0]
        else:
            _key_field = 0

        self.clear_preview()

        self.gr_preview["columns"] = ["Change_Data"]
        self.gr_preview.column("Change_Data", width=500)

        self.gr_preview.heading("Change_Data", text="Change/Data")

        # Add a main for each action

        # Add deletes
        self.gr_preview.insert(parent="", index="end", iid="obpm_deletes", text="Deletes")
        if self.merge.delete:
            for _curr_row in _deletes:
                _curr_item_idx = self.gr_preview.insert(parent="obpm_deletes", index="end", iid="",
                                                        text=_curr_row[2][_key_field])
                _curr_value = ",".join([str(_item) for _item in _curr_row[2]])
                self.gr_preview.item(_curr_item_idx, values=[_curr_value])
                for _curr_column_idx in range(len(_curr_row[2])):
                    _curr_change_item_idx = self.gr_preview.insert(parent=_curr_item_idx, index="end", iid="", text=str(
                        self.merge.destination.field_names[_curr_column_idx]))
                    self.gr_preview.item(_curr_change_item_idx, values=[str(_curr_row[2][_curr_column_idx])])
        # Add inserts
        self.gr_preview.insert(parent="", index="end", iid="obpm_inserts", text="Inserts")
        if self.merge.insert:
            for _curr_row in _inserts:
                _curr_item_idx = self.gr_preview.insert(parent="obpm_inserts", index="end", iid="",
                                                        text=_curr_row[2][_key_field])
                _curr_value = ",".join([str(_item) for _item in _curr_row[2]])
                self.gr_preview.item(_curr_item_idx, values=[_curr_value])
                for _curr_column_idx in range(len(_curr_row[2])):
                    _curr_change_item_idx = self.gr_preview.insert(parent=_curr_item_idx, index="end", iid="", text=str(
                        self.merge.destination.field_names[_curr_column_idx]))
                    self.gr_preview.item(_curr_change_item_idx, values=[str(_curr_row[2][_curr_column_idx])])
        # Add updates
        self.gr_preview.insert(parent="", index="end", iid="obpm_updates", text="Updates")
        if self.merge.update:
            for _curr_row in _updates:
                _curr_item_idx = self.gr_preview.insert(parent="obpm_updates", index="end", iid="",
                                                        text=_curr_row[2][_key_field])
                _changes = []
                for _curr_column_idx in range(len(_curr_row[2])):
                    if _curr_row[2][_curr_column_idx] != _curr_row[3][_curr_column_idx]:
                        _curr_change_item_idx = self.gr_preview.insert(parent=_curr_item_idx, index="end", iid="",
                                                                       text=str(self.merge.destination.field_names[
                                                                           _curr_column_idx]))
                        self.gr_preview.item(_curr_change_item_idx, values=[
                            str(_curr_row[3][_curr_column_idx]) + "=>" + str(_curr_row[2][_curr_column_idx])])
                        _changes.append(str(self.merge.destination.field_names[_curr_column_idx]))
                _curr_value = ",".join([str(_item) for _item in _changes])
                self.gr_preview.item(_curr_item_idx, values=[_curr_value])

        # Add log
        self.gr_preview.insert(parent="", index="end", iid="obpm_log", text="Log")
        if _log is not None:
            for _curr_row in _log:
                _log_fields = _curr_row.split(";")
                _curr_item_idx = self.gr_preview.insert(parent="obpm_log", index="end", iid="", text=_log_fields[0])
                _curr_value = ",".join([unquote(str(_item)) for _item in _log_fields[1:]])
                self.gr_preview.item(_curr_item_idx, values=[_curr_value])

        # Add data table

        self.gr_preview.insert(parent="", index="end", iid="obpm_data_table", text="Result")
        if _data_table is not None:
            for _curr_row in _data_table:
                _curr_item_idx = self.gr_preview.insert(parent="obpm_data_table", index="end", iid="",
                                                        text=_curr_row[_key_field])
                _curr_value = ",".join([str(_item) for _item in _curr_row])
                self.gr_preview.item(_curr_item_idx, values=[_curr_value])
                for _curr_column_idx in range(len(_curr_row)):
                    _curr_change_item_idx = self.gr_preview.insert(parent=_curr_item_idx, index="end", iid="", text=str(
                        self.merge.destination.field_names[_curr_column_idx]))
                    self.gr_preview.item(_curr_change_item_idx, values=[str(_curr_row[_curr_column_idx])])
        if _commit == True:
            _simulation_expression = "Merge"
        else:
            _simulation_expression = "Simulated merge"

        if not (self.merge.insert or self.merge.delete or self.merge.update):
            self.notify_task(
                _simulation_expression + " done. (Expecting merge results? Neither insert, delete or update is selected)",
                100)
        else:
            self.notify_task(_simulation_expression + " done.", 100)

    def on_preview_selected(self, *args):
        _selection = self.gr_preview.selection()
        if len(_selection) > 0:
            _item = self.gr_preview.item(_selection[0])
            self.preview_detail.set(str(",".join([str(_item) for _item in _item["values"]])))
예제 #21
0
class Plastey(Tk):

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def __init__(self, *args, **kwargs):
        Tk.__init__(self, *args, **kwargs)

        # Set window title
        self.wm_title('Plastey Configurator')

        # Create GUI driven variables
        self._mode       = BooleanVar()
        self._base       = BooleanVar()
        self._comm       = BooleanVar()
        self._pass       = StringVar()
        self._addressed  = StringVar()
        self._connected  = StringVar()
        self._this_host  = StringVar()
        self._this_port  = StringVar()
        self._other_host = StringVar()
        self._other_port = StringVar()

        # Create GUI
        self._build_gui()

        # Set default values for GUI driven variables
        self._mode.set(MODE_SINGLE_PLAYER)
        self._base.set(BASE_OPENED_GEOMETRY)
        self._comm.set(COMM_SOCKET_SERVER)
        self._pass.set('')
        self._addressed.set(ADDR_HAVE_ADDRESS if check(COMM_THIS_HOST) else ADDR_NO_ADDRESS)
        self._connected.set(CONN_NOT_CONNECTED)
        self._this_host.set(COMM_THIS_HOST)
        self._this_port.set(COMM_THIS_PORT)
        self._other_host.set(COMM_THIS_HOST)
        self._other_port.set(COMM_OTHER_PORT)

        # Follow changes on password
        self._pass.trace('w', self._on_bind_address)

        # Create folder structures if they don't exists yet
        makedirs(FILE_TEMPORARY_FOLDER,  exist_ok=True)
        makedirs(FILE_PERMANENT_FOLDER,  exist_ok=True)
        makedirs(FILE_TEMP_SAVE_FOLDER,  exist_ok=True)
        makedirs(FILE_AUTO_SAVE_FOLDER,  exist_ok=True)
        #makedirs(FILE_TEMP_STATE_FOLDER, exist_ok=True)
        #makedirs(FILE_TEMP_FEEDS_FOLDER, exist_ok=True)


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _build_gui(self):
        # Create GUI sections
        row = 0
        col = 0

        # Warning text
        Label(master  = self,
              text    = WARN_TEXT,
              anchor  = WEST,
              justify = CENTER).grid(row     = row,
                                     column  = col,
                                     sticky  = NORTH_WEST,
                                     rowspan = 16)

        # Set column spacing
        self.columnconfigure(index = col,
                             pad   = GUI_SECTION_PAD_X)
        row  = 0
        col += 1

        # Game mode options
        Label(master = self,
              text   = 'Game Mode:').grid(row    = row,
                                          column = col,
                                          sticky = WEST)
        row += 1
        Radiobutton(master   = self,
                    text     = 'Single Player',
                    value    = MODE_SINGLE_PLAYER,
                    variable = self._mode).grid(row    = row,
                                                column = col,
                                                sticky = WEST)
        row += 1
        Radiobutton(master   = self,
                    text     = 'Multi Player',
                    value    = MODE_MULTI_PLAYER,
                    variable = self._mode).grid(row    = row,
                                                column = col,
                                                sticky = WEST)
        row += 1

        # Base object modes
        Label(master = self,
              text   = 'Base Object:').grid(row    = row,
                                            column = col,
                                            sticky = WEST)
        row += 1
        Radiobutton(master   = self,
                    text     = 'Plane mesh',
                    value    = BASE_OPENED_GEOMETRY,
                    variable = self._base).grid(row    = row,
                                                column = col,
                                                sticky = WEST)
        row += 1
        Radiobutton(master   = self,
                    text     = 'Sphere mesh',
                    value    = BASE_CLOSED_GEOMETRY,
                    variable = self._base).grid(row    = row,
                                                column = col,
                                                sticky = WEST)
        row += 1

        # Start oculus-daemon
        Label(master = self,
              text   = 'Daemons:').grid(row    = row,
                                        column = col,
                                        sticky = WEST)
        row += 1
        Button(master  = self,
               text    = 'Start OVRD',
               command = self._on_start_oculus_daemon).grid(row    = row,
                                                            column = col,
                                                            sticky = WEST)

        # Set column spacing
        self.columnconfigure(index = col,
                             pad   = GUI_SECTION_PAD_X)
        row  = 0
        col += 1

        # Multiplayer mode options
        Label(master = self,
              text   = 'Multi Player Options:').grid(row        = row,
                                                     column     = col,
                                                     sticky     = WEST,
                                                     columnspan = 2)
        row += 1

        Label(master = self,
              text   = 'This role:').grid(row    = row,
                                          column = col,
                                          sticky = WEST)
        Radiobutton(master   = self,
                    text     = 'Server',
                    value    = COMM_SOCKET_SERVER,
                    variable = self._comm).grid(row    = row,
                                                column = col + 1,
                                                sticky = WEST)
        row += 1
        Radiobutton(master   = self,
                    text     = 'Client',
                    value    = COMM_SOCKET_CLIENT,
                    variable = self._comm).grid(row    = row,
                                                column = col + 1,
                                                sticky = WEST)
        row += 1

        Label(master = self,
              text   = 'This host:').grid(row    = row,
                                          column = col,
                                          sticky = WEST)
        Entry(master       = self,
              textvariable = self._this_host).grid(row    = row,
                                                   column = col + 1,
                                                   sticky = WEST)
        row += 1
        Label(master = self,
              text   = 'This port:').grid(row    = row,
                                          column = col,
                                          sticky = WEST)
        Entry(master       = self,
              textvariable = self._this_port).grid(row    = row,
                                                   column = col + 1,
                                                   sticky = WEST)
        row += 1

        Label(master = self,
              text   = 'Other host:').grid(row    = row,
                                           column = col,
                                           sticky = WEST)
        Entry(master       = self,
              textvariable = self._other_host).grid(row    = row,
                                                    column = col + 1,
                                                    sticky = WEST)
        row += 1
        Label(master = self,
              text   = 'Other port:').grid(row    = row,
                                           column = col,
                                           sticky = WEST)
        Entry(master       = self,
              textvariable = self._other_port).grid(row    = row,
                                                    column = col + 1,
                                                    sticky = WEST)
        row += 1

        Button(master  = self,
               text    = 'Bind address',
               command = self._on_ask_password).grid(row        = row,
                                                     column     = col,
                                                     sticky     = WEST + EAST)
        Label(master       = self,
              textvariable = self._addressed).grid(row    = row,
                                                   column = col + 1,
                                                   sticky = WEST)
        row += 1
        Button(master  = self,
               text    = 'Connect machines',
               command = self._on_bind_address).grid(row        = row,
                                                     column     = col,
                                                     sticky     = WEST + EAST)
        Label(master       = self,
              textvariable = self._connected).grid(row    = row,
                                                   column = col + 1,
                                                   sticky = WEST)

        # Set column spacing
        self.columnconfigure(index = col + 1,
                             pad   = GUI_SECTION_PAD_X)
        row  = 0
        col += 2

        # Controller buttons
        Label(master = self,
              text   = 'Controllers:').grid(row    = row,
                                            column = col,
                                            sticky = WEST)
        row += 1
        Button(master  = self,
               text    = 'Start game',
               command = self._on_start_game).grid(row    = row,
                                                   column = col,
                                                   sticky = WEST + EAST)
        row += 1
        Button(master  = self,
               text    = 'Restart game',
               command = self._on_restart_game).grid(row    = row,
                                                     column = col,
                                                     sticky = WEST + EAST)
        row += 1
        Button(master  = self,
               text    = 'Stop game',
               command = self._on_stop_game).grid(row    = row,
                                                  column = col,
                                                  sticky = WEST + EAST)
        row += 1
        Button(master  = self,
               text    = 'Save last mesh',
               command = self._on_save_mesh).grid(row    = row,
                                                  column = col,
                                                  sticky = WEST + EAST)
        row += 1
        Button(master  = self,
               text    = 'Load last mesh',
               command = self._on_load_mesh).grid(row    = row,
                                                  column = col,
                                                  sticky = WEST + EAST)
        row += 1
        Button(master  = self,
               text    = 'Save log file',
               command = self._on_save_log).grid(row     = row,
                                                  column = col,
                                                  sticky = WEST + EAST)
        row += 1


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_ask_password(self, *args, **kwargs):
        # Create a password-dialog
        self._dialog = Password(self._pass)


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_start_oculus_daemon(self, *args, **kwargs):
        print('starting daemon...')


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_bind_address(self, *args, **kwargs):
        # Check for status and if address is not bound
        if not check(COMM_THIS_HOST):
            # Bind address
            try:
                setup(self._this_host, user_pass=self._pass.get())
            except CommunicationSetupError as exception:
                Report(exception.error)
            # Check status and report to user
            self._addressed.set(ADDR_HAVE_ADDRESS if check(COMM_THIS_HOST)
                                                  else ADDR_NO_ADDRESS)


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_connect(self, *args, **kwargs):
        pass


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_start_game(self, *args, **kwargs):
        # HACK: Is this really the best option we have, to get into fullscreen,
        #       other than using the blender's fullscreen option, which will
        #       unfortunately resize the display's resolution??? :(
        window_command = ['sleep 1']
        window_command.append('wmctrl -r :ACTIVE: '
                              '-e 0,{},{},{},{}'.format(DRAW_DISPLAY_X,
                                                        DRAW_DISPLAY_Y,
                                                        DRAW_RESOLUTION_X,
                                                        DRAW_RESOLUTION_Y))
        if DRAW_FULL_SCREEN:
            window_command.append('wmctrl -r :ACTIVE: -b add,fullscreen')

        Popen(args   = ' && '.join(window_command),
              shell  = True,
              stdin  = PIPE,
              stderr = PIPE,
              universal_newlines=True)

        # Store subprocess, for further communication
        self._pipe = Popen(args   = './plastey',
                           stdin  = PIPE,
                           stdout = PIPE,
                           stderr = PIPE,
                           universal_newlines=True)


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_restart_game(self, *args, **kwargs):
        self._pipe.stdin.write('hello-world\n')
        #if not self._locked:
        #    self._locked = True
        #    with open(FILE_STATE_RESTART, mode='w') as file:
        #        file.write('')
        #    Thread(name   = 'feedbackd-restart',
        #           target = self._get_feedback_to_clean_up).start()


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_stop_game(self, *args, **kwargs):
        #if not self._locked:
        #    self._locked = True
        #    with open(FILE_STATE_SHUT_DOWN, mode='w') as file:
        #        file.write('')
        #    Thread(name   = 'feedbackd-shutdown',
        #           target = self._get_feedback_to_clean_up).start()
        self._pipe.communicate('hello-world\n')


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_save_mesh(self, *args, **kwargs):
        pass
        #if self._pipe.poll():
        #    print('saving inside game')
        #else:
        #    print('save last auto-saved')

        #print('parent says: hey there, daemon!\n')
        #self._pipe.stdin.write('hey there, daemon!\n')

        #self._pipe.stdin.close()
        #try:
        #    self._pipe.communicate('hey there, daemon!\n', timeout=0.1)
        ## Hack: since communicate waits for the subprocess to terminate, the
        ##       timeout value is necessary, however, after the timeout, the app
        ##       won't terminate either. One solution should be
        ##       self._pipe.stdin.write instead of the communicate method, but
        ##       unfortunately the process's stdin.read/input are not getting
        ##       anything.. is it because the value set to shell=True?
        #except TimeoutExpired:
        #    return


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_load_mesh(self, *args, **kwargs):
        pass


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def _on_save_log(self, *args, **kwargs):
        pass


    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
    def run(self):
        self.mainloop()
예제 #22
0
class PolicyFrame(Frame):
    '''
    ClassPolicy screen record blocker.
    A custom image can be used.
    '''
    def __init__(self, master, title):
        Frame.__init__(self, master)
        self.grid()

        self.block = BooleanVar()
        self.block.set(True)
        self.use_custom = BooleanVar()
        self.use_custom.set(False)

        self.title = title

        self.l1 = Label(self,
                        text='The last time your teacher used ClassPolicy')
        self.l1.grid(row=0)

        self.last_used = Text(self, height=1, width=30)
        self.last_used.grid(row=1)
        self.last_used.insert(END, 'Has not used yet')

        self.l2 = Label(self, text='Current time')
        self.l2.grid(row=0, column=1)

        self.current = Text(self, height=1, width=20)
        self.current.grid(row=1, column=1)

        self.options = Frame(self)
        self.options.grid(row=2, column=0, columnspan=2, sticky=W)

        self.b_change = Button(self.options,
                               text='Change Custom Image',
                               command=self.change_custom)
        self.b_change.grid()

        self.b_get_location = Button(self.options,
                                     text='Custom Image View',
                                     command=self.view_custom)
        self.b_get_location.grid(row=0, column=1)

        self.blocking = Checkbutton(self.options,
                                    text='Block CP',
                                    var=self.block,
                                    onvalue=True,
                                    offvalue=False)
        self.blocking.grid(row=0, column=2)

        self.using_custom = Checkbutton(self.options,
                                        text='Use Custom Image',
                                        var=self.use_custom,
                                        onvalue=True,
                                        offvalue=False)
        self.using_custom.grid(row=0, column=3)

    def format_time(self, now=time.localtime()):
        '''
        For
        '''
        now = list(now)
        if now[5] < 10:
            now[5] = '0' + str(now[5])
        if int(now[3]) == 0:
            now[3] = 12
        if len(str(now[3])) == 1:
            now[3] = '0' + str(now[3])
        if len(str(now[4])) == 1:
            now[4] = '0' + str(now[4])
        return str(
            str(now[3]) + ':' + str(now[4]) + ':' + str(now[5]) + '  ' +
            str(now[1]) + '/' + str(now[2]) + '/' + str(now[0]))

    def check(self):
        if self.use_custom.get() == 1 and self.get_custom() != '':
            #Using custom image
            try:
                shutil.copy(self.get_custom(),
                            f'c:\\classpolicy\\{os.getlogin()}.jpeg')
            except:
                pass
                #Copies personal file to ClassPolicy folder

            try:
                same = filecmp.cmp(self.get_custom(),
                                   f'c:\\classpolicy\\{os.getlogin()}.jpeg')
            except:
                same = False
            if same == False:
                self.insert_last_used()
                try:
                    os.remove(f'c:\\classpolicy\\{os.getlogin()}.jpeg')
                except:
                    pass

        elif self.use_custom.get() == 1 and self.get_custom() == '':
            #Need to set a custom image
            self.change_custom()

        else:
            #Not using custom image
            if os.path.exists(f'c:\\classpolicy\\{os.getlogin()}.jpeg'):
                #If the ClassPolicy file gets created
                self.insert_last_used()
                try:
                    os.remove(f'c:\\classpolicy\\{os.getlogin()}.jpeg')
                except:
                    pass

    def update(self):
        self.insert_time()

    def get_custom(self):
        try:
            with open(PREFERENCES, 'r') as file:
                content = file.read()
                file.close()
                return content
        except PermissionError:
            showerror(title=' denied',
                      message='''
Could not get the custom image.
Check your permissions.''')
            self.use_custom.set(0)

    def change_custom(self):
        content = askopenfilename(title='Open image')
        if content != '':
            try:
                with open(PREFERENCES, 'w+') as file:
                    file.write(content)
                    file.close()
            except PermissionError as err:
                print(err)
                self.use_custom.set(0)

        else:
            self.use_custom.set(0)

    def view_custom(self):
        pass

    def insert_time(self):
        self.current.delete(1.0, END)
        self.current.insert(END, self.format_time(time.localtime()))

    def insert_last_used(self):
        self.last_used.delete(1.0, END)
        self.last_used.insert(END, self.format_time(time.localtime()))
예제 #23
0
class TkApp(Tk):
    """
    The main Tk class for the gui of simplebackup
    """
    def __init__(self, **kwargs):
        super().__init__()
        title = "Simple Backup | V" + __version__
        self.wm_title(title)
        self.protocol("WM_DELETE_WINDOW", self.on_closing)

        self.__thread = None
        self.__files_found = 0
        self.__files_copied = 0

        config_fn = kwargs.get("config_fn", user_config_filepath())
        self.__app_config = Config_Handler(config_fn)
        self.__curr_config = self.__app_config.default_config_i

        self.__menu = Menu(self)
        self.__menu_file = Menu(self.__menu, tearoff=0)
        self.__menu_file.add_command(label="Quit", command=self.quit)
        self.__menu_config = Menu(self.__menu, tearoff=0)
        self.__menu_config.add_command(label="New", command=self.new_config)
        self.__menu_config.add_command(label="Load",
                                       command=self.switch_config)
        self.__menu_config.add_command(label="Change Default",
                                       command=self.change_default_config)
        self.__menu_config.add_command(label="Rename Current",
                                       command=self.rename_curr_conf)
        self.__menu_config.add_separator()
        self.__menu_config.add_command(label="Delete Current",
                                       command=self.delete_current_config)
        self.__menu_config.add_command(label="Delete All",
                                       command=self.reset_config)
        self.__menu_help = Menu(self.__menu, tearoff=0)
        self.__menu_help.add_command(label="Check for Updates",
                                     command=self.show_update_popup)
        self.__menu_help.add_command(label="About",
                                     command=self.show_about_popup)
        self.__menu.add_cascade(label="File", menu=self.__menu_file)
        self.__menu.add_cascade(label="Config", menu=self.__menu_config)
        self.__menu.add_cascade(label="Help", menu=self.__menu_help)

        self.__title_l = Label(self, text=title, font=(16))
        self.__curr_config_name_l = Label(self)
        self.__last_backup_l = Label(self)
        self.__set_versions_to_keep = Button(
            self,
            text="Set Versions To Keep",
            command=self.update_versions_to_keep)
        self.__versions_to_keep_l = Label(self)
        self.__inc_folder_bnt = Button(self,
                                       text="Include Another Folder",
                                       command=self.add_included_folder)
        self.__included_folders_lb = Listbox(self, height=4)
        self.__included_folders_lb.bind("<<ListboxSelect>>",
                                        self.remove_selected_included_folder)
        self.__included_folders_lb.bind('<FocusOut>',
                                        self.deselect_included_folder)
        self.__excl_folder_bnt = Button(self,
                                        text="Exclude Another Folder",
                                        command=self.add_excluded_folder)
        self.__excluded_folders_lb = Listbox(self, height=4)
        self.__excluded_folders_lb.bind("<<ListboxSelect>>",
                                        self.remove_selected_excluded_folder)
        self.__excluded_folders_lb.bind('<FocusOut>',
                                        self.deselect_excluded_folder)
        self.__backup_to_bnt = Button(self,
                                      text="Backup Folder",
                                      command=self.set_backup_folder)
        self.__backup_folder_l = Label(self)
        self.__use_tar_l = Label(self, text="Use Tar")
        self.__use_tar_var = BooleanVar(self)
        self.__use_tar_var.trace_add("write", self.use_tar_changed)
        self.__use_tar = Checkbutton(self, variable=self.__use_tar_var)
        self.__backup_start_bnt = Button(self,
                                         text="Start Backup",
                                         command=self.start_backup)
        self.__progress = Progressbar(self)
        self.__statusbar = Label(self, text="ok", relief=SUNKEN, anchor=W)
        self._load_display()
        self._layout()

        if self.__app_config.show_help:
            self.show_help_popup()

    def on_closing(self):
        """
        called on window close
        """
        if self.__files_found != self.__files_copied:
            if messagebox.askyesno("Backup Running",
                                   "Do you want to stop the backup?"):
                self.destroy()
        else:
            self.destroy()

    def _load_display(self):
        """
        load the widgets with data from the current backup config,
        should be run after loading a config from file and at app launch
        """
        self.__versions_to_keep = self.__app_config.get_versions_to_keep(
            self.__curr_config)
        self.__included_folders = self.__app_config.get_included_folders(
            self.__curr_config)
        self.__excluded_folders = self.__app_config.get_excluded_folders(
            self.__curr_config)
        self.__backup_location = self.__app_config.get_backup_path(
            self.__curr_config)

        curr_conf_name = self.__app_config.get_config_name(self.__curr_config)
        self.__curr_config_name_l.config(text=f"Config Name: {curr_conf_name}")
        self.__last_backup_l.config(
            text=
            f"Last Known Backup: {self.__app_config.get_human_last_backup(self.__curr_config)}"
        )
        self.__versions_to_keep_l.config(text=self.__versions_to_keep)
        self.__included_folders_lb.delete(0, END)
        self.__included_folders_lb.insert(0, *self.__included_folders)
        self.__excluded_folders_lb.delete(0, END)
        self.__excluded_folders_lb.insert(0, *self.__excluded_folders)
        self.__backup_folder_l.config(text=str(self.__backup_location))
        self.__use_tar_var.set(
            self.__app_config.get_use_tar(self.__curr_config))

    def switch_config(self):
        """
        switches what config to use for backup,
        asks the user for a config to load,
        then loads the display
        """
        next_combo = ask_combobox("Load Config", "Config Name",
                                  self.__app_config.get_config_names())
        if next_combo != None:
            self.__curr_config = next_combo
            self._load_display()

    def change_default_config(self):
        """
        switches what config to use for the default backup,
        asks the user for a config to load
        """
        next_combo = ask_combobox("Default Config", "Config Name",
                                  self.__app_config.get_config_names())
        if next_combo != None:
            self.__app_config.default_config_i = next_combo

    def rename_curr_conf(self):
        """
        rename a existing config,
        will ask the user in a popup string input
        """
        new_name = simpledialog.askstring("Rename Config", "New Name")
        if new_name:
            self.__app_config.rename_config(self.__curr_config, new_name)
            self._load_display()

    def new_config(self):
        """
        creates a new empty backup config,
        asks the user for config name
        """
        name = simpledialog.askstring("New Config", "Config Name")
        if name:
            self.__app_config.create_config(name)

    def delete_current_config(self):
        """
        deletes the current selected config, asks the user to confirm
        """
        if messagebox.askyesno(
                "Confirm Delete",
                "Are you sure you want to delete the current config?"):
            self.__app_config.remove_config(self.__curr_config)
            self.__curr_config = self.__app_config.default_config_i
            self._load_display()

    def reset_config(self):
        """
        resets all the user configs, asks the user to confirm
        """
        if messagebox.askyesno(
                "Confirm Reset",
                "Are you sure you want to reset the all configurations?"):
            self.__app_config.reset_config()
            self.__curr_config = self.__app_config.default_config_i
            self._load_display()

    def use_tar_changed(self, *args):
        """
        called each time the __use_tar_var is called
        """
        self.__app_config.set_use_tar(self.__curr_config,
                                      self.__use_tar_var.get())

    def update_versions_to_keep(self):
        """
        update the number of versions to keep,
        asks the user for a integer
        """
        new_val = simpledialog.askinteger(
            "Versions To Keep",
            "How many backups do you want to keep",
            minvalue=0)
        if new_val != self.__versions_to_keep and new_val != None:
            self.__versions_to_keep = new_val
            self.__app_config.set_versions_to_keep(self.__curr_config,
                                                   self.__versions_to_keep)
            self.__versions_to_keep_l.config(text=self.__versions_to_keep)

    def deselect_included_folder(self, *args):
        """
        deselects the selected element in included folder
        """
        self.__included_folders_lb.selection_clear(0, END)

    def deselect_excluded_folder(self, *args):
        """
        deselects the selected element in excluded folder
        """
        self.__excluded_folders_lb.selection_clear(0, END)

    def add_included_folder(self):
        """
        add a folder to include in the backup,
        will ask user for a directory
        """
        folder = filedialog.askdirectory(initialdir="/",
                                         title="Select Folder To Backup")
        if folder:
            folder_path = Path(folder)
            if folder_path != self.__backup_location:
                self.__included_folders.append(folder_path)
                self.__included_folders_lb.insert(END, folder_path)
                self.__app_config.set_included_folders(self.__curr_config,
                                                       self.__included_folders)
            else:
                messagebox.showwarning(
                    title="Folder Same As Backup Path",
                    message=
                    "You selected a folder that was the same as the backup path!"
                )

    def remove_selected_included_folder(self, *args):
        """
        remove the currently selected
        item in the included folders ListBox,
        will ask the user to confirm
        """
        curr_selection = self.__included_folders_lb.curselection()
        # check if there is a selection
        if curr_selection:
            if messagebox.askyesno("Confirm Delete",
                                   "Are you want to delete this folder?"):
                index_to_del = curr_selection[0]
                self.__included_folders.pop(index_to_del)
                self.__app_config.set_included_folders(self.__curr_config,
                                                       self.__included_folders)
                self.__included_folders_lb.delete(index_to_del)
            self.deselect_included_folder()

    def add_excluded_folder(self):
        """
        add a folder to exclude in the backup,
        will ask user for a directory
        """
        folder = filedialog.askdirectory(initialdir="/",
                                         title="Select Folder To Exclude")
        if folder:
            folder_path = Path(folder)
            self.__excluded_folders.append(folder_path)
            self.__excluded_folders_lb.insert(END, folder_path)
            self.__app_config.set_excluded_folders(self.__curr_config,
                                                   self.__excluded_folders)

    def remove_selected_excluded_folder(self, *args):
        """
        remove the currently selected
        item in the excluded folders ListBox,
        will ask the user to confirm
        """

        curr_selection = self.__excluded_folders_lb.curselection()
        # check if there is a selection
        if curr_selection:
            if messagebox.askyesno("Confirm Delete",
                                   "Are you want to delete this folder?"):
                index_to_del = curr_selection[0]
                self.__excluded_folders.pop(index_to_del)
                self.__app_config.set_excluded_folders(self.__curr_config,
                                                       self.__excluded_folders)
                self.__excluded_folders_lb.delete(index_to_del)
            self.deselect_excluded_folder()

    def set_backup_folder(self):
        """
        sets the backup folder by asking the user for a base directory
        """
        folder = filedialog.askdirectory(initialdir="/",
                                         title="Select Where To Backup To")
        if folder:
            self.__backup_location = Path(folder)
            self.__backup_folder_l.config(text=folder)
            self.__app_config.set_backup_path(self.__curr_config,
                                              self.__backup_location)

    def enable_gui(self):
        """
        enable the gui buttons, run when a backup has completed
        """
        self.__set_versions_to_keep.config(state=NORMAL)
        self.__inc_folder_bnt.config(state=NORMAL)
        self.__included_folders_lb.config(state=NORMAL)
        self.__excl_folder_bnt.config(state=NORMAL)
        self.__excluded_folders_lb.config(state=NORMAL)
        self.__backup_to_bnt.config(state=NORMAL)
        self.__use_tar.config(state=NORMAL)
        self.__backup_start_bnt.config(state=NORMAL)

    def disable_gui(self):
        """
        disable the gui buttons, run when a backup is started
        """
        self.__set_versions_to_keep.config(state=DISABLED)
        self.__inc_folder_bnt.config(state=DISABLED)
        self.__included_folders_lb.config(state=DISABLED)
        self.__excl_folder_bnt.config(state=DISABLED)
        self.__excluded_folders_lb.config(state=DISABLED)
        self.__backup_to_bnt.config(state=DISABLED)
        self.__use_tar.config(state=DISABLED)
        self.__backup_start_bnt.config(state=DISABLED)

    def progress_find_incr(self, finished=False):
        """
        increment the progress bar for finding
        files by 1 or mark as finished

            :param finished: mark the progressbar as finished
        """
        if finished:
            self.__progress.config(mode="determinate")
            self.__progress.config(value=0, maximum=self.__files_found)
            self.__statusbar.config(text=f"Found {self.__files_found} Files")
        else:
            self.__files_found += 1
            self.__progress.config(value=self.__files_found)
            self.__statusbar.config(
                text=f"Searching For Files, Found {self.__files_found} Files")

    def progress_copy_incr(self):
        """
        increment the progress bar for copying
        files by 1 or mark as finished
        """
        self.__files_copied += 1
        self.__progress.config(value=self.__files_copied)
        self.__statusbar.config(
            text=f"Copying Files {self.__files_copied} of {self.__files_found}"
        )
        if self.__files_copied == self.__files_found:
            self.__app_config.set_last_backup(self.__curr_config,
                                              datetime.utcnow())
            self.__last_backup_l.config(
                text=
                f"Last Known Backup: {self.__app_config.get_human_last_backup(self.__curr_config)}"
            )
            self.__statusbar.config(text=f"Finished Copying Files")
            messagebox.showinfo(title="Finished Copying Files",
                                message="Finished copying all found files")
            # reset counters
            self.__files_found = 0
            self.__files_copied = 0
            self.__progress.config(value=0, maximum=100)
            self.enable_gui()

    def start_backup(self):
        """
        starts the backup
        """
        if not self.__backup_location:
            # no backup location was selected
            messagebox.showwarning(
                title="Backup Location Not Selected",
                message="You did not select a backup location!")
        elif not self.__included_folders:
            # no folders where found to backup
            messagebox.showwarning(
                title="No Folders To Backup",
                message="You did not add any folders to backup!")
        else:
            # basic checks passed
            self.disable_gui()
            # prep for search of files
            self.__progress.config(mode="indeterminate")
            self.__statusbar.config(text=f"Searching For Files")

            self.__thread = BackupThread(
                self.__included_folders, self.__excluded_folders,
                self.__backup_location, self.__versions_to_keep,
                self.progress_find_incr, self.progress_copy_incr,
                self.handle_error_message, self.__use_tar_var.get())
            # start the background backup thread so GUI wont appear frozen
            self.__thread.start()

    def show_about_popup(self):
        """
        show the about popup
        """
        messagebox.showinfo(
            "About", "simplebackup V" + __version__ +
            """ is cross-platform backup program written in python.
This app was made by enchant97/Leo Spratt.
It is licenced under GPL-3.0""")

    def show_update_popup(self):
        """
        open the default webbrowser to the update url
        """
        webbrowser.open(UPDATE_URL)

    def show_help_popup(self):
        messagebox.showinfo(
            "Welcome",
            """Welcome to simplebackup, here is some help to get you started:
\nIncluding a folder to backup
    - Press the 'Include Folder' button to add a folder to backup
    - Remove a entry by clicking on the list below
\nExcluding a folder from the backup
    - Press the 'Exclude Folder' button to skip a folder to backup
    - Remove a entry by clicking on the list below
\nSetting where backups are stored
    - Click the 'Backup Folder' button to set where backups should be placed
\nMultiple backup configs
    Use the 'Config' button in the titlebar to change varius settings like creating a new config
\nVersions to keep
    This will be the number of backup to keep in the backup folder
""")
        self.__app_config.show_help = False

    def handle_error_message(self, error_type: ERROR_TYPES):
        self.__statusbar.config(text="Failed")
        if error_type is ERROR_TYPES.NO_BACKUP_WRITE_PERMISION:
            messagebox.showerror("No Write Permission",
                                 ERROR_TYPES.NO_BACKUP_WRITE_PERMISION.value)
        elif error_type is ERROR_TYPES.NO_BACKUP_READ_PERMISION:
            messagebox.showerror("No Read Permission",
                                 ERROR_TYPES.NO_BACKUP_READ_PERMISION.value)
        elif error_type is ERROR_TYPES.NO_FILES_FOUND_TO_BACKUP:
            messagebox.showerror("No Files Found",
                                 ERROR_TYPES.NO_FILES_FOUND_TO_BACKUP.value)
        elif error_type is ERROR_TYPES.NO_BACKUP_PATH_FOUND:
            messagebox.showerror("No Backup Path Found",
                                 ERROR_TYPES.NO_BACKUP_PATH_FOUND.value)
        self.__progress.config(mode="determinate")
        self.enable_gui()

    def _layout(self):
        self.config(menu=self.__menu)
        self.__title_l.pack(fill=X, pady=10, padx=5)
        self.__curr_config_name_l.pack(fill=X, padx=5)
        self.__last_backup_l.pack(fill=X, padx=5)
        self.__set_versions_to_keep.pack(fill=X, padx=5)
        self.__versions_to_keep_l.pack(fill=X, padx=5)
        self.__inc_folder_bnt.pack(fill=X, padx=5)
        self.__included_folders_lb.pack(fill=X, padx=5)
        self.__excl_folder_bnt.pack(fill=X, padx=5)
        self.__excluded_folders_lb.pack(fill=X, padx=5)
        self.__backup_to_bnt.pack(fill=X, padx=5)
        self.__backup_folder_l.pack(fill=X, padx=5)
        self.__use_tar_l.pack(fill=X, padx=5)
        self.__use_tar.pack(fill=X, padx=5)
        self.__backup_start_bnt.pack(fill=X, padx=5)
        self.__progress.pack(fill=X)
        self.__statusbar.pack(side=BOTTOM, fill=X)
        self.wm_minsize(300, self.winfo_height())
        self.wm_resizable(True, False)
class GUIDatasetClasificacion():
    def __init__(self, root):
        self.root = root

        #TODO Esta información se lee desde .cfg con ConfigParser
        self.ruta_datasets = ''
        self.ruta_resultados = ''
        self.rutas_relativas = BooleanVar(root, True)
        self.usa_sha1 = BooleanVar(root, True)
        self._tamanyo_muestra = 5
        self.clase_al_final = BooleanVar(root, True)
        self.mostrar_proceso = BooleanVar(root, False)

        self.lee_configuracion()

        estilo_bien = Style()
        estilo_bien.configure('G.TLabel', foreground='green')
        estilo_mal = Style()
        estilo_mal.configure('R.TLabel', foreground='red')

        self.crea_GUI()

        self.root.title(APP_NAME)
        #        self.root.update()
        #        self.root.minsize(self.root.winfo_width(), self.root.winfo_height())
        self.root.minsize(800, 500)

        #        self.lee_configuracion()

        self.root.protocol('WM_DELETE_WINDOW', self.cerrar_aplicacion)

    def crea_GUI(self):
        root = self.root
        #Menús
        self.menubar = Menu(root, tearoff=0)

        m_archivo = Menu(self.menubar, tearoff=0)
        m_archivo.add_command(label='Abrir',
                              command=self.abrir_dataset,
                              accelerator='Ctrl+O')
        m_archivo.add_separator()
        m_archivo.add_command(label='Salir', command=self.cerrar_aplicacion)
        self.menubar.add_cascade(label='Archivo', menu=m_archivo)

        m_proyecto = Menu(self.menubar, tearoff=0)
        m_proyecto.add_command(label='Abrir',
                               command=self.abrir_proyecto,
                               state="disabled")
        m_proyecto.add_separator()
        m_proyecto.add_checkbutton(label='Clase al final',
                                   onvalue=True,
                                   offvalue=False,
                                   variable=self.clase_al_final)
        self.menubar.add_cascade(label='Proyecto', menu=m_proyecto)

        self.m_configuracion = Menu(self.menubar, tearoff=0)
        self.m_configuracion.add_command(
            label='Ruta datasets', command=lambda: self.rutas('datasets'))
        self.m_configuracion.add_command(
            label='Ruta resultados', command=lambda: self.rutas('resultados'))
        self.m_configuracion.add_checkbutton(label='Rutas relativas',
                                             onvalue=True,
                                             offvalue=False,
                                             variable=self.rutas_relativas,
                                             command=self.cambia_rutas)
        self.m_configuracion.add_separator()
        #TODO Revisar self.v_tamanyo_muestra, no la uso
        #        self.v_tamanyo_muestra = StringVar(root, 'Tamaño muestra ({:,})'.\
        #                                           format(self._tamanyo_muestra))
        self.m_cfg_tamanyo_muestra = \
            self.m_configuracion.add_command(label='Tamaño muestra ({:,})'.\
                                           format(self._tamanyo_muestra),
                                        command=lambda: self.tamanyo_muestra(\
                                                        self._tamanyo_muestra))
        self.m_configuracion.add_separator()
        self.m_configuracion.add_checkbutton(label='Utiliza sha1',
                                             onvalue=True,
                                             offvalue=False,
                                             variable=self.usa_sha1)
        self.menubar.add_cascade(label='Configuración',
                                 menu=self.m_configuracion)

        m_ver = Menu(self.menubar, tearoff=0)
        self.v_tipo_dataset = StringVar(self.root, 'Dataset original')
        m_ver.add_radiobutton(label='Dataset original',
                              value='Dataset original',
                              variable=self.v_tipo_dataset,
                              command=self.muestra_atributos_y_clase)
        m_ver.add_radiobutton(label='Dataset sin evidencias incompletas',
                              value='Dataset sin evidencias incompletas',
                              variable=self.v_tipo_dataset,
                              command=self.muestra_atributos_y_clase)
        m_ver.add_radiobutton(label='Dataset sin atributos constantes',
                              value='Dataset sin atributos constantes',
                              variable=self.v_tipo_dataset,
                              command=self.muestra_atributos_y_clase)
        m_ver.add_radiobutton(label='Catálogo',
                              value='Catálogo',
                              variable=self.v_tipo_dataset,
                              command=self.muestra_atributos_y_clase)
        m_ver.add_radiobutton(label='Catálogo Robusto',
                              value='Catálogo Robusto',
                              variable=self.v_tipo_dataset,
                              command=self.muestra_atributos_y_clase)
        m_ver.add_separator()
        m_ver.add_checkbutton(label='Log del proceso',
                              onvalue=True,
                              offvalue=False,
                              variable=self.mostrar_proceso,
                              state='disabled')
        self.menubar.add_cascade(label='Ver', menu=m_ver)

        root.config(menu=self.menubar)

        #Dataset de clasificación
        lf_dataset = LabelFrame(root, text='Dataset de Clasificación')
        lf_dataset.pack(fill='both', expand=True, padx=5, pady=5)

        Label(lf_dataset, text='Nombre:').grid(row=0, column=0, sticky='e')
        self.v_nombre_dataset = StringVar(root, '-------')
        self.l_nombre_dataset = Label(lf_dataset,
                                      textvariable=self.v_nombre_dataset)
        self.l_nombre_dataset.grid(row=0, column=1, sticky='w')

        Label(lf_dataset, text='Tamaño:').grid(row=0, column=2, sticky='e')
        self.v_tamanyo_dataset = StringVar(root, '-------')
        Label(lf_dataset, textvariable=self.v_tamanyo_dataset).grid(row=0,
                                                                    column=3,
                                                                    sticky='w')

        Label(lf_dataset, text='Ubicación:').grid(row=1, column=0, sticky='e')
        self.v_ruta_dataset = StringVar(root, '-------------------------')
        #TODO Expandir en columnas 1-3, puede ser muy larga
        Label(lf_dataset, textvariable=self.v_ruta_dataset).grid(row=1,
                                                                 column=1,
                                                                 sticky='w',
                                                                 columnspan=3)

        #Dataset de clasificación / Muestra
        lf_dataset_muestra = LabelFrame(lf_dataset, text='Muestra')
        lf_dataset_muestra.grid(row=2,
                                column=0,
                                sticky='nsew',
                                columnspan=4,
                                padx=5,
                                pady=5)

        self.sb_v_t_muestra = Scrollbar(lf_dataset_muestra)
        self.sb_v_t_muestra.grid(row=0, column=1, sticky='sn')

        self.sb_h_t_muestra = Scrollbar(lf_dataset_muestra,
                                        orient='horizontal')
        self.sb_h_t_muestra.grid(row=1, column=0, sticky='ew')

        self.t_muestra = Text(lf_dataset_muestra,
                              yscrollcommand=self.sb_v_t_muestra.set,
                              xscrollcommand=self.sb_h_t_muestra.set,
                              bd=0,
                              wrap='none',
                              state='disabled',
                              height=8)
        self.t_muestra.grid(row=0, column=0, sticky='nswe')

        self.sb_v_t_muestra.config(command=self.t_muestra.yview)
        self.sb_h_t_muestra.config(command=self.t_muestra.xview)

        lf_dataset_muestra.rowconfigure(0, weight=1)
        lf_dataset_muestra.columnconfigure(0, weight=1)

        lf_dataset.rowconfigure(2, weight=3)
        lf_dataset.columnconfigure(1, weight=1)
        lf_dataset.columnconfigure(3, weight=1)

        #Dataset de clasificación / Evidencias
        lf_dataset_evidencias = LabelFrame(lf_dataset, text='Evidencias')
        lf_dataset_evidencias.grid(row=3,
                                   column=0,
                                   sticky='nsew',
                                   padx=5,
                                   pady=5)

        Label(lf_dataset_evidencias, text='Total:').grid(row=0,
                                                         column=0,
                                                         sticky='e')
        self.v_evidencias_total = StringVar(root, '-------')
        Label(lf_dataset_evidencias, textvariable=self.v_evidencias_total).\
              grid(row=0, column=1, sticky='w')
        Label(lf_dataset_evidencias, text='Completas:').grid(row=1,
                                                             column=0,
                                                             sticky='e')
        self.v_evidencias_completas = StringVar(root, '-------')
        Label(lf_dataset_evidencias, textvariable=self.v_evidencias_completas).\
              grid(row=1, column=1, sticky='w')
        Label(lf_dataset_evidencias, text='Únicas:').grid(row=2,
                                                          column=0,
                                                          sticky='e')
        self.v_evidencias_catalogo = StringVar(root, '-------')
        Label(lf_dataset_evidencias, textvariable=self.v_evidencias_catalogo).\
              grid(row=2, column=1, sticky='w')
        Label(lf_dataset_evidencias, text='Robustas:').grid(row=3,
                                                            column=0,
                                                            sticky='e')
        self.v_evidencias_robustas = StringVar(root, '-------')
        Label(lf_dataset_evidencias, textvariable=self.v_evidencias_robustas).\
              grid(row=3, column=1, sticky='w')

        #Dataset de clasificación / Atributos
        lf_dataset_clase_y_atributos = LabelFrame(lf_dataset,
                                                  text='Clase y atributos')
        lf_dataset_clase_y_atributos.grid(row=3,
                                          column=1,
                                          sticky='nsew',
                                          columnspan=3,
                                          padx=5,
                                          pady=5)

        PROPIEDADES_ATRIBUTOS = ('Nombre', 'count', 'unique', 'top', 'freq',
                                 'mean', 'std', 'min', '25%', '50%', '75%',
                                 'max')

        self.sb_h_tv_clase = Scrollbar(lf_dataset_clase_y_atributos,
                                       orient='horizontal')
        self.sb_h_tv_clase.grid(row=1, column=0, sticky='ew')
        self.tv_clase = Treeview(lf_dataset_clase_y_atributos,
                                 columns=PROPIEDADES_ATRIBUTOS,
                                 height=1,
                                 xscrollcommand=self.sb_h_tv_clase.set)
        self.tv_clase.grid(row=0, column=0, sticky='ew')
        self.sb_h_tv_clase.config(command=self.tv_clase.xview)
        self.tv_clase.heading("#0", text="#")
        self.tv_clase.column("#0", minwidth=30, width=40, stretch=False)

        self.sb_v_tv_atributos = Scrollbar(lf_dataset_clase_y_atributos)
        self.sb_v_tv_atributos.grid(row=2, column=1, sticky='sn')
        self.sb_h_tv_atributos = Scrollbar(lf_dataset_clase_y_atributos,
                                           orient='horizontal')
        self.sb_h_tv_atributos.grid(row=3, column=0, sticky='ew')
        self.tv_atributos = Treeview(lf_dataset_clase_y_atributos,
                                     columns=PROPIEDADES_ATRIBUTOS,
                                     yscrollcommand=self.sb_v_tv_atributos.set,
                                     xscrollcommand=self.sb_h_tv_atributos.set)
        self.tv_atributos.grid(row=2, column=0, sticky='nsew')
        self.tv_atributos.bind('<ButtonRelease-1>', self.selectItem)
        self.sb_v_tv_atributos.config(command=self.tv_atributos.yview)
        self.sb_h_tv_atributos.config(command=self.tv_atributos.xview)
        self.tv_atributos.heading("#0", text="#")
        self.tv_atributos.column("#0", minwidth=30, width=40, stretch=False)

        for i in PROPIEDADES_ATRIBUTOS:
            self.tv_clase.heading(i, text=i)
            self.tv_clase.column(i, minwidth=50, width=50, stretch=False)
            self.tv_atributos.heading(i, text=i)
            self.tv_atributos.column(i, minwidth=50, width=50, stretch=False)

        lf_dataset_clase_y_atributos.rowconfigure(2, weight=1)
        lf_dataset_clase_y_atributos.columnconfigure(0, weight=1)

        lf_dataset.rowconfigure(3, weight=1)

    def abrir_dataset(self):
        inicio = time.time()

        #TODO Las constantes se podrán modificar a través de .cfg
        nombre = askopenfilename(
            initialdir=self.ruta_datasets,
            filetypes=(('Archivos de valores separado por comas', '*.csv'),
                       ('Todos los archivos', '*.*')),
            title='Selecciona un Dataset de Clasificación')

        self.root.focus_force()

        if not nombre:
            return

        self.v_nombre_dataset.set(
            os.path.splitext(os.path.basename(nombre))[0])
        #TODO Esto debería hacerlo en otro sitio, no cuando lo elijo con
        #     filedialog, y tener en cuenta self.usa_sha1
        if os.path.exists(os.path.dirname(nombre)):
            self.l_nombre_dataset.configure(style='G.TLabel')
        else:
            self.l_nombre_dataset.configure(style='R.TLabel')
        self.v_tamanyo_dataset.set(tamanyo_legible(os.path.getsize(nombre)))

        self.v_ruta_dataset.set(os.path.relpath(os.path.dirname(nombre)) \
                                if self.rutas_relativas.get() else \
                                os.path.dirname(nombre))
        self.limpia_muestra()
        self.limpia_atributos_y_clase()
        self.root.update()

        #TODO Usar hilos o procesos para leer grandes datasets sin problemas
        #        self.progreso = Toplevel(self.root)
        #        self.progreso.title("Leyendo Dataset de Clasificación")
        #        barra = Progressbar(self.progreso, length=200, mode="indeterminate")
        #        barra.pack()
        #        self.q = Queue()
        #        hilo_lectura = Process(target=self.get_dc)
        #        hilo_lectura.start()
        ##        self.dc = self.q.get()
        ##        hilo_lectura.join()
        #        self.root.after(50, self.check_if_running, hilo_lectura, self.progreso)
        self.dc = DC(self.v_ruta_dataset.get(),
                     self.v_nombre_dataset.get(),
                     self.ruta_resultados,
                     guardar_resultados=False,
                     clase_al_final=self.clase_al_final.get(),
                     mostrar_proceso=self.mostrar_proceso,
                     num_filas_a_leer=None,
                     obtener_catalogo_robusto=False,
                     guardar_datos_proyecto=False,
                     mostrar_uso_ram=False)
        self.escribe_datos()

    def escribe_datos(self):
        self.escribe_muestra()
        self.v_evidencias_total.set('{:,}'.\
            format(self.dc.info_dataset_original.num_evidencias()))
        self.v_evidencias_completas.set('{:,}'.\
          format(self.dc.info_dataset_sin_datos_desconocidos.num_evidencias()))
        self.v_evidencias_catalogo.set('{:,}'.\
            format(self.dc.info_catalogo.num_evidencias()))
        self.v_evidencias_robustas.set('{:,}'.\
            format(self.dc.info_catalogo_robusto.num_evidencias()))

        self.muestra_atributos_y_clase()

        self.root.title('{} - {}'.format(APP_NAME,
                                         self.v_nombre_dataset.get()))

    def get_dc(self):
        #TODO No puedo crear self.dc en un try mientras depure DC
        #        try:
        self.dc = DC(self.v_ruta_dataset.get(),
                     self.v_nombre_dataset.get(),
                     self.ruta_resultados,
                     guardar_resultados=False,
                     clase_al_final=self.clase_al_final,
                     mostrar_proceso=self.mostrar_proceso,
                     num_filas_a_leer=None,
                     obtener_catalogo_robusto=False,
                     guardar_datos_proyecto=False,
                     mostrar_uso_ram=False)
        self.q.put(self.dc)


#        except Exception as e:
#            self.t_muestra.delete(1.0, 'end')
#            self.t_muestra.insert('end', e)

    def check_if_running(self, hilo, ventana):
        """Check every second if the function is finished."""
        if hilo.is_alive():
            self.root.after(50, self.check_if_running, hilo, ventana)
        else:
            ventana.destroy()
            self.escribe_datos()

    def abrir_proyecto(self):
        inicio = time.time()

        #TODO Diseñar estrategia para que el usuario sepa si ha de cambiarlo.
        #     Podría bastar con mostrarle los atributos y sus características.
        #        clase_al_final = self._clase_al_final

        #TODO Las constantes se podrán modificar a través de .cfg
        nombre = askopenfilename(initialdir=self.ruta_resultados,
                                 filetypes=(('Proyectos ACDC', '*.prjACDC'),
                                            ('Todos los archivos', '*.*')),
                                 title='Selecciona un proyecto ACDC')
        if nombre is None:
            return

        #TODO ¿Mostrar sólo el nombre del dataset original?
        self.root.title('{} - {}'.format(
            APP_NAME,
            os.path.splitext(os.path.basename(nombre))[0]))

    def rutas(self, r=None):
        ruta = askdirectory(title='Directorio de {}'.format(r),
                            initialdir=eval('self.ruta_{}'.format(r)),
                            mustexist=True)
        if ruta != '':
            if self.rutas_relativas.get():
                if r == 'datasets':
                    self.ruta_datasets = os.path.relpath(ruta)
                else:
                    self.ruta_resultados = os.path.relpath(ruta)
            else:
                if r == 'datasets':
                    self.ruta_datasets = ruta
                else:
                    self.ruta_resultados = ruta

    def cambia_rutas(self):
        if self.rutas_relativas.get():
            self.ruta_datasets = os.path.relpath(self.ruta_datasets)
            self.ruta_resultados = os.path.relpath(self.ruta_resultados)
        else:
            self.ruta_datasets = os.path.abspath(self.ruta_datasets)
            self.ruta_resultados = os.path.abspath(self.ruta_resultados)

    def limpia_atributos_y_clase(self):
        for i in self.tv_clase.get_children():
            self.tv_clase.delete(i)
        for i in self.tv_atributos.get_children():
            self.tv_atributos.delete(i)

    def limpia_muestra(self):
        self.t_muestra['state'] = 'normal'
        self.t_muestra.delete(1.0, 'end')
        self.t_muestra['state'] = 'disabled'

    def tamanyo_muestra(self, tamanyo):
        nuevo_tamanyo = askinteger('Muestra',
                                   '¿Cuántas evidencias quieres ver?',
                                   parent=self.root,
                                   minvalue=1,
                                   initialvalue=self._tamanyo_muestra)
        #                                            minvalue=0, maxvalue=1000)
        if nuevo_tamanyo:
            self._tamanyo_muestra = nuevo_tamanyo
        #TODO Debería averiguar el índice del menú que quiero modificar
        self.m_configuracion.entryconfigure(4, label='Tamaño muestra ({:,})'.\
                                                 format(self._tamanyo_muestra))
        self.escribe_muestra()

    #TODO Tratar excepciones para que no se quede habilitada la escritura
    def escribe_muestra(self):
        self.t_muestra['state'] = 'normal'
        self.t_muestra.delete(1.0, 'end')
        self.t_muestra.insert('end', '#######################################'\
                              '########################\n')
        self.t_muestra.insert('end', '   PRIMERAS {:,} LÍNEAS DEL DATASET DE '\
                              'CLASIFICACIÓN ORIGINAL\n'.\
                              format(self._tamanyo_muestra))
        self.t_muestra.insert('end', '#######################################'\
                              '########################\n')
        self.t_muestra.insert('end', self.dc.muestra(self._tamanyo_muestra))
        self.t_muestra.insert('end', '\n\n')
        self.t_muestra['state'] = 'disabled'

    def muestra_atributos_y_clase(self):
        self.limpia_atributos_y_clase()
        if self.v_tipo_dataset.get() == 'Dataset original':
            df = self.dc.info_dataset_original.columnas
        elif self.v_tipo_dataset.get() == 'Dataset sin evidencias incompletas':
            df = self.dc.info_dataset_sin_datos_desconocidos.columnas
        elif self.v_tipo_dataset.get() == 'Dataset sin atributos constantes':
            df = self.dc.info_dataset_sin_atributos_constantes.columnas
        elif self.v_tipo_dataset.get() == 'Catálogo':
            df = self.dc.info_catalogo.columnas
        elif self.v_tipo_dataset.get() == 'Catálogo Robusto':
            df = self.dc.info_catalogo_robusto.columnas

        self.tv_clase["columns"] = list(df.index).insert(0, 'Nombre')
        self.tv_atributos["columns"] = list(df.index).insert(0, 'Nombre')

        self.tv_clase.heading('Nombre', text='Nombre')
        self.tv_atributos.heading('Nombre', text='Nombre')
        for i in df.index:
            self.tv_clase.heading(i, text=i)
            self.tv_clase.column(i, minwidth=50, width=50, stretch=False)
            self.tv_atributos.heading(i, text=i)
            self.tv_atributos.column(i, minwidth=50, width=50, stretch=False)

        for i, atributo in enumerate(df.columns):
            valores = [valor if not pd.isnull(valor) else '-' for valor \
                       in df[atributo]]
            valores.insert(0, atributo)
            if atributo == self.dc.info_dataset_original.clase:
                self.tv_clase.insert('', 'end', text=(0), values=valores)
            else:
                self.tv_atributos.insert('',
                                         'end',
                                         text=(i + 1),
                                         values=valores)

    #TODO Modificar para que muestre información relevante de la celda.
    def selectItem(self, event):
        curItem = self.tv_atributos.item(self.tv_atributos.focus())
        col = self.tv_atributos.identify_column(event.x)
        print('curItem = ', curItem)
        print('col = ', col)
        if col == '#0':
            cell_value = curItem['text']
        else:
            cell_value = curItem['values'][int(col[1:]) - 1]
        print('cell_value = ', cell_value)

    def lee_configuracion(self):
        archivo_cfg = ConfigParser()
        archivo_cfg.optionxform = lambda option: option
        archivo_cfg.read('app.cfg')

        self.root.geometry(
            archivo_cfg.get('Ventana principal', 'Dimensiones y posición'))
        self.clase_al_final.set(
            archivo_cfg.get('Proyecto', 'Clase al final', fallback=True))
        self.rutas_relativas.set(
            archivo_cfg.get('Proyecto', 'Rutas relativas', fallback=True))
        self.ruta_datasets = archivo_cfg.get('Proyecto',
                                             'Ruta datasets',
                                             fallback='../datos/ACDC/')
        self.ruta_resultados = archivo_cfg.get('Proyecto',
                                               'Ruta resultados',
                                               fallback='../datos/catalogos/')

    def guarda_configuracion(self):
        archivo_cfg = ConfigParser()
        archivo_cfg.optionxform = lambda option: option

        #Dimensiones y posición de la ventana
        self.root.update()
        ancho, alto = self.root.winfo_width(), self.root.winfo_height()
        x, y = self.root.winfo_x(), self.root.winfo_y()
        archivo_cfg['Ventana principal'] = {\
            'Dimensiones y posición': '{}x{}+{}+{}'.format(ancho, alto, x, y)}

        archivo_cfg['Proyecto'] = {\
            'Clase al final': self.clase_al_final.get(),
            'Ruta datasets': self.ruta_datasets,
            'Ruta resultados': self.ruta_resultados,
            'Rutas relativas': self.rutas_relativas.get()}
        with open('app.cfg', 'w') as archivo:
            archivo_cfg.write(archivo)

    def cerrar_aplicacion(self):
        self.guarda_configuracion()
        self.root.destroy()
예제 #25
0
class MainWindow:
    def __init__(self) -> None:
        self.Root = Tk()
        self.App = Frame(self.Root, padding=(5, 2))
        self.UpdatesFrame = LabelFrame(self.App,
                                       text=L.UpdatesFrame,
                                       borderwidth=2,
                                       relief='sunken',
                                       padding=(5, 2))
        self.upd_enabled = BooleanVar()  # Флаг обновлений
        self.upd_unit = StringVar()  # Единица измерения времени
        self.time_units = {
            Minutes: L.Minutes,
            Hours: L.Hours,
            Days: L.Days,
            Weeks: L.Weeks,
            Months: L.Months
        }
        self.size_units = {
            Bytes: L.Bytes,
            KBytes: L.KBytes,
            MBytes: L.MBytes,
            GBytes: L.GBytes,
            TBytes: L.TBytes
        }  # Список единиц измерения времени
        self.maxfsize = StringVar()  # Максимальный размер файла
        self.size_unit = StringVar()  # Единица измерения информации
        self.units_amount1 = StringVar()  # Количество единиц
        self.quar = BooleanVar()  # False - удалять, True - карантин
        self.quar_path = StringVar()  # Расположение карантина
        self.rpt_enabled = BooleanVar()  # Флаг отправки отчета
        self.email = StringVar()  # Адрес отправки
        self.passwd = StringVar()  # Пароль исходящего ящика
        self.rpt_unit = StringVar()  # Единица измерения времени
        self.units_amount2 = StringVar()  # Количество единиц

        self.Upd_Label1 = Label(self.UpdatesFrame, text=L.Upd_Label1)
        self.Upd_Checkbutton1 = Checkbutton(self.UpdatesFrame,
                                            variable=self.upd_enabled)
        self.Upd_Label2 = Label(self.UpdatesFrame, text=L.Upd_Label2)
        self.Upd_Spinbox1 = Spinbox(self.UpdatesFrame,
                                    textvariable=self.units_amount1,
                                    from_=1,
                                    to=999999999,
                                    width=4)
        self.Upd_OptionMenu1 = OptionMenu(self.UpdatesFrame, self.upd_unit,
                                          *self.time_units.values())
        self.Upd_Button1 = Button(
            self.UpdatesFrame,
            text=L.Upd_Button1,
            command=lambda: EntryOptionsWindow('AV_SOURCES', self.Root))

        self.ScanFrame = LabelFrame(self.App,
                                    text=L.ScanFrame,
                                    borderwidth=2,
                                    relief='sunken',
                                    padding=(5, 2))
        self.Scn_Label1 = Label(self.ScanFrame, text=L.Scn_Label1)
        self.Scn_Spinbox1 = Spinbox(self.ScanFrame,
                                    textvariable=self.maxfsize,
                                    from_=0,
                                    to=999999999,
                                    width=8)

        self.Quar_Label = Label(self.ScanFrame, text=L.Quar_Label)
        self.Quar_RadButton1 = Radiobutton(self.ScanFrame,
                                           text=L.Quar_RadButton1,
                                           variable=self.quar,
                                           value=False)
        self.Quar_RadButton2 = Radiobutton(self.ScanFrame,
                                           text=L.Quar_RadButton2,
                                           variable=self.quar,
                                           value=True)

        self.Scn_OptionMenu1 = OptionMenu(self.ScanFrame, self.size_unit,
                                          *self.size_units.values())
        self.Scn_Edit_Targets = Button(
            self.ScanFrame,
            text=L.Scn_Edit_Targets,
            command=lambda: EntryOptionsWindow(
                'SCAN_TARGETS', self.Root, select_path=True))
        self.Scn_Edit_Exceptions = Button(
            self.ScanFrame,
            text=L.Scn_Edit_Exceptions,
            command=lambda: EntryOptionsWindow('SCAN_EXCLUDE', self.Root))
        self.Quar_Button1 = Button(
            self.ScanFrame,
            text=L.Quar_Button1,
            command=lambda: self.quar_path.set(filedialog.askdirectory()))

        self.ReportFrame = LabelFrame(self.App,
                                      text=L.ReportFrame,
                                      borderwidth=2,
                                      relief='sunken',
                                      padding=(5, 2))

        self.Rpt_Label1 = Label(self.ReportFrame, text=L.Rpt_Label1)
        self.Rpt_Checkbutton1 = Checkbutton(self.ReportFrame,
                                            variable=self.rpt_enabled)
        self.Rpt_Label2 = Label(self.ReportFrame, text=L.Rpt_Label2)
        self.Rpt_Entry1 = Entry(self.ReportFrame,
                                textvariable=self.email,
                                width=32)
        self.Rpt_Label3 = Label(self.ReportFrame, text=L.Rpt_Label3)
        self.Rpt_Entry2 = Entry(self.ReportFrame,
                                textvariable=self.passwd,
                                width=32,
                                show='*')
        self.Rpt_Label4 = Label(self.ReportFrame, text=L.Rpt_Label4)
        self.Rpt_Spinbox1 = Spinbox(self.ReportFrame,
                                    textvariable=self.units_amount2,
                                    from_=1,
                                    to=999999999,
                                    width=4)
        self.Rpt_OptionMenu1 = OptionMenu(self.ReportFrame, self.rpt_unit,
                                          *self.time_units.values())
        self.Rpt_Button1 = Button(
            self.ReportFrame,
            text=L.Rpt_Button1,
            command=lambda: EntryOptionsWindow('SEND_TO', self.Root))

        self.Buttons = Frame(self.App, padding=(5, 2))
        self.Button1 = Button(self.Buttons,
                              text=L.Done,
                              command=self.save_conf)
        self.Button2 = Button(self.Buttons,
                              text=L.Cancel,
                              command=self.Root.destroy)

    def main(self) -> None:
        self.upd_unit.set(self.time_units[type(UPDATE_FREQ)])
        self.units_amount1.set(UPDATE_FREQ.value)
        self.upd_enabled.set(CHECK_FOR_UPDATES)
        self.Upd_Checkbutton1.configure(command=(lambda: self.__change_state(
            self.upd_enabled, self.Upd_Label2, self.Upd_Spinbox1, self.
            Upd_OptionMenu1, self.Upd_Button1) and self.upd_enabled.set(
                not self.upd_enabled.get())))
        self.Rpt_Checkbutton1.configure(command=(lambda: self.__change_state(
            self.rpt_enabled, self.Rpt_Label2, self.Rpt_Entry1, self.
            Rpt_Label3, self.Rpt_Entry2, self.Rpt_Label4, self.Rpt_Spinbox1,
            self.Rpt_OptionMenu1, self.Rpt_Button1) and self.rpt_enabled.set(
                not self.rpt_enabled.get())))
        self.maxfsize.set(MAX_FILE_SIZE.value)
        self.size_unit.set(self.size_units[type(MAX_FILE_SIZE)])
        self.quar.set(REMOVE_THREATS)
        self.quar_path.set(QUARANTINE_PATH)
        self.rpt_enabled.set(SEND_SCAN_REPORTS)
        self.email.set(SEND_FROM)
        try:
            with open('/root/.cobpwd', 'r') as f:
                self.passwd.set(f.read())
        except FileNotFoundError:
            pass
        self.rpt_unit.set(self.time_units[type(SEND_FREQ)])
        self.units_amount2.set(SEND_FREQ.value)

        self.App.pack(fill='both', expand=True)
        center_win(self.Root, '500x500')
        self.Root.resizable(False, False)
        self.Root.title('CobraAV Configuration')

        self.UpdatesFrame.place(y=0, height=150, width=490)
        self.__change_state(self.upd_enabled, self.Upd_Label2,
                            self.Upd_Spinbox1, self.Upd_OptionMenu1)

        self.__change_state(self.rpt_enabled, self.Rpt_Label2, self.Rpt_Entry1,
                            self.Rpt_Label3, self.Rpt_Entry2, self.Rpt_Label4,
                            self.Rpt_Spinbox1, self.Rpt_OptionMenu1,
                            self.Rpt_Button1)

        self.Upd_Label1.place(relx=.01, rely=.05)  # Проверять обновления ?
        self.Upd_Checkbutton1.place(relx=.8, rely=.05)  # Да/Нет

        self.Upd_Label2.place(relx=.01, rely=.3)  # Частота проверки
        self.Upd_Spinbox1.place(relx=.55, rely=.3, width=60)  # Количество
        self.Upd_OptionMenu1.place(relx=.72, rely=.28)  # Единицы измерения
        self.Upd_Button1.place(relx=.01, rely=.65)  # Источники сигнатур

        self.ScanFrame.place(y=150, height=150, width=490)

        self.Scn_Label1.place(relx=.01, rely=.05)  # Максимальный размер файла
        self.Scn_Spinbox1.place(relx=.55, rely=.05, width=60)  # Количество

        self.Quar_Label.place(relx=.01, rely=.35)
        self.Quar_RadButton1.place(
            relx=.52, rely=.35)  # Переключатель на удаление угрозы
        self.Quar_RadButton2.place(
            relx=.72,
            rely=.35)  # Переключатель на добавление вкарантина угрозы
        self.Quar_Button1.place(relx=.56, rely=.65)  # Расположение карантина

        self.Scn_OptionMenu1.place(relx=.72, rely=.014)  # Единицы измерения
        self.Scn_Edit_Targets.place(relx=.01, rely=.65)  # Цели сканирования
        self.Scn_Edit_Exceptions.place(relx=.33, rely=.65)  # Исключения

        self.Rpt_Label1.place(relx=.01, rely=.05)  # Отправлять отчеты ?
        self.Rpt_Checkbutton1.place(relx=.8, rely=.05)  # Да/Нет

        self.ReportFrame.place(y=300, height=150, width=490)
        self.Rpt_Label2.place(relx=.01, rely=.35)  # Адрес отправки отчетов:
        self.Rpt_Entry1.place(relx=.35,
                              rely=.35)  # Ввод адреса отправки отчетов
        self.Rpt_Label3.place(relx=.01, rely=.50)  # Пароль:
        self.Rpt_Entry2.place(relx=.35, rely=.50)  # Ввод пароля:
        self.Rpt_Label4.place(relx=.01, rely=.75)  # Частота отправки
        self.Rpt_Spinbox1.place(relx=.35, rely=.75, width=60)  # Количество
        self.Rpt_OptionMenu1.place(relx=.52, rely=.72)  # Единицы измерения
        self.Rpt_Button1.place(relx=.72, rely=.74)  # Получатели

        self.Buttons.place(y=450, height=50, width=490)
        self.Button1.place(relx=.62, rely=.2)  # Кнопка "Готово"
        self.Button2.place(relx=.82, rely=.2)  # Кнопка "Отмена"

        self.Root.mainloop()

    @staticmethod
    def __change_state(state: BooleanVar, *args: Widget) -> None:
        for i in args:
            i.configure(state=('disabled', 'normal')[state.get()])

    def save_conf(self) -> None:
        size_units = {v: k for k, v in self.size_units.items()}
        time_units = {v: k for k, v in self.time_units.items()}

        def wrap_list(a: 'list[str]') -> str:
            return '[' + ', \n'.join(f"r'{i}'" for i in a) + ']'

        def wrap_cls(_unit: Variable, amount: Variable) -> str:
            unit = _unit.get()
            if unit in size_units:
                return size_units[unit].__name__ + f'({amount.get()})'
            elif unit in time_units:
                return time_units[unit].__name__ + f'({amount.get()})'
            else:
                raise NotImplementedError

        if self.upd_enabled.get() and not CHECK_FOR_UPDATES:
            system('systemctl enable cobra-update.service')
            system('systemctl restart cobra-update.service')
        else:
            system('systemctl stop cobra-update.service')
            system('systemctl disable cobra-update.service')

        if self.rpt_enabled.get() and not SEND_SCAN_REPORTS:
            system('systemctl enable cobra-notify.service')
            system('systemctl restart cobra-notify.service')
        else:
            system('systemctl stop cobra-notify.service')
            system('systemctl disable cobra-notify.service')

        with open('/root/.cobpwd', 'w') as f:
            f.write(self.passwd.get())

        with open(CONF_PATH, 'w') as f:
            f.write(f"""from libunits import *

CHECK_FOR_UPDATES = {int(self.upd_enabled.get())}  # Check for updates
UPDATE_FREQ = {wrap_cls(self.upd_unit, self.units_amount1)}  # Check interval
MAX_FILE_SIZE = {wrap_cls(self.size_unit, self.maxfsize)}  # Max file size

# Antivirus database sources
AV_SOURCES = {wrap_list(AV_SOURCES)}

# Antivirus database path
DB_PATH = r'{DB_PATH}'

# On threat:
# 0 - quarantine
# 1 - remove
REMOVE_THREATS = {int(self.quar.get())}

# Directories to scan
SCAN_TARGETS = {wrap_list(SCAN_TARGETS)}

# Exclude from scanning
SCAN_EXCLUDE = {wrap_list(SCAN_EXCLUDE)}

# quarantine location
QUARANTINE_PATH = r'{self.quar_path.get() or QUARANTINE_PATH}'

# Send scan reports
SEND_SCAN_REPORTS = {int(self.rpt_enabled.get())}

# Scan reports frequency
SEND_FREQ = {wrap_cls(self.rpt_unit, self.units_amount2)}

# Send from this email
SEND_FROM = r'{self.email.get()}'

# Send to these emails
SEND_TO = {wrap_list(SEND_TO)}

# SMTP settings (preset for gmail)
SMTP_HOST = 'smtp.gmail.com'
SMTP_PORT = 587

# GUI Language
LANG = '{LANG}'
""")
        self.Root.destroy()
예제 #26
0
class SetUp():
    def __init__(self, parent):
        self.parent = parent
        print('We are in the SetUp class')
        self.myFont = font.Font(family='Helvetica', size=15)
        self.setup()

    def setup(self):
        """
        Sets program variables that can be cleared upon "Clear" button function "destroy_f1_frame"
        Setup styles for window, buttons, labels, and grids
        """
        # variables
        self.urls = []
        self.url_data = False
        self.checkboxes = []
        self.checkboxes_val = False
        self.filename = None
        self.upload_val = False

        # text widget
        self.text = Text(self.parent)

        # styles widget
        self.f1_style = ttk.Style() 

        # styles config
        self.f1_style.configure('My.TFrame')
        self.f1 = ttk.Frame(self.parent, style='My.TFrame')

        # styles/config buttons
        self.f1_style.configure('TButton', foreground='#013A70', font=('Helvetica', 15))
        self.quit_Button = ttk.Button(self.parent, width=5, text="Quit ", command=self.parent.quit)
        self.start_Button = ttk.Button(self.f1, width=5, text="Start", command=ValidationStuff(self).get_entries)
        self.clear_Button = ttk.Button(self.parent, width=5, text="Clear", command=ValidationStuff(self).destroy_f1_frame)
        self.help_Button = ttk.Button(self.parent, width=5, text="Help", command=Factory("HelpScreen")(self.parent).help_screen)

        # logo image
        self.image = Image.open('assets/ezgif-2-18770de0fea5.gif')
        self.photo = ImageTk.PhotoImage(self.image)
        self.img_label = Label(self.parent, image=self.photo, width=70)

        # label stuff
        self.url_Label_0 = ttk.Label(self.f1, text="              ")
        self.url_Label_1 = ttk.Label(self.f1, text="Enter URL To Parse ")
        self.url_Label_1['font'] = self.myFont
        self.url_Entry = ttk.Entry(self.f1)
        self.parse_data_Label = ttk.Label(self.f1, text="Data To Parse")
        self.parse_data_Label['font'] = self.myFont
        self.upload_File = ttk.Label(self.f1, text="Upload Data File")
        self.upload_File['font'] = self.myFont
        self.upload_Button = ttk.Button(self.f1, text="Upload", command=ValidationStuff(self).uploadAction)
        self.error_message = ttk.Label(self.f1, foreground="red", text="Please complete all fields... ")
        self.go_message = ttk.Label(self.f1, foreground="blue", text="Working on parsing... ")
        self.done_message = ttk.Label(self.f1, foreground="#006400", text="Finished parsing this page... ")        
        self.finished_message = ttk.Label(background="white", foreground="blue", text="Finished... ")  
        self.clear_values_message = ttk.Label(self.f1, foreground="blue", text="Cleared the URL and any attached file... ") 

        # checkbox variables
        self.body_Var = BooleanVar()

        # set checkbox values
        self.body_Var.set(True)

        # add functionality to checkbox
        self.body_tag = ttk.Checkbutton(self.f1, text="Full HTML", variable=self.body_Var, onvalue=True)

        # main style grid
        self.f1.grid(column=0, row=0, sticky=(E, W, S, N))

        # blank line grid
        self.url_Label_0.grid(column=0, row=0, sticky=(N, E, S, W), padx=(10,10), pady=1)

        # url input and parse grid
        self.url_Label_1.grid(column=0, row=1, sticky=(N, E, S, W), padx=(10,1), pady=1)
        self.url_Entry.grid(column=0, row=2, sticky=(N, E, S, W), padx=(10,1), pady=1)

        # check boxes grid
        self.parse_data_Label.grid(column=0, row=4, sticky=(N, E, S, W), padx=(10,1), pady=(10,1))
        self.body_tag.grid(column=0, row=4, padx=(10,1), pady=(55,1), sticky=(W))

        # upload button grid
        self.upload_File.grid(column=0, row=7, sticky=(N, E, S, W), padx=(10,1), pady=(40,1))
        self.upload_Button.grid(column=0, row=8, sticky=(E, W, N, S), padx=(10,110), pady=(1,1))

        # error message and go message
        self.done_message.grid(column=0, row=9, sticky=(E, W), pady=(2,1),padx=(10,1))
        self.done_message.grid_remove()
        self.error_message.grid(column=0, row=9, sticky=(E, W), pady=(2,1),padx=(10,1))
        self.error_message.grid_remove()
        self.go_message.grid(column=0, row=9, sticky=(N, S, E, W), pady=(2,1),padx=(10,1))
        self.go_message.grid_remove()
        self.clear_values_message.grid(column=0, row=9, sticky=(N, S, E, W), pady=(2,1),padx=(10,1))
        self.clear_values_message.grid_remove()
        
        # image grid
        self.img_label.grid(column=2, row=0, sticky=(N, W), pady=(0,0), padx=(0,0))
        self.start_Button.grid(column=1, row=10, sticky=(E, W), pady=(40,10), padx=(20,10))

        # quit button grid
        self.quit_Button.grid(column=2, row=0, sticky=(S), pady=(1,10), padx=(1,1))
        self.clear_Button.grid(column=2, row=0, sticky=(S), pady=(1,40), padx=(1,1))
        self.help_Button.grid(column=2, row=0, sticky=(S), pady=(1,70), padx=(1,1))

        # need to check what these do
        self.parent.columnconfigure(0, weight=1)# weight determines how much of the available space a row or column should occupy relative to the other rows or columns
        self.parent.rowconfigure(0, weight=1)
        self.f1.columnconfigure(0, weight=2)# weight determines how much of the available space a row or column should occupy relative to the other rows or columns
        self.f1.rowconfigure(0, weight=2)

        ValidationStuff(self)
예제 #27
0
    def load_data(self):
        # reads in various other pieces of information required
        with open(self.file, 'rb') as file:
            # let's get the gain:
            file.seek(0x70)
            offset = unpack('i', file.read(4))[0]
            file.seek(offset)
            amp_data = unpack('i', file.read(4))[0]
            gain1 = (amp_data & 0x00007000) >> 12
            gain2 = (amp_data & 0x70000000) >> 28
            gain3 = (amp_data & 0x07000000) >> 24
            self.info['gains'] = '{0}, {1}, {2}'.format(
                GAINS[gain1], GAINS[gain2], GAINS[gain3])

            # get the InsitutionName and ManufacturersModelName:
            # code taken pretty much directly from the kit.py script in mne
            file.seek(0x20C)
            system_name = unpack('128s', file.read(0x80))[0].decode()
            model_name = unpack('128s', file.read(0x80))[0].decode()
            nchans = unpack('i', file.read(4))[0]
            file.seek(0x100, 1)  # ignore any comments
            create_time, = unpack('i', file.read(0x4))
            system_name = system_name.replace('\x00', '')
            # system_name = system_name.strip().replace('\n', '/')
            model_name = model_name.replace('\x00', '')
            # model_name = model_name.strip().replace('\n', '/')
            self.info['Institution name'] = system_name
            self.info['Serial Number'] = model_name
            self.info['Channels'] = nchans
            self.info['Measurement date'] = datetime.fromtimestamp(
                create_time).strftime('%d/%m/%Y')

            # determine whether the data has continuous head movement data
            file.seek(0x1D0)
            reTHM_offset, = unpack('i', file.read(0x4))
            self.extra_data['ContinuousHeadLocalization'] = (reTHM_offset != 0)

            # Get all the channel information here separately from mne.
            # This way the data is intrinsically linked to the con file
            # and we can generate the channels tab from the start
            file.seek(0x40)
            chan_offset, chan_size = unpack('2i', file.read(8))

            # check to see if any of the channels are designated as triggers
            # by default
            def_trigger_info = None
            if isinstance(self.container, KITData):
                if self.container.contains_required_files:
                    if isinstance(self.container.settings, dict):
                        def_trigger_info = self.container.settings.get(
                            'DefaultTriggers', None)
            default_triggers = []
            default_descriptions = []
            if def_trigger_info is not None:
                default_triggers = [int(row[0]) for row in def_trigger_info]
                default_descriptions = [row[1] for row in def_trigger_info]

            channels_from_load = list(self.interesting_channels)
            """ optimise to only load interesting channels """
            for i in range(nchans):
                file.seek(chan_offset + i * chan_size)
                channel_type, = unpack('i', file.read(4))
                if channel_type in KIT.CHANNELS_MEG:
                    name = "MEG {0:03d}".format(i)
                elif (channel_type in KIT.CHANNELS_MISC
                      or channel_type == KIT.CHANNEL_NULL):
                    ch_type_label = KIT.CH_LABEL[channel_type]
                    name = "{0} {1:03d}".format(ch_type_label, i)
                self.channel_names.append(name)

                # only add the default channels if the list of channels loaded
                # is empty. Otherwise default channels removed before save will
                # be re-added
                if channels_from_load == []:
                    if i in default_triggers:
                        is_trigger = True
                        self.interesting_channels.add(i)
                    else:
                        is_trigger = False
                    if (i in self.interesting_channels
                            and i not in self.tab_info.keys()):
                        name_var = StringVar()
                        name_var.set(name)
                        bad_var = BooleanVar()
                        bad_var.set(False)
                        trigger_var = BooleanVar()
                        trigger_var.set(is_trigger)
                        if is_trigger:
                            idx = default_triggers.index(i)
                            description = default_descriptions[idx]
                        else:
                            description = ''
                        desc_var = StringVar()
                        desc_var.set(description)
                        self.tab_info[i] = [
                            name_var, bad_var, trigger_var, desc_var
                        ]

        self.loaded = True
예제 #28
0
class BaseFeature(Pane):
    _instance = None
    name = "Feature"
    pane = None
    bar = None
    icon = "blank"
    _view_mode = None
    _transparency_flag = None
    _side = None
    rec = (20, 20, 300, 300)  # Default window mode position
    _defaults = {
        "mode": "docked",
        "inactive_transparency": False,
        "position": "left",
        "visible": True,
        "side": "left",
        "pane": {
            "height": 300,
            "index":
            1000,  # setting 1000 allows the feature pane to pick an index
        },
        "pos": {
            "initialized": False,
            "x": 20,
            "y": 20,
            "width": 200,
            "height": 200,
        }
    }

    @classmethod
    def update_defaults(cls):
        pref = Preferences.acquire()
        path = "features::{}".format(cls.name)
        if not pref.exists(path):
            pref.set(path, copy.deepcopy(cls._defaults))
        else:
            pref.update_defaults(path, copy.deepcopy(cls._defaults))

    def __init__(self, master, studio=None, **cnf):
        super().__init__(master, **cnf)
        self.update_defaults()
        self.__class__._instance = self
        if not self.__class__._view_mode:
            self.__class__._view_mode = StringVar(None, self.get_pref('mode'))
            self.__class__._transparency_flag = t = BooleanVar(
                None, self.get_pref('inactive_transparency'))
            self.__class__._side = StringVar(None, self.get_pref('side'))
            self.is_visible = BooleanVar(None, self.get_pref('visible'))
            t.trace_add(
                "write",
                lambda *_: self.set_pref('inactive_transparency', t.get()))
        self.studio = studio
        Label(self._header, **self.style.text_accent,
              text=self.name).pack(side="left")
        self._min = Button(self._header,
                           image=get_icon_image("close", 15, 15),
                           **self.style.button,
                           width=25,
                           height=25)
        self._min.pack(side="right")
        self._min.on_click(self.minimize)
        self._pref = MenuButton(self._header, **self.style.button)
        self._pref.configure(image=get_icon_image("settings", 15, 15))
        self._pref.pack(side="right")
        self._pref.tooltip("Options")
        menu = self.make_menu(
            (("cascade", "View Mode", None, None, {
                "menu": (
                    ("radiobutton", "Docked", None, self.open_as_docked, {
                        "variable": self._view_mode,
                        "value": "docked"
                    }),
                    ("radiobutton", "Window", None, self.open_as_window, {
                        "variable": self._view_mode,
                        "value": "window"
                    }),
                )
            }), ("cascade", "Position", None, None, {
                "menu": (
                    ("radiobutton", "Left", None,
                     lambda: self.reposition("left"), {
                         "variable": self._side,
                         "value": "left"
                     }),
                    ("radiobutton", "Right", None,
                     lambda: self.reposition("right"), {
                         "variable": self._side,
                         "value": "right"
                     }),
                )
            }),
             EnableIf(lambda: self._view_mode.get() == 'window',
                      ("cascade", "Window options", None, None, {
                          "menu": (("checkbutton", "Transparent when inactive",
                                    None, None, {
                                        "variable": self._transparency_flag
                                    }), )
                      })), ("command", "Close", get_icon_image(
                          "close", 14, 14), self.minimize, {}),
             ("separator", ), *self.create_menu()), self._pref)
        self._pref.config(menu=menu)
        # self._pref.on_click(self.minimize)
        self.config(**self.style.surface)
        self.indicator = None
        self.window_handle = None
        self.on_focus(self._on_focus_get)
        self.on_focus_lost(self._on_focus_release)
        self.on_close(self.close_window)
        self._mode_map = {
            'window': self.open_as_window,
            'docked': self.open_as_docked
        }

    @classmethod
    def get_pref_path(cls, short_path):
        return "features::{}::{}".format(cls.name, short_path)

    @classmethod
    def get_pref(cls, short_path):
        return Preferences.acquire().get(cls.get_pref_path(short_path))

    @classmethod
    def set_pref(cls, short_path, value):
        Preferences.acquire().set(cls.get_pref_path(short_path), value)

    @classmethod
    def get_instance(cls):
        return cls._instance

    def on_select(self, widget):
        """
        Called when a widget is selected in the designer
        :param widget: selected widget
        :return:None
        """
        pass

    def on_widget_change(self, old_widget, new_widget=None):
        """
        Called when a widget is fundamentally altered
        :param old_widget: Altered widget
        :param new_widget: The new widget taking the older widgets place
        :return: None
        """
        pass

    def on_widget_layout_change(self, widget):
        """
        Called when layout options of a widget are changed
        :param widget: Widget with altered layout options
        :return: None
        """
        pass

    def on_widget_add(self, widget, parent):
        """
        Called when a new widget is added to the designer
        :param widget: widget
        :param parent: the container widget to which thw widget is added
        :return: None
        """
        pass

    def on_widget_delete(self, widget, silently=False):
        """
        Called when a widget is deleted from the designer
        :param widget: deleted widget
        :param silently: flag indicating whether the deletion should be treated implicitly
        which is useful for instance when you don't want the deletion to be logged in the
        undo stack
        :return: None
        """
        pass

    def on_widget_restore(self, widget):
        """
        Called when a deleted widget is restored
        :param widget: restored widget
        :return: None
        """
        pass

    def on_session_clear(self):
        """
        Override to perform operations before a session is cleared and the studio
        resets to a new design
        :return: None
        """
        pass

    def on_context_switch(self):
        """
        Override to perform operations when the active tab changes
        """
        pass

    def on_context_close(self, context):
        """
        Override to perform operations when a tab context is closed
        """
        pass

    def on_app_close(self) -> bool:
        """
        Override to perform operations before the studio app closes.
        :return: True to allow shutdown to proceed or False to abort shutdown
        """
        return True

    def minimize(self, *_):
        if self.window_handle:
            self.close_window()
            return
        self.studio.minimize(self)
        self.set_pref("visible", False)
        self.is_visible.set(False)

    def maximize(self):
        if self.get_pref("mode") == "window":
            self.open_as_window()
            self.bar.select(self)
        else:
            self.studio.maximize(self)
        self.set_pref("visible", True)
        self.is_visible.set(True)

    def toggle(self):
        if self.get_pref("visible"):
            self.minimize()
        else:
            self.maximize()

    def create_menu(self):
        """
        Override this method to provide additional menu options
        :return: tuple of menu templates i.e. (type, label, image, callback, **additional_config)
        """
        # return an empty tuple as default
        return ()

    def _on_focus_release(self):
        if self._transparency_flag.get() and self.window_handle:
            if self.window_handle:
                self.window_handle.wm_attributes('-alpha', 0.3)
        if self.window_handle:
            self.save_window_pos()

    def _on_focus_get(self):
        if self.window_handle:
            self.window_handle.wm_attributes('-alpha', 1.0)

    def open_as_docked(self):
        self._view_mode.set("docked")
        self.set_pref('mode', 'docked')
        if self.window_handle:
            self.master.window.wm_forget(self)
            self.window_handle = None
            self.maximize()

    def reposition(self, side):
        self._side.set(side)
        self.studio.reposition(self, side)

    def open_as_window(self):
        if TkVersion < 8.5:
            logging.error("Window mode is not supported in current tk version")
            return
        self.master.window.wm_forget(self)
        rec = absolute_position(
            self) if not self.get_pref("pos::initialized") else (
                self.get_pref("pos::x"),
                self.get_pref("pos::y"),
                self.get_pref("pos::width"),
                self.get_pref("pos::height"),
            )
        self.window.wm_manage(self)
        # Allow us to create a hook in the close method of the window manager
        self.bind_close()
        self.title(self.name)
        self.geometry('{}x{}+{}+{}'.format(rec[2], rec[3], rec[0], rec[1]))
        self.update_idletasks()
        self.window_handle = self
        self._view_mode.set("window")
        self.set_pref("mode", "window")
        self.studio._adjust_pane(self.pane)
        self.transient(self.master.window)
        self.save_window_pos()
        if self.focus_get() != self and self.get_pref("inactive_transparency"):
            self.window_handle.wm_attributes('-alpha', 0.3)

    def save_window_pos(self):
        if not self.window_handle:
            if self.winfo_ismapped():
                self.set_pref("pane::height", self.height)
            return
        self.update_idletasks()
        geometry = parse_geometry(self.geometry(), default=0)
        if geometry:
            # more accurate
            # cast geometry values returned to int
            self.set_pref(
                "pos",
                dict({k: int(v)
                      for k, v in geometry.items()},
                     initialized=True))
        else:
            raise Exception("Could not parse window geometry")

    def close_window(self):
        if self.window_handle:
            # Store the current position of our window handle to used when it is reopened
            self.save_window_pos()
            self.master.window.wm_forget(self)
            self.window_handle = None
            self.studio.minimize(self)
            self.set_pref("visible", False)
예제 #29
0
class ViewManager:
    def __init__(self):
        self.network_manager = NetworkManager(self.state_changer)
        self.running = True
        self.labels, self.entries, self.buttons = dict(), dict(), dict()
        self.root = Tk()
        self.override_data = BooleanVar()
        self.override_data.set(True)
        self.tk_root_setup()

    def tk_root_setup(self):
        self.root.title("Deshe AutoReporter")
        self.labels.update(
            {'username': Label(master=self.root, text="Username: "******"Password: "******"Username", command=None)
        })
        self.entries.update({
            'password':
            Entry(master=self.root, text="Password", show="*", command=None)
        })
        self.buttons.update({
            'authentication':
            Button(master=self.root,
                   text="Login",
                   command=lambda: self.network_manager.login(entries=self.
                                                              entries))
        })
        self.buttons.update({
            'override_data':
            Checkbutton(master=self.root,
                        text="Override existing data",
                        variable=self.override_data,
                        onvalue=True,
                        offvalue=False)
        })
        self.buttons.update({
            'submit_excel_hours':
            Button(master=self.root,
                   text="Submit Hours from Excel",
                   command=self.set_hours_from_excel,
                   state='disabled')
        })
        self.buttons.update({
            'get_salary':
            Button(master=self.root,
                   text="Last Salary",
                   command=self.network_manager.get_last_salary,
                   state='disabled')
        })
        row = 0
        for key in self.labels:
            self.labels[key].grid(row=row, column=0)
            row += 1
        row = 0
        for key in self.entries:
            self.entries[key].bind(
                '<Return>',
                lambda event: self.network_manager.login(entries=self.entries))
            self.entries[key].grid(row=row, column=1)
            row += 1
        column = 0
        for key in self.buttons:
            self.buttons[key].grid(row=2, column=column)
            column += 1
        menu_bar = Menu(master=self.root)
        self.root.config(menu=menu_bar)
        menu_bar.add_command(label="Close Window", command=self.close_app)
        menu_bar.add_command(label="Help!", command=self.help_user)
        self.root.after(200, lambda: self.geometry_setter(self.root))
        self.root.mainloop()

    def help_user(self):
        """
        Input: Clicked by user!
        Output: Explains about the program.
        Meaning: Contains information about the program.
        """
        top = Toplevel(master=self.root)
        top.title("Instructions")
        top.resizable(width=False, height=False)
        menu_bar = Menu(master=top)
        menu_bar.add_command(label="Quit", command=top.destroy)
        top.config(menu=menu_bar)
        labels = list()
        labels.append(
            Label(
                master=top,
                text="1) Insert your username and password in the given fields."
            ))
        labels.append(Label(master=top, text="2) Click login."))
        labels.append(
            Label(
                master=top,
                text=
                "3) Once you get the message you're authenticated you're good to go, else, retry."
            ))
        labels.append(
            Label(
                master=top,
                text=
                "4) If you want to run on existing dates tick v on override existing data."
            ))
        labels.append(
            Label(
                master=top,
                text=
                "5) Click Submit Hours from Excel, choose your excel hours file."
            ))
        labels.append(
            Label(master=top,
                  text="6)You're free to go, your hours have been submitted."))
        labels.append(
            Label(
                master=top,
                text=
                "\nNote) It doesn't take breaks in count, only the earliest hour and the latest one."
            ))
        for label in labels:
            label.pack()
        self.geometry_setter(top, minimum_x=500, minimum_y=160)

    def close_app(self):
        self.running = False
        self.root.quit()

    def state_changer(self, is_logged_in):
        if is_logged_in:
            self.update_when_need(self.buttons['submit_excel_hours'], 'state',
                                  'normal')
            self.update_when_need(self.buttons['get_salary'], 'state',
                                  'normal')
            self.update_when_need(self.buttons['authentication'], 'text',
                                  'Logout')
            for key in self.entries:
                self.update_when_need(self.entries[key], 'state', 'disabled')
        else:
            self.update_when_need(self.buttons['submit_excel_hours'], 'state',
                                  'normal')
            self.update_when_need(self.buttons['get_salary'], 'state',
                                  'disabled')
            self.update_when_need(self.buttons['authentication'], 'text',
                                  'Login')
            for key in self.entries:
                self.update_when_need(self.entries[key], 'state', 'normal')

    @staticmethod
    def update_when_need(element, field_to_change, variable):
        if element[field_to_change] != variable:
            element[field_to_change] = variable

    def set_hours_from_excel(self):
        path_to_excel = askopenfilename(
            title="Select your Excel file for import",
            filetypes=(("Excel Files", ".xlsx"), ))
        threads = []
        if path_to_excel:
            try:
                dates = DateManager(path_to_excel).get_all_days()
                for date in dates:
                    if date.get('dead'):
                        showinfo('Invalid Credential', date)
                    elif date.get('reason'):
                        thr = Thread(
                            target=self.network_manager.enter_special_occasion,
                            args=(date['reason'], date['start_date'],
                                  date['hours'], date['minutes'],
                                  date['elaboration_text'],
                                  self.override_data))
                        thr.start()
                        threads.append(thr)
                    else:
                        thr = Thread(target=self.network_manager.report_shift,
                                     args=(date['start_date'],
                                           date['end_date'],
                                           date['elaboration_text'],
                                           self.override_data))
                        thr.start()
                        threads.append(thr)
                for thr in threads:
                    thr.join()
                showinfo('Submitted', 'Hours successfully passed!')
            except TimeoutException as ex:
                showinfo('Timeout', 'Error ' + str(ex))
        else:
            showinfo('Cancelled', 'Process cancelled.')

    @staticmethod
    def geometry_setter(root, minimum_x=0, minimum_y=0):
        root.minsize(width=root.winfo_width() + minimum_x,
                     height=root.winfo_height() + minimum_y)
        x_width_pos = int(
            (root.winfo_screenwidth() - (root.winfo_width() + minimum_x)) / 2)
        y_height_pos = int((root.winfo_screenheight() -
                            (root.winfo_height() + minimum_y)) / 2)
        geometry_text = str(root.winfo_width() + minimum_x) + "x" + str(
            root.winfo_height() +
            minimum_y) + "+" + str(x_width_pos -
                                   75) + "+" + str(y_height_pos) + ""
        root.geometry(geometry_text)
        root.update()
예제 #30
0
class Gui(Tk):
    ''' ------------------------------------------------------------------------------------------------ '''
    def __init__(self):

        Tk.__init__(self)
        self.title("Steam Career - " + constants.APP_VERSION)
        self.iconbitmap(os.getcwd() + '\\resources\\favicon.ico')

        self.buildGui()
        self.__centre(self)

    ''' ------------------------------------------------------------------------------------------------ '''

    def __centre(self, toplevel):

        toplevel.update_idletasks()

        w = toplevel.winfo_screenwidth()
        h = toplevel.winfo_screenheight()

        size = tuple(
            int(_) for _ in toplevel.geometry().split('+')[0].split('x'))

        x = w / 2 - size[0] / 2
        y = h / 2 - size[1] / 2

        toplevel.geometry("%dx%d+%d+%d" % (size + (x, y)))

    ''' ------------------------------------------------------------------------------------------------ '''

    def __setResultLocation(self):
        filename = filedialog.askdirectory()
        self.resultLocation.set(filename)

    ''' ------------------------------------------------------------------------------------------------ '''

    def __generateResult(self):
        try:
            os.makedirs(os.path.dirname(constants.CONF_FILE_STEAM_USER),
                        exist_ok=True)
            with open(constants.CONF_FILE_STEAM_USER, "wb") as f:
                f.write(self.entry.get().encode("UTF-8"))

            os.makedirs(os.path.dirname(constants.CONF_FILE_STEAM_API_KEY),
                        exist_ok=True)
            with open(constants.CONF_FILE_STEAM_API_KEY, "wb") as f:
                f.write(self.apiKeyEntry.get().encode("UTF-8"))

            os.makedirs(os.path.dirname(constants.CONF_RESULT_LOCATION),
                        exist_ok=True)
            with open(constants.CONF_RESULT_LOCATION, "wb") as f:
                f.write(self.resultLocationEntry.get().encode("UTF-8"))

            os.makedirs(os.path.dirname(constants.OVERWRITE_CSS_LOCATION),
                        exist_ok=True)
            with open(constants.OVERWRITE_CSS_LOCATION, "wb") as f:
                if (self.overwriteCssState.get() == True):
                    f.write("true".encode("UTF-8"))
                else:
                    f.write("false".encode("UTF-8"))

            logic.generateResultPage(self.apiKeyEntry.get(), self.entry.get(),
                                     self.resultLocationEntry.get(),
                                     self.overwriteCssState.get())

        except Exception as exception:
            messagebox.showerror("Error", str(exception))

    ''' ------------------------------------------------------------------------------------------------ '''

    def buildGui(self):
        padx = 5
        pady = 5

        self.frame = Frame(self)
        self.frame.pack(padx=padx, pady=pady)

        self.bottomframe = Frame(self)
        self.bottomframe.pack(side=BOTTOM, padx=padx, pady=pady)

        self.__buildUsername(padx, pady)
        self.__buildApiKey(padx, pady)
        self.__buildResultLocation(padx, pady)
        self.__buildOverwriteCss(padx, pady)

        self.button = Button(self.bottomframe,
                             text="Go",
                             command=self.__generateResult,
                             height=2,
                             width=30,
                             padx=padx,
                             pady=pady)
        self.button.pack(side=BOTTOM)

    ''' ------------------------------------------------------------------------------------------------ '''

    def __buildUsername(self, padx, pady):
        self.label = Label(self.frame, text="User Name")
        self.label.grid(row=0, column=0, sticky=E, padx=padx, pady=pady)

        self.entry = Entry(self.frame, width=40)
        if os.path.isfile(constants.CONF_FILE_STEAM_USER):
            with open(constants.CONF_FILE_STEAM_USER, 'r') as myfile:
                steamApiUser = myfile.read().replace('\n', '')
            self.entry.insert(END, steamApiUser)
        self.entry.grid(row=0, column=1, padx=padx, pady=pady)

    ''' ------------------------------------------------------------------------------------------------ '''

    def __buildApiKey(self, padx, pady):
        self.apiKeyLabel = Label(self.frame, text="API Key")
        self.apiKeyLabel.grid(row=1, column=0, sticky=E, padx=padx, pady=pady)

        self.apiKeyEntry = Entry(self.frame, width=40)
        if os.path.isfile(constants.CONF_FILE_STEAM_API_KEY):
            with open(constants.CONF_FILE_STEAM_API_KEY, 'r') as myfile:
                steamApiKey = myfile.read().replace('\n', '')
            self.apiKeyEntry.insert(END, steamApiKey)
        self.apiKeyEntry.grid(row=1, column=1, padx=padx, pady=pady)

    ''' ------------------------------------------------------------------------------------------------ '''

    def __buildResultLocation(self, padx, pady):
        self.resultLocationLabel = Label(self.frame, text="Result Location")
        self.resultLocationLabel.grid(row=2,
                                      column=0,
                                      sticky=E,
                                      padx=padx,
                                      pady=pady)

        self.resultLocation = StringVar()
        self.resultLocationEntry = Entry(self.frame,
                                         textvariable=self.resultLocation,
                                         width=40)
        if os.path.isfile(constants.CONF_RESULT_LOCATION):
            with open(constants.CONF_RESULT_LOCATION, 'r') as myfile:
                resultLocation = myfile.read().replace('\n', '')
            self.resultLocationEntry.insert(END, resultLocation)
        self.resultLocationEntry.grid(row=2, column=1, padx=padx, pady=pady)

        self.resultLocationButton = Button(self.frame,
                                           text="...",
                                           command=self.__setResultLocation,
                                           height=1,
                                           width=1,
                                           padx=padx,
                                           pady=pady)
        self.resultLocationButton.grid(row=2, column=2, padx=padx, pady=pady)

    ''' ------------------------------------------------------------------------------------------------ '''

    def __buildOverwriteCss(self, padx, pady):
        self.overwriteCssLabel = Label(self.frame, text="Overwrite CSS?")
        self.overwriteCssLabel.grid(row=3,
                                    column=0,
                                    sticky=E,
                                    padx=padx,
                                    pady=pady)
        self.overwriteCssState = BooleanVar()
        self.overwriteCss = Checkbutton(self.frame,
                                        justify=tkinter.LEFT,
                                        variable=self.overwriteCssState)
        if os.path.isfile(constants.OVERWRITE_CSS_LOCATION):
            with open(constants.OVERWRITE_CSS_LOCATION, 'r') as myfile:
                if myfile.read().replace('\n', '') == 'true':
                    self.overwriteCssState.set(True)
                else:
                    self.overwriteCssState.set(False)
        self.overwriteCss.grid(row=3, column=1, sticky=W, padx=padx, pady=pady)
예제 #31
0
class ImporterGUI:
    """
    This class is the main gui and shows the import window, it also contains the main methods which uses other helper classes

    Attributes:
        root = the root tk
        previewFrame = the frame that shows the preview of the dataframe
        XMLList = the 2D list which holds the xml filepath on the index 0 and the xsl filepath on index 1
    """
    def __init__(self, root: Tk):
        self.root = root
        self.previewFrame = Frame(root)
        self.pt = Table(self.previewFrame)
        self.dialect = detector.Dialect()
        self.XMLList = []
        self.DialectList = []
        self.hasHeaderVar = BooleanVar()
        self.currentPath = ""

        h1 = Label(self.root, text="Imported Files", bg="#eee")
        h1.pack(padx=5, pady=5, fill="x")

        # Dialog Frame
        dialogFrame = Frame(self.root)
        dialogFrame.grid_columnconfigure(1, weight=1)
        Button(dialogFrame,
               text="Import Files",
               command=self.openFileDialog,
               width=20).grid(row=0, column=0)
        Button(dialogFrame,
               text="Delete selected File",
               command=self.deleteSelectedFile,
               width=20).grid(row=1, column=0)
        Button(dialogFrame,
               text="Delete all",
               command=self.deleteAllFiles,
               width=20).grid(row=2, column=0)

        # the outside frame for the files listbox (it holds the listbox and the scrollbar)
        listbox_border = Frame(dialogFrame,
                               bd=2,
                               relief="sunken",
                               background="white")
        listbox_border.grid(row=0, column=1, rowspan=3, padx=3, sticky="nsew")

        # the actual listbox
        self.importedFiles = Listbox(listbox_border,
                                     selectmode=SINGLE,
                                     height=4,
                                     borderwidth=0,
                                     highlightthickness=0,
                                     relief=SUNKEN,
                                     background="white")
        self.importedFiles.bind("<<ListboxSelect>>", self.selectionChanged)

        # the scrollbar inside the listbox_border frame
        vsb = Scrollbar(listbox_border,
                        orient="vertical",
                        command=self.importedFiles.yview)
        self.importedFiles.configure(yscrollcommand=vsb)
        vsb.pack(side="right", fill="y")
        self.importedFiles.pack(padx=2, pady=2, fill="both", expand=True)
        dialogFrame.pack(fill="x", padx=10)

        # XSL File Frame (its disabled when a csv file is selected in the listbox,
        # and set to "normal" when a xml is selected
        h1 = Label(root, text="XSL File", bg="#eee")
        h1.pack(padx=5, pady=5, fill="x")
        xslFrame = Frame(root)
        self.importXSL_btn = Button(xslFrame,
                                    state=DISABLED,
                                    text="Import XSL File",
                                    command=self.openXSLFileDialog,
                                    width=20)
        self.importXSL_btn.grid(row=0, column=0)
        self.XSLPath_text = Text(xslFrame,
                                 height=1,
                                 borderwidth=2,
                                 relief=SUNKEN)
        self.XSLPath_text.grid(row=0, column=1)
        xslFrame.pack(fill="x", padx=10, pady=5)

        # Detector Frame
        h1 = Label(root, text="Detector", bg="#eee")
        h1.pack(padx=5, pady=5, fill="x")
        detectorFrame = Frame(root)

        Label(detectorFrame,
              text="Encoding:",
              width=20,
              anchor="w",
              justify="left").grid(row=0)
        self.encodingText = Text(detectorFrame,
                                 height=1,
                                 borderwidth=2,
                                 relief=SUNKEN,
                                 width=10)
        self.encodingText.grid(row=0, column=1)

        Label(detectorFrame,
              text="Has Header:",
              width=20,
              anchor="w",
              justify="left").grid(row=1)
        self.hasHeaderCheckbutton = Checkbutton(detectorFrame,
                                                var=self.hasHeaderVar,
                                                onvalue=1,
                                                offvalue=0)
        self.hasHeaderCheckbutton.grid(sticky="W", row=1, column=1)

        Label(detectorFrame,
              text="Seperator:",
              width=20,
              anchor="w",
              justify="left").grid(row=2)
        self.seperatorText = Text(detectorFrame,
                                  height=1,
                                  borderwidth=2,
                                  relief=SUNKEN,
                                  width=10)
        self.seperatorText.grid(row=2, column=1)

        Label(detectorFrame,
              text="Quote Char:",
              width=20,
              anchor="w",
              justify="left").grid(row=3)
        self.quoteCharText = Text(detectorFrame,
                                  height=1,
                                  borderwidth=2,
                                  relief=SUNKEN,
                                  width=10)
        self.quoteCharText.grid(row=3, column=1)

        Button(detectorFrame,
               text="Save Dialect Changes",
               command=self.saveDialectChanges,
               width=20).grid(row=4, column=0)

        detectorFrame.pack(fill="x", padx=10, pady=5)

        # dataframe preview frame
        preview = Label(root, text="Preview", bg="#eee")
        preview.pack(expand=TRUE, fill="x", padx=5, side=TOP)
        self.pt.show()
        self.previewFrame.pack(pady=10, padx=10, fill="both", side=TOP)

        # the bottom most centered export button which leads to the export window
        exportBtn = Button(root,
                           text="Export",
                           command=self.export,
                           width=20,
                           padx=0)
        exportBtn.pack(fill="x", padx=10, pady=10)

    def saveDialectChanges(self):
        """
        saves the Dialect changes made by the user
        """
        dialect = detector.Dialect()
        dialect.encoding = self.encodingText.get(1.0, 'end-1c')
        dialect.hasHeader = self.hasHeaderVar.get()
        dialect.delimiter = self.seperatorText.get(1.0, 'end-1c')
        dialect.quoteChar = self.quoteCharText.get(1.0, 'end-1c')
        if not self.currentPath:
            files = self.getImportedFiles()
            self.currentPath = files[0]
        path = self.currentPath
        print(path)
        if not any(path in x for x in self.DialectList):
            self.DialectList.append([path, dialect])
        elif any(path in x for x in self.DialectList):
            x = [x for x in self.DialectList if path in x][0]
            self.DialectList[self.DialectList.index(x)][1] = dialect
        self.updateDf(self.getImportedFiles())

    def selectionChanged(self, event):
        """
        this is an event which is triggered by selection changed inside the listbox widget
        it checks if the selected file is a xml, if so it sets the textbox intractable for the user

        :param event: the event which called it
        """
        selection = event.widget.curselection()
        if selection:
            data = event.widget.get(selection[0])
            self.currentPath = data
            if data.endswith(".xml"):
                # disable encoding changes
                self.encodingText.delete(1.0, END)
                self.hasHeaderVar.set(False)
                self.seperatorText.delete(1.0, END)
                self.quoteCharText.delete(1.0, END)
                self.encodingText["state"] = "disabled"
                self.hasHeaderCheckbutton["state"] = "disabled"
                self.seperatorText["state"] = "disabled"
                self.quoteCharText["state"] = "disabled"
                self.importXSL_btn["state"] = "normal"

                if any(data in x for x in self.XMLList):
                    x = [x for x in self.XMLList if data in x][0]
                    self.XSLPath_text.delete(1.0, END)
                    self.XSLPath_text.insert(
                        1.0, self.XMLList[self.XMLList.index(x)][1])
                else:
                    self.XSLPath_text.delete(1.0, END)
                    self.XSLPath_text.insert(1.0, "please import a XSL File!")
            else:
                self.encodingText.delete(1.0, END)
                self.hasHeaderVar.set(False)
                self.seperatorText.delete(1.0, END)
                self.quoteCharText.delete(1.0, END)
                self.encodingText["state"] = "normal"
                self.hasHeaderCheckbutton["state"] = "normal"
                self.seperatorText["state"] = "normal"
                self.quoteCharText["state"] = "normal"
                self.importXSL_btn["state"] = "disabled"
                self.XSLPath_text.delete(1.0, END)

                if any(data in x for x in self.DialectList):
                    x = [x for x in self.DialectList if data in x][0]
                    dialect = self.DialectList[self.DialectList.index(x)][1]
                    self.updateDialect(dialect)

    def openXSLFileDialog(self):
        """
        this function is called if the user wants to import a xsl file in the xsl file frame
        it opens the filedialog and appends the xsl to the according xml into the XMLList attribute
        after that, it try's to update the dataframe and its preview by calling the update function
        """
        file = askopenfilename(parent=self.root,
                               title='Choose a file',
                               filetypes=[("Extensible Stylesheet Language",
                                           "*.xsl"), ("All files", "*.*")])
        self.XMLList.append(
            [self.importedFiles.get(self.importedFiles.curselection()), file])
        self.XSLPath_text.delete(1.0, END)
        self.XSLPath_text.insert(1.0, file)
        self.updateDf(self.getImportedFiles())

    def openFileDialog(self):
        """
        this function opens the file dialog and imports the selected filepaths into the listbox and also
        calls the update function to redraw the new dataframe
        """
        files = list(
            askopenfilenames(parent=self.root,
                             title='Choose a file',
                             filetypes=[("Excel files", ".xml .csv")]))
        self.updateSelectedFiles(files)
        self.updateDf(self.getImportedFiles())

    def deleteSelectedFile(self):
        """
        deletes the selected file from the listbox and redraws the dataframe since one of its source is deleted
        also if a xml file is deleted, it also deletes the corresponding xsl file from the XMLList
        """
        path = self.importedFiles.get(self.importedFiles.curselection())
        if path is self.currentPath:
            self.currentPath = ""
        # delete from dialect list
        if any(path in x for x in self.DialectList):
            x = [x for x in self.DialectList if path in x][0]
            self.DialectList.pop(self.DialectList.index(x))

        index = self.importedFiles.get(0, END).index(path)
        self.importedFiles.delete(index)

        # delete from xml list
        if path.endswith(".xml"):
            x = [x for x in self.XMLList if path in x][0]
            self.XMLList.pop(self.XMLList.index(x))
        self.updateDf(self.getImportedFiles())

    def deleteAllFiles(self):
        """
        deletes all imported filepaths from the listbox and also from the dataframe
        """
        self.importedFiles.delete(0, END)
        self.currentPath = ""
        self.XMLList = []
        self.DialectList = []

    def getImportedFiles(self):
        """
        :return: returns the selected filepath from the listbox
        """
        return self.importedFiles.get(0, END)

    def updateSelectedFiles(self, files):
        """
        after opening a file dialog, this method is called to pass the new imported filepaths into the listbox

        :param files: filespaths from the filedialog
        """
        startIndex = self.importedFiles.size()
        for index, file in enumerate(files):
            self.importedFiles.insert(index + startIndex, file)

    def export(self):
        """
        opens the export window and passes the dataframe from the preview frame
        """
        importer.setDataFrame(self.pt.model.df)
        ExporterGUI(self.root, importer, self.dialect)

    def updateDf(self, files: list):
        """
        checks if the dataframe can be updated by the newly imported filepaths
        calls the merge function if there is more than 1 file inside the filelist
        also udpates the detector frame (displaying dialect data)

        :param files: the whole filepath list
        """
        if len(files) > 1 or len(self.XMLList) > 0:
            canMerge = merger.prepareMerge(files, self.XMLList,
                                           self.DialectList)
            self.DialectList = merger.dialectList
            if canMerge:
                newDataFrame = merger.mergeFiles()
                importer.setDataFrame(newDataFrame)
                self.pt.updateModel(TableModel(newDataFrame))
                self.pt.redraw()
        elif len(files) > 0 and files[0].endswith(".csv"):
            if not any(files[0] in x for x in self.DialectList):
                self.dialect.guessDialectCSV(files[0])
                self.DialectList.append([files[0], self.dialect])
            else:
                x = [x for x in self.DialectList if files[0] in x][0]
                self.dialect = self.DialectList[self.DialectList.index(x)][1]
            importer.importCSV(files[0], self.dialect)
            updatedDataframe = importer.getDataFrame()
            self.pt.updateModel(TableModel(updatedDataframe))
            self.pt.redraw()
            self.updateDialect(self.dialect)

    def updateDialect(self, dialect: detector.Dialect):
        """
        updates the dialect text fields from the gui
        :param dialect: the new changed dialect
        """
        # updates the dialect data
        self.encodingText.delete(1.0, END)
        self.encodingText.insert(1.0, dialect.encoding)

        self.hasHeaderVar.set(dialect.hasHeader)

        self.seperatorText.delete(1.0, END)
        self.seperatorText.insert(1.0, dialect.delimiter)

        self.quoteCharText.delete(1.0, END)
        self.quoteCharText.insert(1.0, dialect.quoteChar)
예제 #32
0
ttk.Checkbutton(mainframe, variable=grass_e).grid(column=4, row=1, sticky=(W))
ttk.Entry(mainframe, textvariable=no_branch_grace_e).grid(column=4,
                                                          row=2,
                                                          sticky=(W))

ttk.Entry(mainframe, textvariable=seed_e).grid(column=1,
                                               row=18,
                                               sticky=(W),
                                               columnspan=2)
ttk.OptionMenu(mainframe, save_size_e, save_sizes[1],
               *save_sizes).grid(column=1, row=19, sticky=(W), columnspan=2)

ttk.Button(
    mainframe,
    text="Regenerate",
    command=lambda: [x() for x in [lambda: animate_e.set(False), gen]]).grid(
        column=1, row=20, sticky=W)
ttk.Button(mainframe,
           text="Random Seed",
           command=lambda:
           [x() for x in [lambda: animate_e.set(False), set_seed, gen]]).grid(
               column=2, row=20, sticky=W)
ttk.Button(mainframe,
           text="Animate",
           command=lambda: [x() for x in [lambda: animate_e.set(True), gen]]
           if not animate_e.get() else None).grid(column=3, row=20, sticky=W)
ttk.Button(mainframe, text="Save", command=save).grid(column=0,
                                                      row=20,
                                                      sticky=W)
ttk.Button(mainframe, text="Save Animation",
           command=save_animation).grid(column=4, row=20, sticky=W)
예제 #33
0
class MediumQuestions(Frame):
    def __init__(self, master=None, cnf={}, **kw):
        self.root = Tk()
        self.root.title("Medium questions")
        self.root.option_add("*Font", "arial 18")
        self.root.geometry("800x400")
        self.questions = QuestionService.open_json_by_tag("medium")
        self.var1 = BooleanVar()
        self.var2 = BooleanVar()
        self.var3 = BooleanVar()
        self.var4 = BooleanVar()
        self.pos = -1
        self.root.grid()
        self.render()
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        self.root.mainloop()

    def create_widgets(self):
        lb = Label(self.root, text=self.questions[self.pos]['text'])
        lb.pack(side=TOP)
        variants = self.questions[self.pos]['answers']
        self.var1.set(0)
        self.var2.set(0)
        self.var3.set(0)
        self.var4.set(0)
        self.checkbuttons = list()
        c1 = Checkbutton(self.root,
                         text=variants["1"],
                         variable=self.var1,
                         onvalue=1,
                         offvalue=0)
        c1.pack()
        self.checkbuttons.append(c1)
        c2 = Checkbutton(self.root,
                         text=variants["2"],
                         variable=self.var2,
                         onvalue=1,
                         offvalue=0)
        c2.pack()
        self.checkbuttons.append(c2)
        c3 = Checkbutton(self.root,
                         text=variants["3"],
                         variable=self.var3,
                         onvalue=1,
                         offvalue=0)
        c3.pack()
        self.checkbuttons.append(c3)
        c4 = Checkbutton(self.root,
                         text=variants["4"],
                         variable=self.var4,
                         onvalue=1,
                         offvalue=0)
        c4.pack()
        self.checkbuttons.append(c4)
        Button(self.root, text="Next question",
               command=self.next_question).pack(side=LEFT)

    def next_question(self):
        if self.var1.get() == 0 and self.var2.get() == 0 and self.var3.get(
        ) == 0 and self.var4.get() == 0:
            warning = Tk()
            warning.geometry("100x50")
            Label(warning, text='Pick a variant!').pack(side=TOP)
        else:
            vars = [self.var1, self.var2, self.var3, self.var4]
            res = zip(self.checkbuttons, vars)
            tmp = list()
            for el in res:
                if el[1].get() == True:
                    tmp.append(el[0].cget('text'))
            print(tmp)
            set_answers = set(tmp)
            set_correct = set(self.questions[self.pos]['correctAns'])
            if set_answers == set_correct:
                QuestionService.answers.append(len(set_correct))
            elif len(set_answers) > len(set_correct):
                QuestionService.answers.append(0)
            elif set_correct - set_answers == {}:
                QuestionService.answers.append(0)
            else:
                QuestionService.answers.append(
                    len(set_correct - (set_correct - set_answers)))
            # QuestionService.answers.append(tmp == self.questions[self.pos]['correctAns'])
            # tmp.clear()
            self.render()

    def render(self):
        self.pos += 1
        for w in self.root.winfo_children():
            w.destroy()
        if self.pos == len(self.questions):
            self.root.destroy()
        else:
            self.create_widgets()

    def on_closing(self):
        if messagebox.askokcancel("Quit", "Are you sure?"):
            self.root.destroy()
            exit(0)
예제 #34
0
class take_data:
    '''
    '''

    def __init__(self, pype, toplevel=False, filename=False, num_sequences=10,
                 run_tag=''):
        '''
        '''
        self.pype = pype
        self.toplevel = toplevel

        self.keep_runningVar = BooleanVar(value=True)
        self.extend_runVar = BooleanVar(value=False)
        self.run_typeVar = StringVar(value="/tmp/")
        self.run_tagVar = StringVar(value=run_tag)
        self.num_sequencesVar = IntVar(value=num_sequences)
        self.sequence_spacingVar = DoubleVar(value=0)
        self.len_sequenceVar = DoubleVar()
        self.stateVar = StringVar(value='done')
        self.conf_filename = StringVar(value='')
        self.params = {}
        self.runthread = multiprocessing.Process()

        self._GetParamFuncs()
        if toplevel:
            self._BuildGui()

    def _BuildGui(self):
        '''
            Setup all of the buttons and user entries
        '''
        # Data Location
        row = 0
        Label(self.toplevel, text='-'*20+'Data Location'+'-'*20).grid(row=row,
                                                        columnspan=3, column=0)
        row += 1
        Label(self.toplevel, text='/data').grid(row=row, column=0, sticky='E')
        run_type_options = ["/tmp/", "/commissioning/", "/runs/"]
        OptionMenu(self.toplevel, self.run_typeVar, *run_type_options).grid(
                                             row=row, column=1, sticky='EW')
        Entry(self.toplevel, textvariable=self.run_tagVar).grid(row=row,
                                                                column=2)
        Checkbutton(self.toplevel, text="Extend if Exists",
                    variable=self.extend_runVar).grid(row=row, column=3)
        row += 1
        Label(self.toplevel, text="(raid location)").grid(row=row, column=0, sticky='E')
        Label(self.toplevel, text="(run type)").grid(row=row, column=1)
        Label(self.toplevel, text="(run tag)").grid(row=row, column=2)
        row += 1

        # Acquisition Cycle Details
        Label(self.toplevel, text='-'*20+'Acquisition Cycles'+'-'*20).grid(row=row,
                                                        columnspan=3, column=0)
        row += 1
        Label(self.toplevel, text='Number of Sequences').grid(row=row,
                                                              column=0)
        Entry(self.toplevel, textvariable=self.num_sequencesVar).grid(row=row,
                                                                      column=1)
        row += 1
        Label(self.toplevel, text='Delay Between').grid(row=row, column=0)
        Entry(self.toplevel, textvariable=self.sequence_spacingVar).grid(row=row, column=1)
        Label(self.toplevel, text='[s]').grid(row=row, column=2, sticky='W')
        row += 1
        builtins_list = ['default_run', 'noise_analysis_run']
        self.conf_filename.set(builtins_list[0])
        Button(self.toplevel, text='Load Builtin Run Def',
               command=self._GetParamFuncs).grid(row=row, column=0)
        OptionMenu(self.toplevel, self.conf_filename, *builtins_list).grid(
            row=row, column=1)
        self.conf_filename.set(builtins_list[0])
        row += 1
        Label(self.toplevel, text='Load Custom Run Def').grid(row=row,
                                                              column=0)
        Button(self.toplevel, text="find file", command=self._ParamFuncFile
               ).grid(row=row, column=1)
        row += 1

        # Mantis Settings
        Label(self.toplevel, text='-'*20+'Mantis Settings'+'-'*20).grid(row=row,
                                                        columnspan=3, column=0)
        row += 1
        Label(self.toplevel, text='(Empty fields use default values)').grid(row=row,
                                                        columnspan=3, column=0)
        row += 1
        Label(self.toplevel, text='Digitization Time').grid(row=row, column=0)
        Entry(self.toplevel, textvariable=self.len_sequenceVar).grid(row=row,
                                                                     column=1)
        Label(self.toplevel, text='[ms]').grid(row=row, column=2, sticky='W')
        row += 1

        Button(self.toplevel, text="Start Run", command=self.DoRun
               ).grid(row=row, column=0)
        Button(self.toplevel, text="ABORT", command=self._Abort, bg='red'
               ).grid(row=row, column=1)
        Label(self.toplevel, textvariable=self.stateVar).grid(row=row, column=2)

    def _ParamFuncFile(self):
        '''
        '''
        self.conf_filename.set(askopenfilename())
        if self.conf_filename.get():
            self._GetParamFuncs()

    def _Abort(self):
        '''
        '''
        self.keep_runningVar.set(False)
        if self.runthread.is_alive():
            print('terminating child process')
            self.runthread.terminate()
        else:
            print('no current thread')
        self.stateVar.set('aborted')

    def _IsRunning(self):
        '''
        '''
        print(self.runthread.is_alive())

    def _GetParamFuncs(self):
        '''
        '''
        fname = self.conf_filename.get()
        if not fname or fname == 'default_run':
            if not 'run_params' in sys.modules:
                from . import default_run as run_params
            else:
                reload(run_params)
        elif fname == 'noise_analysis_run':
            from . import noise_analysis_run as run_params
        else:
            imp.load_source('run_params', fname)
            import run_params
        self.DefaultParams = run_params.DefaultParams
        self.SequenceParams = run_params.SequenceParams
        self.FilenamePrefix = run_params.FilenamePrefix
        self.Mantis_kwargs = run_params.Mantis_kwargs()
        if 'duration' in self.Mantis_kwargs:
            self.len_sequenceVar.set(self.Mantis_kwargs['duration'])

    def DoRun(self):
        '''
            Execute the run
        '''
        self.keep_runningVar.set(True)
        self.stateVar.set('normal')
        if self.runthread.is_alive():
            print('there is already live process, abort first or let it finish')
        else:
            self.runthread = multiprocessing.Process(target=self.__DoRun)
            self.runthread.start()

    def __DoRun(self):
        '''
            the run called by DoRun in a subprocess
        '''
        self.params['run_tag'] = self.run_tagVar.get()
        self.params['num_sequences'] = self.num_sequencesVar.get()
        print('setting defaults')
        self._SetParams(self.DefaultParams())
        for sequence_num in range(self.params['num_sequences']):
            print('--> starting sequence {0}/{1}'.format(sequence_num, self.params['num_sequences'] - 1))
            if not self.keep_runningVar.get():
                print('Aborting!')
                break
            self._DoSequence(sequence_num)
            print('--> sequence {0}/{1} complete.'.format(sequence_num, self.params['num_sequences'] - 1))
            sleep(self.sequence_spacingVar.get())
        print('-> run (tag: {0}) complete.'.format(self.params['run_tag']))
        self.stateVar.set('run complete')

    def _SetParams(self, params_list):
        '''
        '''
        for channel_name, value in params_list:
            setattempt = self.pype.Set(channel_name, value)
            setattempt.Wait()
            if setattempt.Waiting():
                raise NoResponseError('setting ' + str(channel_name))
            print(channel_name, '->', value)

    def _DoSequence(self, sequence_number):
        '''
            Do one sequence within the run
        '''
        mantis_kwargs = self.Mantis_kwargs.copy()
        run_doc = self.pype.NewDump(uuid4().hex, self.params['run_tag'],
                                    new_run=((not sequence_number) and
                                    not self.extend_runVar.get()))
        self._SetParams(self.SequenceParams(sequence_number))
        for channel in self.pype.ListWithProperty('dump'):
            run_doc[channel] = self.pype.Get(channel)
            run_doc[channel].Update()
            run_doc[channel].Wait()
        run_doc._UpdateTo()
        outfilename = '/data/{:s}_{:05d}_{:05d}.egg'.format(
            self.FilenamePrefix(sequence_number),
            run_doc['run_number'],
            run_doc['sequence_number'])
        print('outputting '+outfilename)
        run_descrip = ast.literal_eval(mantis_kwargs['description'])
        for (chan, val) in self.SequenceParams(sequence_number):
            run_descrip[chan] = val
        run_descrip['run_tag'] = self.params['run_tag']
        run_doc['sequence_tag'] = dumps(run_descrip)
        mantis_kwargs.update({'output': outfilename,
                              'description': dumps(run_descrip),
                              'duration': self.len_sequenceVar.get()})
        run = self.pype.RunMantis(**mantis_kwargs)
        print('mantis run starting')
        run.Wait()
        run_doc['mantis'] = run
        run_doc._UpdateTo()
예제 #35
0
class ChkBoxes(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, master=parent)

        self.lbl_printfilt = tk.Label(self,
                                      text="Print Filters: ",
                                      font=("Times", 20))
        self.lbl_printfilt.grid(row=0, column=0)

        self.title = BooleanVar(self)
        self.title.set(True)
        self.genre = BooleanVar(self)
        self.genre.set(True)
        self.director = BooleanVar(self)
        self.director.set(True)
        self.vrate = BooleanVar(self)
        self.vrate.set(True)
        self.srate = BooleanVar(self)
        self.srate.set(True)
        self.relyear = BooleanVar(self)
        self.relyear.set(True)
        self.tb = BooleanVar(self)
        self.tb.set(True)

        self.chk_1 = tk.Checkbutton(self,
                                    text="Title",
                                    variable=self.title,
                                    selectcolor="black",
                                    font=("Times", 15))
        self.chk_1.grid(row=1, column=0, sticky="w")

        self.chk_2 = tk.Checkbutton(self,
                                    text="Genre",
                                    variable=self.genre,
                                    selectcolor="black",
                                    font=("Times", 15))

        self.chk_2.grid(row=2, column=0, sticky="w")

        self.chk_3 = tk.Checkbutton(self,
                                    text="Director",
                                    variable=self.director,
                                    selectcolor="black",
                                    font=("Times", 15))
        self.chk_3.grid(row=3, column=0, sticky="w")

        self.chk_4 = tk.Checkbutton(self,
                                    text="Viewer Rating",
                                    selectcolor="black",
                                    variable=self.vrate,
                                    font=("Times", 15))
        self.chk_4.grid(row=1, column=1, sticky="w")

        self.chk_5 = tk.Checkbutton(self,
                                    text="Star Rating",
                                    selectcolor="black",
                                    variable=self.srate,
                                    font=("Times", 15))
        self.chk_5.grid(row=2, column=1, sticky="w")

        self.chk_6 = tk.Checkbutton(self,
                                    text="Release Year",
                                    selectcolor="black",
                                    variable=self.relyear,
                                    font=("Times", 15))
        self.chk_6.grid(row=3, column=1, sticky="w")

        self.chk_7 = tk.Checkbutton(self,
                                    text="Top-Billed",
                                    selectcolor="black",
                                    variable=self.tb,
                                    font=("Times", 15))
        self.chk_7.grid(row=4, column=0, sticky="w")

        self.grid_columnconfigure(0, weight=1)
        self.grid_columnconfigure(1, weight=1)
예제 #36
0
파일: GrepDialog.py 프로젝트: Darriall/idle
class GrepDialog(SearchDialogBase):

    title = "Find in Files Dialog"
    icon = "Grep"
    needwrapbutton = 0

    def __init__(self, root, engine, flist):
        SearchDialogBase.__init__(self, root, engine)
        self.flist = flist
        self.globvar = StringVar(root)
        self.recvar = BooleanVar(root)

    def open(self, text, searchphrase, io=None):
        SearchDialogBase.open(self, text, searchphrase)
        if io:
            path = io.filename or ""
        else:
            path = ""
        dir, base = os.path.split(path)
        head, tail = os.path.splitext(base)
        if not tail:
            tail = ".py"
        self.globvar.set(os.path.join(dir, "*" + tail))

    def create_entries(self):
        SearchDialogBase.create_entries(self)
        self.globent = self.make_entry("In files:", self.globvar)[0]

    def create_other_buttons(self):
        f = self.make_frame()[0]

        btn = ui.Checkbutton(f, variable=self.recvar,
                             text="Recurse down subdirectories")
        btn.pack(side="top", fill="both")
        self.recvar.set(True)
        if not ui.using_ttk:
            btn.select()

    def create_command_buttons(self):
        SearchDialogBase.create_command_buttons(self)
        self.make_button("Search Files", self.default_command, 1)

    def default_command(self, event=None):
        prog = self.engine.getprog()
        if not prog:
            return
        path = self.globvar.get()
        if not path:
            self.top.bell()
            return
        from idlelib.OutputWindow import OutputWindow  # leave here!
        save = sys.stdout
        try:
            sys.stdout = OutputWindow(self.flist)
            self.grep_it(prog, path)
        finally:
            sys.stdout = save

    def grep_it(self, prog, path):
        dir, base = os.path.split(path)
        list = self.findfiles(dir, base, self.recvar.get())
        list.sort()
        self.close()
        pat = self.engine.getpat()
        print("Searching %r in %s ..." % (pat, path))
        hits = 0
        try:
            for fn in list:
                try:
                    with open(fn, errors='replace') as f:
                        for lineno, line in enumerate(f, 1):
                            if line[-1:] == '\n':
                                line = line[:-1]
                            if prog.search(line):
                                sys.stdout.write("%s: %s: %s\n" %
                                                 (fn, lineno, line))
                                hits += 1
                except OSError as msg:
                    print(msg)
            print(("Hits found: %s\n"
                  "(Hint: right-click to open locations.)"
                  % hits) if hits else "No hits.")
        except AttributeError:
            # Tk window has been closed, OutputWindow.text = None,
            # so in OW.write, OW.text.insert fails.
            pass

    def findfiles(self, dir, base, rec):
        try:
            names = os.listdir(dir or os.curdir)
        except OSError as msg:
            print(msg)
            return []
        list = []
        subdirs = []
        for name in names:
            fn = os.path.join(dir, name)
            if os.path.isdir(fn):
                subdirs.append(fn)
            else:
                if fnmatch.fnmatch(name, base):
                    list.append(fn)
        if rec:
            for subdir in subdirs:
                list.extend(self.findfiles(subdir, base, rec))
        return list

    def close(self, event=None):
        if self.top:
            self.top.grab_release()
            self.top.withdraw()
예제 #37
0
class MainFrame(Frame):
    def set_saved_title(self, fpath):
        fname = split(fpath)[-1].replace('.json', '')
        self.master.title('{}  -  {}'.format(fname, _title))

    def set_unsaved_title(self, *args):
        if len(roller_groups) < 1:
            return
        if self.autosave.get():
            self.save_config(self.fpath)
            return
        title = self.master.title()
        if title == _title:
            title = '{}  -  {}'.format('Unsaved', title)
        if '*' not in title:
            title = '*' + title

        self.master.title(title)

    def __init__(self, master):
        Frame.__init__(self, master)

        self.master = master

        self.use_random_org = BooleanVar()
        self.allow_odd = IntVar()
        self.always_on_top = BooleanVar()
        self.autosave = BooleanVar()

        self.use_random_org.trace('w', self.set_unsaved_title)
        self.allow_odd.trace('w', self.set_unsaved_title)
        self.always_on_top.trace('w', self.set_unsaved_title)

        self.set_defaults()

        self.menubar = Menu(master)

        self.filemenu = Menu(self.menubar,
                             tearoff=0,
                             postcommand=maintain_group_indices)
        self.filemenu.add_command(label='New',
                                  underline=0,
                                  command=self.reset_default_group,
                                  accelerator='Ctrl+N')
        self.filemenu.add_command(label='Load',
                                  underline=3,
                                  command=self.load_config,
                                  accelerator='Ctrl+D')
        self.filemenu.add_command(
            label='Save',
            underline=1,
            command=lambda: self.save_config(fpath=self.fpath),
            accelerator='Ctrl+S')
        self.filemenu.add_command(label='Save as...',
                                  underline=4,
                                  command=self.save_config,
                                  accelerator='Ctrl+Shift+S')

        self.editmenu = Menu(self.menubar, tearoff=0)
        self.editmenu.add_checkbutton(label='Use random.org',
                                      underline=0,
                                      variable=self.use_random_org)
        self.editmenu.add_checkbutton(label='Allow odd dice',
                                      underline=6,
                                      variable=self.allow_odd,
                                      command=self.toggle_odd,
                                      onvalue=1,
                                      offvalue=2)
        self.editmenu.add_separator()  #      ------------------
        self.editmenu.add_checkbutton(label='Always on top',
                                      underline=10,
                                      variable=self.always_on_top,
                                      command=self.pin)
        self.editmenu.add_checkbutton(label='Autosave',
                                      underline=4,
                                      variable=self.autosave,
                                      command=self.toggle_autosave)
        self.editmenu.add_separator()  #      ------------------
        self.editmenu.add_command(label='Repeat last action',
                                  underline=0,
                                  accelerator='Ctrl+R')

        self.menubar.add_cascade(label='File', underline=0, menu=self.filemenu)
        self.menubar.add_cascade(label='Edit', underline=0, menu=self.editmenu)

        self.menubar.config(relief='flat')

        master.config(menu=self.menubar)

        self.reset_default_group()

        self.bind_all('<Control-n>', lambda e: self.reset_default_group())
        self.bind_all('<Control-d>', lambda e: self.load_config())
        self.bind_all('<Control-s>',
                      lambda e: self.save_config(fpath=self.fpath))
        self.bind_all('<Control-Shift-S>', lambda e: self.save_config())

    def ask_proceed(self):
        if '*' in self.master.title():
            if not askyesno(
                    'Unsaved changes!',
                    'There are unsaved changes!\r\nWould you like to proceed anyway?'
            ):
                return False
        return True

    def pin(self):
        self.master.wm_attributes('-topmost', self.always_on_top.get())

    def toggle_odd(self):
        for group in roller_groups:
            for roller in group.rollers:
                roller.die_faces_spin.interval = self.allow_odd.get()
                num = roller.die_faces.get()
                if num % 2 != 0:
                    roller.die_faces.set(num - 1)

    def toggle_autosave(self):
        if self.autosave.get():
            self.save_config(self.fpath)
        else:
            self.set_unsaved_title()

    def set_defaults(self):
        self.master.title(_title)
        self.fpath = ''
        self.use_random_org.set(False)
        self.allow_odd.set(2)
        self.always_on_top.set(False)
        self.autosave.set(False)

    def reset_default_group(self):
        if self.ask_proceed():
            self.autosave.set(False)
            self.clear_groups()
            self.set_defaults()
            self.create_group(0, 1)

    @staticmethod
    def clear_groups():
        temp_groups = list(roller_groups)
        for group in temp_groups:
            group.remove_group(override=True)

    def create_group(self, index, rollers):
        default_group = RollerGroup(self, index)
        for i in range(rollers):
            default_group.rollers.append(Roller(default_group, i))
        roller_groups.append(default_group)

    def load_config(self):
        autosave = False
        self.autosave.set(autosave)
        if not self.ask_proceed():
            return

        fpath = askopenfilename(filetypes=[('JSON', '*.json'), ('All', '*.*')],
                                defaultextension='.json')
        if not fpath or not isfile(fpath):
            return
        self.fpath = fpath

        self.clear_groups()

        with open(fpath, 'r') as f:
            group_dict = load(f)

        try:
            settings_dict = group_dict.pop('settings')
            autosave = (settings_dict['autosave'])
            self.use_random_org.set(settings_dict['use_random_org'])
            self.allow_odd.set(settings_dict['allow_odd'])
            self.always_on_top.set(settings_dict['always_on_top'])
        except KeyError:
            pass

        g = 0
        for group_name, group_settings in group_dict.items():
            self.create_group(g, len(group_settings['rollers']))

            group = roller_groups[g]
            group.name.set(group_name)
            group.index = group_settings['index']

            r = 0
            h = 0
            for roller_name, roller_settings in group_settings[
                    'rollers'].items():
                roller = group.rollers[r]
                roller.name.set(roller_name)
                for attr, value in roller_settings.items():
                    try:
                        getattr(roller, attr).set(value)
                    except AttributeError:
                        setattr(roller, attr, value)
                roller.reset(loading=True)
                h = len(roller.history) - 1
                r += 1

            group.navigate_history(desired_index=h)
            g += 1

        roller_groups.sort(key=lambda x: x.index)

        maintain_group_indices()
        for group in roller_groups:
            group.rollers.sort(key=lambda x: x.index)
            group.maintain_roller_indices()
            for roller in group.rollers:
                roller.apply_modifiers()

        maintain_tabstops()

        self.pin()
        self.autosave.set(autosave)
        self.set_saved_title(fpath)

    def save_config(self, fpath=''):
        if not fpath:
            fpath = asksaveasfilename(filetypes=[('JSON', '*.json'),
                                                 ('All', '*.*')],
                                      defaultextension='.json')
        if not fpath:
            if '*' in self.master.title():
                self.autosave.set(False)
            return
        self.fpath = fpath

        d1 = {}
        d1['settings'] = {
            'use_random_org': self.use_random_org.get(),
            'allow_odd': self.allow_odd.get(),
            'always_on_top': self.always_on_top.get(),
            'autosave': self.autosave.get()
        }
        for group in roller_groups:
            group.maintain_roller_indices()
            d2 = {}
            d2['index'] = group.index
            d2['rollers'] = {}
            for roller in group.rollers:
                name = roller.name.get()
                while name in d2['rollers']:
                    name += '!'
                d2['rollers'][name] = {
                    'index': roller.index,
                    'history': roller.history,
                    'dice_qty': roller.dice_qty.get(),
                    'die_faces': roller.die_faces.get(),
                    'modifier': roller.modifier.get(),
                    'finalmod': roller.finalmod.get()
                }
            name = group.name.get()
            if name in d1:
                name += '!'
            d1[name] = d2

        with open(fpath, 'w') as f:
            f.write(dumps(d1, indent=2, separators=(',', ': ')))

        self.set_saved_title(fpath)
예제 #38
0
class OmxGui(Frame):
   
   def __init__(self, parent, argv):
      
      Frame.__init__(self, parent, padding=(3,6,3,12), style="TFrame")
      
      self.parent = parent
      
      self.initData()
      
      self.initUI()
      
      if len(argv) > 1:
         try:
            self.updateAndPlayVideo(argv[1])
         except FileNotFoundError:
            self.logDebug('File Not Found')
      
   def initData(self):
      self.browseInitialDir = def_initialDir
      
      self.recentFile = def_recentFile
      
      self.menuOutputAudio = StringVar()
      self.menuOutputAudio.set(def_menuOutputAudio)
      
      self.menuVideoRefresh = BooleanVar()
      self.menuVideoRefresh.set(def_menuVideoRefresh)
      
      self.menuBgBlack = BooleanVar()
      self.menuBgBlack.set(def_menuBgBlack)
      
      self.maxRecentVideos = def_maxRecentVideos
      
      self.moreOptions = def_moreOptions
      
      self.playProcess = None

   def initUI(self):
      
      self.parent.title('OMX GUI')
      
      self.parent.bind("<Key>", self.keyEvt)
      
      # ---- STYLE ----
      
      Style().theme_use('default')

      Style().configure("TFrame", background="white")
      Style().configure("TButton", font="12", padding=(5,1,5,1), background="#4285F4", foreground="white")
      Style().configure("TEntry", font="12", padding=(5,3,5,2))
      Style().configure("TLabel", background="white")
      Style().map('TButton',
                 foreground=[('pressed', 'white'), ('active', 'white')],
                 background=[('pressed', '!disabled', '#3367d6'), ('active', '#3b78e7')],
                 highlightcolor=[('focus','#4285F4')],
                 relief=[('pressed', '!disabled', 'flat')])
      Style().configure('Treeview', foreground='#333', background="white", highlightthickness='0')
      Style().map('Treeview',
                 foreground=[('focus', '#000')],
                 background=[('focus', '#F5F5F5')])

      # ---- MENU ----
      self.menubar = menubar = MenuBar(self, self.parent)
      
      # ---- TREE ----
      self.filesTree = filesTree = FilesTree(self)
      self.filesTree.loadRecentFile()
      
      # ---- BUTTONS ----
      bBrowse = Button(self, text=_("browse"), width="6", command=self.openVideo)
      bPlay = Button(self, text=_("play"), width="6", command=self.playVideo)
      
      # ---- GRID ----
      self.grid(column=0, row=0, sticky=(N, E, W, S))
      filesTree.grid(column=0, row=0, columnspan=2, rowspan=2, sticky=(N,W,E))
      bBrowse.grid(column=0, row=2, sticky=(N,W))
      bPlay.grid(column=0, row=2, sticky=(N,W), padx=70)
      
      self.parent.columnconfigure(0, weight=1)
      self.parent.rowconfigure(0, weight=1)
      self.columnconfigure(0, weight=1)
      self.columnconfigure(1, weight=1)
      self.rowconfigure(0, weight=1)
      self.rowconfigure(1, weight=1)
      
      self.centerWindow()
      
   def centerWindow(self):
      self.parent.update_idletasks()
      
      w = self.parent.winfo_reqwidth() + 20
      h = self.parent.winfo_reqheight() + 20
      sw = self.parent.winfo_screenwidth()
      sh = self.parent.winfo_screenheight()

      x = (sw - w)/4
      y = (sh - h)/4
      self.parent.geometry("%dx%d+%d+%d" % (w, h, x, y))
      self.parent.resizable(False,False)
      self.parent.focus_force()
      self.parent.lift()
   
   def quitProgram(self):
      self.parent.quit()

   def clearRecentVideos(self):
      self.filesTree.clearRecentVideos()

   def updateRecentVideos(self, fullpath):
      return self.filesTree.updateRecentVideos(fullpath)

   def updateAndPlayVideo(self, fullpath):
      if self.updateRecentVideos(fullpath):
         self.playVideo()

   def openVideo(self):
      fullpath = fileDialog.askopenfilename(
         title=_('open.file')
         ,initialdir=self.browseInitialDir)
      self.updateAndPlayVideo(fullpath)
      
   def playVideo(self):
      lastFile = self.filesTree.getLastFile()
      if lastFile is not None and lastFile['fullpath'] is not '':
         outputAudio = '-o ' + self.menuOutputAudio.get() + ' '
         adjustVideo = '-r ' if self.menuVideoRefresh.get() else ''
         bgBlack = '-b ' if self.menuBgBlack.get() else ''
         moreOptions = self.moreOptions
         fPath = lastFile['fullpath'].replace(' ', '\ ')
         cmdStr = 'omxplayer ' + outputAudio + adjustVideo + bgBlack + moreOptions + fPath
         
         self.logDebug(cmdStr)
         self.playProcess = Popen(['bash', '-c', cmdStr], stdin=PIPE, bufsize = 1)
         self.parent.focus_force()
   
   def keyEvt(self, event):
      self.logDebug('char: ' + event.char + ' --- key simbol: ' + event.keysym + ' ---  key code: ' + str(event.keycode))
      if self.playProcess is not None:
         # right
         if event.keysym == 'Right':
            self.playProcess.stdin.write(bytes('^[[C', 'UTF-8'))
         # left
         elif event.keysym == 'Left':
            self.playProcess.stdin.write(bytes('^[[D', 'UTF-8'))
         # up
         elif event.keysym == 'Up':
            self.playProcess.stdin.write(bytes('^[[A', 'UTF-8'))
         # down
         elif event.keysym == 'Down':
            self.playProcess.stdin.write(bytes('^[[B', 'UTF-8'))
         elif event.char == 'x':
            self.playProcess.kill()
            self.playProcess = None
         else:
            self.playProcess.stdin.write(bytes(event.char, 'UTF-8'))
         try:
            self.playProcess.stdin.flush()
         except IOError:
            try:
               self.playProcess.stdin.close()
               self.playProcess = None
            except IOError:
               self.playProcess = None
         self.parent.focus_force()
   
   def logDebug(self, msg):
      if isDebug and msg is not None:
         print(str(msg))
예제 #39
0
class MainWindow:
    def __init__(self, credentials):
        self.window = Tk()
        self.window.withdraw()
        self.credentials = credentials
        self.settings = readSettings()
        self.followedStreams = getAllStreamsUserFollows(self.credentials)
        self.topTwitchStreams = getTopTwitchStreams(self.credentials)
        self.teams = readTeams(self.followedStreams)
        self.tags = readTags(self.credentials.oauth)

        self.windowFrame = Frame(self.window)
        self.searchFrame = SearchFrame(self)

        self.singleSelectMode = BooleanVar()
        self.multipleSelectMode = BooleanVar()
        self.hideThumbnail = BooleanVar()
        self.hideBoxArt = BooleanVar()
        self.enableFilters = BooleanVar()
        self.enableDesktopNotifications = BooleanVar()
        self.autoRefreshLength = IntVar()

        self.scrollableFrame = ScrollableFrame(1010, 680, self)
        self.liveStreams = getLiveFollowedStreams(credentials.oauth, [
            self.followedStreams[i:i + 100]
            for i in range(0, len(self.followedStreams), 100)
        ])

        self.initializeWindow()
        self.gridFrames()
        self.addMenu()
        self.applySettings()
        self.window.update()

        self.scrollableFrame.loadImagesIntoFrames()
        self.window.deiconify()

    def gridFrames(self):
        self.searchFrame.topFrame.grid(row=0,
                                       column=0,
                                       sticky=NSEW,
                                       padx=4,
                                       pady=6)
        self.searchFrame.middleFrame.grid(row=1,
                                          column=0,
                                          sticky=NSEW,
                                          padx=4,
                                          pady=6)
        self.searchFrame.bottomFrame.grid(row=2,
                                          column=0,
                                          sticky=NSEW,
                                          padx=4,
                                          pady=6)
        self.searchFrame.bottomestFrame.grid(row=3,
                                             column=0,
                                             sticky=NSEW,
                                             padx=4,
                                             pady=8)
        self.scrollableFrame.grid(row=0,
                                  column=1,
                                  rowspan=4,
                                  sticky=NSEW,
                                  padx=4)
        self.windowFrame.grid()

    def addMenu(self):
        menu = Menu(self.window)

        fileMenu = Menu(menu, tearoff=0)
        fileMenu.add_command(label=LabelConstants.QUIT,
                             command=lambda: self.closeWindow())
        menu.add_cascade(label=LabelConstants.FILE, menu=fileMenu)

        manageMenu = Menu(menu, tearoff=0)
        manageMenu.add_command(label=LabelConstants.SETTINGS_TEAM_WINDOW,
                               command=lambda: TeamWindow(self, self.teams))
        manageMenu.add_command(
            label=LabelConstants.SETTINGS_FILTER_WINDOW,
            command=lambda: FilterWindow(self, self.scrollableFrame.filters))
        manageMenu.add_command(label=LabelConstants.SETTINGS_TAG_WINDOW,
                               command=lambda: TagWindow(self))
        menu.add_cascade(label=LabelConstants.EDIT, menu=manageMenu)

        settingsMenu = Menu(menu, tearoff=0)
        settingsMenu.add_checkbutton(label=LabelConstants.HIDE_THUMBNAIL,
                                     variable=self.hideThumbnail,
                                     command=lambda: self.toggleThumbnail())
        settingsMenu.add_checkbutton(label=LabelConstants.HIDE_BOXART,
                                     variable=self.hideBoxArt,
                                     command=lambda: self.toggleBoxArt())
        settingsMenu.add_checkbutton(
            label=LabelConstants.ENABLE_FILTERS,
            variable=self.scrollableFrame.enableFilters,
            command=lambda: self.scrollableFrame.toggleFilters())

        autoRefreshMenu = Menu(settingsMenu, tearoff=0)
        autoRefreshMenu.add_radiobutton(
            label=LabelConstants.AUTO_REFRESH_ZERO,
            var=self.autoRefreshLength,
            value=0,
            command=lambda: self.scrollableFrame.setAutoRefreshLength(0))
        autoRefreshMenu.add_radiobutton(
            label=LabelConstants.AUTO_REFRESH_ONE,
            var=self.autoRefreshLength,
            value=1,
            command=lambda: self.scrollableFrame.setAutoRefreshLength(1))
        autoRefreshMenu.add_radiobutton(
            label=LabelConstants.AUTO_REFRESH_FIVE,
            var=self.autoRefreshLength,
            value=5,
            command=lambda: self.scrollableFrame.setAutoRefreshLength(5))
        autoRefreshMenu.add_radiobutton(
            label=LabelConstants.AUTO_REFRESH_TEN,
            var=self.autoRefreshLength,
            value=10,
            command=lambda: self.scrollableFrame.setAutoRefreshLength(10))

        settingsMenu.add_cascade(label=LabelConstants.AUTO_REFRESH,
                                 menu=autoRefreshMenu)
        settingsMenu.add_checkbutton(
            label=LabelConstants.DESKTOP_NOTIFICATIONS,
            variable=self.enableDesktopNotifications,
            command=lambda: self.toggleDesktopNotifications())
        menu.add_cascade(label=LabelConstants.SETTINGS_MENU, menu=settingsMenu)

        issueMenu = Menu(menu, tearoff=0)
        issueMenu.add_command(
            label=LabelConstants.VIA_DISCORD,
            command=lambda: webbrowser.open(URLConstants.DISCORD, new=2))
        issueMenu.add_command(
            label=LabelConstants.VIA_GITHUB,
            command=lambda: webbrowser.open(URLConstants.GITHUB, new=2))

        helpMenu = Menu(menu, tearoff=0)
        helpMenu.add_cascade(label=LabelConstants.REPORT_ISSUE, menu=issueMenu)
        helpMenu.add_command(label=LabelConstants.ABOUT,
                             command=lambda: AboutWindow(self))
        menu.add_cascade(label=LabelConstants.HELP, menu=helpMenu)

        self.window.config(menu=menu)

    def initializeWindow(self):
        self.window.iconbitmap(FileConstants.STREAMOPENER_ICON)
        self.window.geometry('1280x720')
        self.window.title(LabelConstants.STREAMOPENER)
        self.window.resizable(width=False, height=False)

    def closeWindow(self):
        sys.exit(0)

    def toggleThumbnail(self):
        if self.hideThumbnail.get():
            self.scrollableFrame.showThumbnails(False)
        else:
            self.scrollableFrame.showThumbnails(True)
        self.settings[LabelConstants.SETTINGS_JSON][
            MiscConstants.KEY_HIDE_THUMBNAIL] = self.hideThumbnail.get()
        writeSettings(self.settings)

    def toggleBoxArt(self):
        if self.hideBoxArt.get():
            self.scrollableFrame.showBoxArts(False)
        else:
            self.scrollableFrame.showBoxArts(True)
        self.settings[LabelConstants.SETTINGS_JSON][
            MiscConstants.KEY_HIDE_BOXART] = self.hideBoxArt.get()
        writeSettings(self.settings)

    def toggleDesktopNotifications(self):
        self.settings[LabelConstants.SETTINGS_JSON][
            MiscConstants.
            KEY_DESKTOP_NOTIFICATIONS] = self.enableDesktopNotifications.get()
        writeSettings(self.settings)

    def applySettings(self):
        if MiscConstants.KEY_HIDE_THUMBNAIL in self.settings[
                LabelConstants.SETTINGS_JSON]:
            self.hideThumbnail.set(self.settings[LabelConstants.SETTINGS_JSON][
                MiscConstants.KEY_HIDE_THUMBNAIL])
        else:
            self.hideThumbnail.set(False)
        if MiscConstants.KEY_HIDE_BOXART in self.settings[
                LabelConstants.SETTINGS_JSON]:
            self.hideBoxArt.set(self.settings[LabelConstants.SETTINGS_JSON][
                MiscConstants.KEY_HIDE_BOXART])
        else:
            self.hideBoxArt.set(False)
        if MiscConstants.KEY_OPEN_STREAMS_ON in self.settings[
                LabelConstants.SETTINGS_JSON]:
            self.searchFrame.site.set(
                self.settings[LabelConstants.SETTINGS_JSON][
                    MiscConstants.KEY_OPEN_STREAMS_ON])
        else:
            self.searchFrame.site.set(URLConstants.ORDERED_STREAMING_SITES[
                LabelConstants.URL_TWITCH])
        if MiscConstants.KEY_TEAM in self.settings[
                LabelConstants.SETTINGS_JSON] and self.settings[
                    LabelConstants.SETTINGS_JSON][
                        MiscConstants.KEY_TEAM] in self.teams.keys():
            self.searchFrame.currentTeam.set(self.settings[
                LabelConstants.SETTINGS_JSON][MiscConstants.KEY_TEAM])
        if MiscConstants.KEY_AUTOREFRESH in self.settings[
                LabelConstants.SETTINGS_JSON]:
            self.autoRefreshLength.set(self.settings[
                LabelConstants.SETTINGS_JSON][MiscConstants.KEY_AUTOREFRESH])
        if MiscConstants.KEY_DESKTOP_NOTIFICATIONS in self.settings[
                LabelConstants.SETTINGS_JSON]:
            self.enableDesktopNotifications.set(
                self.settings[LabelConstants.SETTINGS_JSON][
                    MiscConstants.KEY_DESKTOP_NOTIFICATIONS])

    def setTags(self, tags):
        self.tags = deepcopy(tags)
        self.searchFrame.populateTwitchTagsListbox()
        writeTags(self.tags)

    def setTeams(self, teams):
        self.teams = teams
        writeTeams(self.teams)
        self.searchFrame.updateComboboxTeam()
예제 #40
0
class FrameFlatfileDataset(FrameCustomFileDataset):
    """
        Holds an instance of, and visually represents, a flatfile dataset.
        See qal.dataset.flatfile.FlatfileDataset
    """

    def __init__(self, _master, _dataset = None, _relief = None, _is_destination=None):
        super(FrameFlatfileDataset, self ).__init__(_master, _dataset, _relief, _is_destination=_is_destination)

        if _dataset is None:
            self.dataset = FlatfileDataset()

    def on_select(self):
        """Brings up a selector dialog, prompting the user to select a file,
        the relative path if the file is then saved to the filename property.
        Also, the base path is set.
        """
        self.select_file(_default_extension = ".csv", _file_types=[('.csv files', '.csv'), ('all files', '.*')])

    def init_widgets(self):
        # file selector
        self.btn_file_select=Button(self, text="Select file",command=self.on_select)
        self.btn_file_select.grid(column=0, row=0, columnspan=2)
        # filename
        self.filename, self.e_filename, self.l_filename = make_entry(self,"File name: ", 1)

        # delimiter
        self.delimiter, self.e_delimiter, self.l_delimiter = make_entry(self,"Delimiter: ", 2)

        # has_header
        self.l_has_header = ttk.Label(self, text="Has header: ")
        self.l_has_header.grid(column=0, row=3, sticky=W)
        self.has_header = BooleanVar()
        self.e_has_header = ttk.Checkbutton(self, variable=self.has_header)
        self.e_has_header.grid(column=1, row=3, sticky=W)

        # csv_dialect
        self.csv_dialect, self.e_csv_dialect, self.l_csv_dialect = make_entry(self,"CSV dialect: ", 4)

        # quoting
        self.quoting, self.e_quoting, self.l_quoting = make_entry(self, "Quoting: ", 5)

        # escapechar
        self.escapechar, self.e_escapechar, self.l_escapechar = make_entry(self, "Escape character: ", 6)

        # lineterminator
        self.lineterminator, self.e_lineterminator, self.l_lineterminator = make_entry(self, "Line terminator: ", 7)

        # quotechar
        self.quotechar, self.e_quotechar, self.l_quotechar = make_entry(self, "Quote character: ", 8)

        # skipinitialspace
        self.skipinitialspace, self.e_skipinitialspace, self.l_skipinitialspace = make_entry(self, "Skip initial space: ", 9)

    def read_from_dataset(self):
        super(FrameFlatfileDataset, self ).read_from_dataset()

        self.filename.set(empty_when_none(self.dataset.filename))
        self.delimiter.set(empty_when_none(self.dataset.delimiter))
        self.has_header.set(bool_to_binary_int(self.dataset.has_header))
        self.csv_dialect.set(empty_when_none(self.dataset.csv_dialect))
        self.quoting.set(empty_when_none(self.dataset.quoting))
        self.escapechar.set(empty_when_none(self.dataset.escapechar))
        self.lineterminator.set(empty_when_none(self.dataset.lineterminator))
        self.quotechar.set(empty_when_none(self.dataset.quotechar))
        self.skipinitialspace.set(empty_when_none(self.dataset.skipinitialspace))

    def write_to_dataset(self):
        super(FrameFlatfileDataset, self ).write_to_dataset()

        if self.dataset is None:
            self.dataset = FlatfileDataset()

        self.dataset.filename = self.filename.get()
        self.dataset.delimiter = self.delimiter.get()
        self.dataset.has_header = self.has_header.get()
        self.dataset.csv_dialect = self.csv_dialect.get()
        self.dataset.quoting = self.quoting.get()
        self.dataset.escapechar = self.escapechar.get()
        self.dataset.lineterminator = self.lineterminator.get()
        self.dataset.quotechar = self.quotechar.get()
        self.dataset.skipinitialspace = self.skipinitialspace.get()


    def reload(self):
        self.notify_task("Load file "+ self.dataset.filename, 10)
        self.dataset.load()
        self.notify_task("Loaded filed "+ self.dataset.filename + ".", 100)

    def get_possible_references(self, _force = None):

        if not self.dataset.field_names or _force == True:
            self.reload()

        self.references = self.dataset.field_names
        return self.dataset.field_names

    def check_reload(self):
        _filename = self.filename.get()
        if not os.path.isabs(_filename) and self.base_path is None:
            return "First save the merge. You use a relative path to the flatfile dataset."
        else:
            return False
예제 #41
0
class UI:
    def __init__(self) -> None:
        self.ventana = tk.Tk()
        self.ventana.title("You Make A Moon 1.2.1")
        self.ventana.iconbitmap('settings/images/moon.ico')
        self.ventana.resizable(False, False)
        self.ventana.overrideredirect(True)  #! ESTO

        self.ventana.tk.eval("""
        set base_theme_dir settings/theme/awthemes-10.3.0/

        package ifneeded awthemes 10.3.0 \
            [list source [file join $base_theme_dir awthemes.tcl]]
        package ifneeded colorutils 4.8 \
            [list source [file join $base_theme_dir colorutils.tcl]]
        package ifneeded awdark 7.11 \
            [list source [file join $base_theme_dir awdark.tcl]]
        package ifneeded awlight 7.6 \
            [list source [file join $base_theme_dir awlight.tcl]]
        """)

        self.ventana.tk.call("package", "require", 'awdark')
        self.ventana.tk.call("package", "require", 'awlight')

        self.style = ttk.Style()
        self.style.theme_use(settings.get_theme())
        self.tamanio = 30
        self.style.configure('TButton', font=('arial', 20, 'bold'))
        self.style.configure('TLabel', font=('arial', 15))
        self.style.configure('TEntry', font=('arial', 15))

        title_bar = ttk.Frame(self.ventana, relief='raised')
        close_button = ttk.Button(title_bar,
                                  text='X',
                                  command=self.ventana.destroy)
        title_text = ttk.Label(title_bar,
                               text="You Make A Moon  1.2",
                               font=(20))
        title_bar.pack(expand=1, fill=tk.X, side=tk.TOP)
        title_text.pack(side=tk.LEFT, padx=10)
        close_button.pack(side=tk.RIGHT)
        title_bar.bind('<B1-Motion>', self.move_window)

        self.notebook = ttk.Notebook(self.ventana)
        self.notebook.pack()

        self.menuframe = ttk.LabelFrame(self.notebook, border=0)
        self.menuframe.pack()
        self.infoframe = ttk.LabelFrame(self.notebook, border=0)
        self.infoframe.pack()
        self.settingsframe = ttk.LabelFrame(self.notebook, border=0)
        self.settingsframe.pack()

        self.notebook.add(self.menuframe, text="You Make A Moon")
        self.notebook.add(self.settingsframe, text="Configuración")
        self.notebook.add(self.infoframe, text="Info")

    def move_window(self, event):
        self.ventana.geometry('+{0}+{1}'.format(event.x_root - 550,
                                                event.y_root))

    def principal(self):
        self.texto = tk.StringVar()
        self.plantilla = tk.IntVar()

        lf_mesadetrabajo = ttk.LabelFrame(self.menuframe, border=0)
        lf_mesadetrabajo.pack(side=tk.LEFT, padx=20)

        self.canvas2 = tk.Canvas(lf_mesadetrabajo,
                                 width="716",
                                 height="402",
                                 relief=tk.RIDGE,
                                 bd=0)
        self.canvas2.grid(row=0, column=0, columnspan=2)

        l_name = ttk.Label(lf_mesadetrabajo,
                           text="Ingrese el texto de su Luna: ")
        l_name.grid(row=1, column=0, padx=20, pady=10)

        e_text = ttk.Entry(lf_mesadetrabajo,
                           textvariable=self.texto,
                           font=(20),
                           width=30)
        e_text.grid(row=1, column=1, padx=20)
        e_text.bind('<Key>',
                    lambda i: MakePhoto.minifoto(i, self.canvas2, self.texto))

        b_generar = ttk.Button(lf_mesadetrabajo,
                               text="Guardar Foto",
                               command=lambda: self.foto(self.texto.get()))
        b_generar.grid(row=2, column=0, columnspan=2, pady=10)

        plantilla_l = ttk.Label(lf_mesadetrabajo, text="Plantilla: ")
        plantilla_l.grid(row=2, column=1, padx=55, sticky='E')

        plantilla = ttk.Spinbox(lf_mesadetrabajo,
                                from_=1,
                                to=len(os.listdir('settings/images/temples')),
                                width=5,
                                textvariable=self.plantilla,
                                command=self.temple)
        self.plantilla.set(settings.get_temple())
        plantilla.grid(row=2, column=1, sticky='E')

        MakePhoto.default(self.canvas2)

    def temple(self):
        settings.update_json(self.var_theme.get(), settings.get_moons(),
                             self.var_history.get(), self.plantilla.get(),
                             settings.get_photo())
        MakePhoto.minifoto_historial(self.canvas2, self.texto.get())

    def foto(self, texto):
        MakePhoto.cearfoto(texto)
        settings.update_json(self.var_theme.get(),
                             settings.get_moons() + 1, self.var_history.get(),
                             settings.get_temple(), settings.get_photo())
        self.lb_moon["text"] = f"Lunas creadas: {settings.get_moons()}"

        if (self.var_history.get()):
            self.colocar_historial()

    def historial(self):
        def borrar():
            texto = self.lista.get(self.lista.curselection()[0])
            base = DataBase.DataBase()
            base.delet_moon(texto)
            base.desconectar()
            self.colocar_historial()

        def seleccionado():
            try:
                self.texto.set(self.lista.get(self.lista.curselection()[0]))
                MakePhoto.minifoto_historial(self.canvas2, self.texto.get())
            except IndexError:
                pass

        lf_historial = ttk.LabelFrame(self.menuframe, border=0)
        lf_historial.pack(expand='yes', fill='both')

        scrollbar = ttk.Scrollbar(lf_historial)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        if settings.get_theme() == 'awdark':
            self.lista = tk.Listbox(lf_historial,
                                    font=self.tamanio,
                                    yscrollcommand=scrollbar.set,
                                    width=25,
                                    bg='#232829',
                                    fg="#FFFFFF")
        else:
            self.lista = tk.Listbox(lf_historial,
                                    font=self.tamanio,
                                    yscrollcommand=scrollbar.set,
                                    width=25)
        self.lista.pack(fill='both', expand='yes', side=tk.LEFT)
        self.lista.bind("<<ListboxSelect>>", lambda x: seleccionado())
        self.lista.bind("<BackSpace>", lambda x: borrar())

        scrollbar.config(command=self.lista.yview)

        self.colocar_historial()

    def colocar_historial(self):
        base_datos = DataBase.DataBase()
        textos = base_datos.get_moons()

        self.lista.delete(0, tk.END)

        for a in textos:
            self.lista.insert(tk.END, a[1])

        base_datos.desconectar()

    def info(self):
        creditos = ttk.LabelFrame(self.infoframe, border=0)
        creditos.pack()

        l_creditos = ttk.Label(
            creditos,
            text="You Make a Moon es un software libre desarrollado ",
            font=25)
        l_creditos.pack()
        l_creditos1 = ttk.Label(creditos,
                                text="por La Odisea de los Memes",
                                font=25)
        l_creditos1.pack()

        lf_enlaces = ttk.LabelFrame(creditos,
                                    text="Links de Referencia:",
                                    border=0)
        lf_enlaces.pack(pady=20, expand='yes')

        self.i_face = tk.PhotoImage(
            file=("settings/images/logos/facebook.png"))

        b_facebook = ttk.Button(lf_enlaces,
                                image=self.i_face,
                                command=Links.facebook)
        b_facebook.pack(side=tk.LEFT)

        self.i_twit = tk.PhotoImage(file='settings/images/logos/twitter.png')

        b_twitter = ttk.Button(lf_enlaces,
                               image=self.i_twit,
                               command=Links.twitter)
        b_twitter.pack(side=tk.LEFT, padx=30, pady=10)

        self.i_github = tk.PhotoImage(file='settings/images/logos/github.png')

        b_github = ttk.Button(lf_enlaces,
                              image=self.i_github,
                              command=Links.github)
        b_github.pack(side=tk.LEFT)

        self.logo1 = Image.open('settings/images/logos/Make.png')
        if settings.get_theme() == 'awdark':
            self.logo2 = Image.open('settings/images/logos/Logo_white.png')
        else:
            self.logo2 = Image.open('settings/images/logos/Logo_black.png')

        self.logo1 = self.logo1.resize((290, 110), Image.ANTIALIAS)
        self.logo1 = ImageTk.PhotoImage(self.logo1)

        self.logo2 = self.logo2.resize((290, 129), Image.ANTIALIAS)
        self.logo2 = ImageTk.PhotoImage(self.logo2)

        lf_logo = ttk.LabelFrame(creditos, border=0)
        lf_logo.pack()

        l_logo1 = ttk.Label(lf_logo, image=self.logo1)
        l_logo1.pack(side=tk.RIGHT, padx=20)

        l_logo2 = ttk.Label(lf_logo, image=self.logo2)
        l_logo2.pack(side=tk.RIGHT, padx=20)

        l_legal = ttk.Label(
            creditos,
            text="Super Mario Odyssey is a trademark of Nintendo Co., Ltd.",
            font=40)
        l_legal.pack(side=tk.BOTTOM)

    def settings(self):
        def update_theme():
            settings.update_json(self.var_theme.get(), settings.get_moons(),
                                 self.var_history.get(), settings.get_temple(),
                                 settings.get_photo())
            lb_warning.grid(row=0, column=3, padx=30)

        def update_history():
            settings.update_json(self.var_theme.get(), settings.get_moons(),
                                 self.var_history.get(), settings.get_temple(),
                                 self.var_photo.get())

        self.var_theme = StringVar()
        self.var_history = BooleanVar()
        self.var_photo = BooleanVar()

        lb_theme = ttk.Label(self.settingsframe, text="Tema: ", font=(25))
        lb_theme.grid(row=0, column=0, sticky='W')

        awdark = ttk.Radiobutton(self.settingsframe,
                                 text="Oscuro",
                                 variable=self.var_theme,
                                 value="awdark",
                                 command=update_theme)
        awdark.grid(row=0, column=1, padx=30)
        awlight = ttk.Radiobutton(self.settingsframe,
                                  text="Claro",
                                  variable=self.var_theme,
                                  value="awlight",
                                  command=update_theme)
        awlight.grid(row=0, column=2, padx=30)
        self.var_theme.set(settings.get_theme())

        lb_theme = ttk.Label(self.settingsframe,
                             text="Historial de Lunas: ",
                             font=(25))
        lb_theme.grid(row=1, column=0, sticky='W')
        self.var_history.set(bool(settings.get_history()))

        switchistory = ttk.Checkbutton(self.settingsframe,
                                       variable=self.var_history,
                                       command=update_history)
        switchistory.grid(row=1, column=1)

        lb_photo = ttk.Label(self.settingsframe, text="Ver foto: ", font=(25))
        lb_photo.grid(row=2, column=0, sticky='W')
        self.var_photo.set(bool(settings.get_photo()))

        switchphoto = ttk.Checkbutton(self.settingsframe,
                                      variable=self.var_photo,
                                      command=update_history)
        switchphoto.grid(row=2, column=1)

        lb_warning = ttk.Label(
            self.settingsframe,
            text="Es necesario reiniciar el programa para aplicar el tema")

        self.lb_moon = ttk.Label(self.settingsframe,
                                 text=f"Lunas creadas: {settings.get_moons()}",
                                 font=25)
        self.lb_moon.grid(row=6, column=0, columnspan=2, sticky='W', pady=20)

    def mantener(self):
        self.ventana.configure(bg=self.style.lookup('TFrame', 'background'))
        self.ventana.mainloop()
예제 #42
0
class LayoutTester(object):
    """Gränssnitt för testning av layoutfunktioner."""
    def __init__(self, layout_func, debug=False):
        """Skapa GUI och förbereder tkinter.Labels som ska layoutas.

        layout_func -- Funktionen som ska placera kvadraterna, se
                       modulbeskrivning ovan.
        """
        self.layout_func = layout_func
        self.debug = debug

        # storleksalternativ
        self.size_options = [
            size
            for size in range(MIN_SQUARE_SIZE, MAX_SQUARE_SIZE + 1, SIZE_STEP)
        ] + ["random"]

        # lista för kvadraterna
        self.squares = []

        # skapa gränssnittet och kör igång mainloop
        self.ui_xpadding = 4
        self.ui_ypadding = 4
        self.init_ui()
        # slumpa fram fönsterstorlek
        w_size = "{}x{}".format(705 + randint(0, 300), 250 + randint(0, 500))
        self.root.geometry(w_size)

        self.root.mainloop()

    def init_ui(self):
        """Skapa gränssnittet och kör igång mainloop."""
        self.root = Tk()
        self.root.title("Laboration 5")
        # root.resizable(width=False, height=False)

        # Tk-variabler till kvadratsstorlek, antal kvadrater, start_left och
        # start_top.
        self.size_value = StringVar()
        self.size_value.set(self.size_options[0])
        self.number_of_squares = IntVar()
        self.start_left = BooleanVar()
        self.start_left.set(True)
        self.start_top = BooleanVar()
        self.start_top.set(True)

        # Frame att lägga kvadraterna i
        self.square_frame = Frame(
            self.root,
            # height=self.squares_frame_height,
            # width=self.squares_frame_width,
            bg="#eef")
        if self.debug:
            self.square_frame.bind("<Configure>", self.frame_changed)
        self.square_frame.pack(side=TOP,
                               expand=1,
                               fill=BOTH,
                               padx=self.ui_xpadding,
                               pady=self.ui_ypadding)

        # Frame med inställningar
        self.controll_panel = LabelFrame(self.root, text="Inställningar")
        self.init_controll_panel()
        self.controll_panel.pack(fill=BOTH,
                                 padx=self.ui_xpadding,
                                 pady=self.ui_ypadding)

        # Informationstext
        infotext = "Kom ihåg att ändra fönstrets storlek när du testar! " + \
                   "Se även utskrifterna i terminalen."
        self.instructions = Label(self.root, text=infotext)
        self.instructions.pack(anchor=W)

    def init_controll_panel(self):
        """Skapa kontrollpanel för inställningar."""
        self.create_size_panel()
        self.create_num_squares_panel()
        # self.create_start_pos_panel()
        self.create_run_quit_panel()

    def create_size_panel(self):
        """Skapa OptionMenu för storlek på kvadraterna."""
        size_panel = Frame(self.controll_panel)
        Label(size_panel, text="Kvadratsstorlek").pack(side=LEFT)
        OptionMenu(size_panel, self.size_value,
                   *self.size_options).pack(side=LEFT)
        size_panel.pack(side=LEFT,
                        padx=self.ui_xpadding,
                        pady=self.ui_ypadding)

    def create_num_squares_panel(self):
        """Skapa kontroller för att välja antal kvadrater som skapas."""
        num_squares_panel = Frame(self.controll_panel)
        Label(num_squares_panel, text="Antal kvadrater").pack(side=LEFT,
                                                              anchor=S)
        Scale(num_squares_panel,
              variable=self.number_of_squares,
              from_=4,
              to=MAX_NUM_SQUARES,
              orient=HORIZONTAL).pack(side=LEFT, anchor=N)
        num_squares_panel.pack(side=LEFT,
                               anchor=N,
                               padx=self.ui_xpadding,
                               pady=self.ui_ypadding)

    def create_start_pos_panel(self):
        """Skapa kontroller för att välja var layouten börjar."""
        start_panel = Frame(self.controll_panel)
        Checkbutton(start_panel,
                    text="Börja från vänster",
                    justify=LEFT,
                    variable=self.start_left,
                    onvalue=True,
                    offvalue=False).pack(fill=X, anchor=N)
        Checkbutton(start_panel,
                    text="Börja uppifrån",
                    variable=self.start_top,
                    justify=LEFT,
                    onvalue=True,
                    offvalue=False).pack(fill=X, anchor=N)
        start_panel.pack(side=LEFT,
                         anchor=N,
                         padx=self.ui_xpadding,
                         pady=self.ui_ypadding)

    def create_run_quit_panel(self):
        """Skapa knappar för att köra layout och avsluta programmet."""
        button_panel = Frame(self.controll_panel)
        Button(button_panel,
               text="Kör layoutfunktion",
               command=self.run_layout).pack(fill=X)
        Button(button_panel, text="Avsluta",
               command=self.root.quit).pack(fill=X)
        button_panel.pack(side=RIGHT,
                          anchor=N,
                          padx=self.ui_xpadding,
                          pady=self.ui_ypadding)

    def create_squares(self):
        """Skapa tkinter.Label objekt som sparas i LayoutTester-instansen.

        Antalet kvadrater som ska skapas, samt kvadraternas storlek hämtas från
        gränssnittet.
        """
        number_of_squares = self.number_of_squares.get()
        size = self.size_value.get()
        square_counter = 0
        hue_step = 1 / number_of_squares
        hue_value = 0

        # Skapa kvadrater och lägg dem i listan self.squares
        while square_counter < number_of_squares:
            # konververa hsv-färg till rgb-trippel (heltal 0-255)
            rgb = [int(val * 255) for val in hsv_to_rgb(hue_value, 0.75, 0.70)]
            # konvertera rgb-trippel till sträng
            bg_color = "#{:x}{:x}{:x}".format(rgb[0], rgb[1], rgb[2])

            # textfärg
            fg_color = "#fff"

            # sätt storleken på kvadraten
            if size != "random":
                square_size = int(size)
            else:
                square_size = choice(self.size_options[:-1])
            # sätt storleken på texten baserat på kvadratstorleken
            font_size = int(square_size * 0.6)

            # skapa kvadraten
            square = Label(self.square_frame,
                           fg=fg_color,
                           bg=bg_color,
                           font=Font(family="Verdana",
                                     weight=NORMAL,
                                     size=font_size),
                           text=str(square_counter + 1))
            # spara den i listan med kvadrater
            self.squares.append(square)

            # göm kvadraten utanför det synliga området och ställ in
            # dess storlek
            square.place(x=-square_size,
                         y=-square_size,
                         height=square_size,
                         width=square_size)

            # gå vidare till nästa kvadrat och färg
            square_counter += 1
            hue_value += hue_step

        # uppdatera geometri-info för alla widgets (ser till att de vet hur
        # stora de är)
        square.update_idletasks()

    def clear_squares(self):
        """Ta bort existerande kvadrater."""
        for square in self.squares:
            square.destroy()
        del self.squares[:]

    def frame_changed(self, event):
        if event.widget == self.square_frame or event.widget == self.root:
            print("Resize. root: {}x{}, square_frame: {}x{}".format(
                self.root.winfo_width(), self.root.winfo_height(),
                self.square_frame.winfo_width(),
                self.square_frame.winfo_height()))

    def run_layout(self):
        """Skapa nya kvadrater och kör layoutfunktionen."""
        # ta bort gamla kvadrater
        self.clear_squares()

        # skapa nya kvadrater
        self.create_squares()

        # placera ut kvadraterna
        print("Running '{0}(<squares>, {1}, {2})'...".format(
            self.layout_func.__name__, self.square_frame.winfo_height(),
            self.square_frame.winfo_width()))
        self.layout_func(self.squares, self.square_frame.winfo_height(),
                         self.square_frame.winfo_width())
예제 #43
0
class App:
    def __init__(self, master):
        self.master = master
        self.fname = StringVar(value='')  # 搜索文件名
        self.ftype = StringVar(value='')  # 搜索文件类型
        self.fpath = StringVar(value=os.environ['HOME'])  # 搜索路径
        self.advance = BooleanVar(value=False)  # 遍历子目录

        self.view()

    def about(self):
        '''关于'''
        txt = '作者:%s\n版本:%s' % (__author__, __version__)
        self.showinfo(title='关于', message=txt)

    def close(self):
        '''关闭应用'''
        self.master.quit()
        exit()

    def showinfo(self, title, message):
        '''显示提示'''
        messagebox.showinfo(parent=self.master, title=title, message=message)

    def showerror(self, title, message):
        '''显示报错'''
        messagebox.showerror(parent=self.master, title=title, message=message)

    def view(self):
        '''加载视图'''

        # 区域:文件名
        row_1 = Frame(self.master)
        row_1.pack(side='top', fill='x', expand=True)
        Label(row_1, text='文件名:', width=13, justify='left').pack(side='left')
        # 文件名输入框
        self.entry_fname = Entry(row_1,
                                 textvariable=self.fname,
                                 borderwidth=1,
                                 highlightcolor='#ddd',
                                 width=60)
        self.entry_fname.pack(side='right', fill='x', expand=True)

        # 区域:文件类型
        row_2 = Frame(self.master)
        row_2.pack(side='top', fill='x', expand=True)
        Label(row_2, text='文件后缀:', width=13, justify='left').pack(side='left')
        # 文件类型输入框
        self.entry_ftype = Entry(row_2,
                                 textvariable=self.ftype,
                                 borderwidth=1,
                                 highlightcolor='#ddd')
        self.entry_ftype.pack(side='left', fill='x', expand=True)

        # 区域:搜索路径
        row_3 = Frame(self.master)
        row_3.pack(side='top', fill='x', expand=True)
        Label(row_3, text='搜索位置:', width=13, justify='left').pack(side='left')
        # 路径输入框
        self.entry_fpath = Entry(row_3,
                                 textvariable=self.fpath,
                                 borderwidth=1,
                                 highlightcolor='#ddd')
        self.entry_fpath.pack(side='left', fill='x', expand=True)

        # 按钮:选择路径按钮
        # bbb = Label(row_3, text='...', justify='left')
        # bbb.bind('<Button-1>', self.select_path)  # 绑定双击事件
        # bbb.pack(side='left')
        button_path = Button(row_3, text='选择', command=self.select_path)
        button_path.pack(side='right')

        # 区域:选项配置
        row_4 = Frame(self.master)
        row_4.pack(side='top', fill='x', expand=True)
        Label(row_4, text='选项', width=13, justify='left').pack(side='left')
        # 是否查找子目录
        Checkbutton(row_4, text='高级功能',
                    variable=self.advance).pack(side='left')

        # 区域:操作按钮
        row_5 = Frame(self.master)
        row_5.pack(side='top', fill='x', expand=True)
        # 按钮
        Label(row_5, text='操作', width=13, justify='left').pack(side='left')
        button = Button(row_5, text='搜索', command=self.do_search)
        button.pack(side='left')
        button = Button(row_5, text='清理结果', command=self.do_clean)
        button.pack(side='left')
        button = Button(row_5, text='重置', command=self.do_reset)
        button.pack(side='left')
        button = Button(row_5, text='关于', command=self.about)
        button.pack(side='left')
        button = Button(row_5, text='关闭', command=self.close)
        button.pack(side='left')

        # 区域:搜索结果
        row_6 = Frame(
            self.master,
            # relief='raised', borderwidth=1,highlightbackground='#ddd'
        )
        row_6.pack(side='bottom', fill='both', expand=True)
        # 滚动条
        # scroll_x = Scrollbar(row_6)
        # scroll_x.pack(side='bottom', fill='x', expand=True)
        scroll_y = Scrollbar(row_6)
        scroll_y.pack(side='right', fill='y')
        # 列表
        self.result = Listbox(
            row_6,
            width=40,
            height=200,
            relief='ridge',
            borderwidth=1,
            highlightcolor='#ddd',
            # foreground='#ddd',
        )
        self.result.pack(side='left', fill='both', expand=True)
        # 列表与滚动绑定
        # self.result['xscrollcommand'] = scroll_x.set
        # scroll_x.config(command=self.result.xview)
        self.result['yscrollcommand'] = scroll_y.set
        scroll_y.config(command=self.result.yview)
        # 双击打开
        self.result.bind('<Double-Button-1>', self.opendir)

    def select_path(self):
        '''选择文件夹'''
        fpath = askdirectory(parent=self.master,
                             message='选择搜索位置',
                             title='选择搜索位置')
        if isdir(fpath):
            self.fpath.set(fpath)

    def do_search(self):
        '''搜索'''
        fname = self.fname.get()
        ftype = self.ftype.get()
        fpath = self.fpath.get()
        advance = self.advance.get()

        if advance:
            self.showinfo(title='错误提示', message='高级功能还没想好。。')
        elif not ftype:
            self.showinfo(title='错误提示', message='文件后缀不能为空')
        elif not fpath:
            self.showinfo(title='错误提示', message='搜索路径不能为空')
        else:
            ftype = '.' + ftype
            self.result.delete(0, 'end')
            fileList = os.walk(fpath)  # 所有文件目录
            resList = []
            for path, _, file in fileList:
                # path:路径,_:文件夹,file:文件
                for filename in file:
                    # re.I不区分大小写
                    rr = re.compile(r'.*?(%s).*(%s)$' % (fname, ftype), re.I)
                    res = rr.search(filename)
                    if res != None:
                        resList.append(filename)
                        self.result.insert('end', join(path, filename))
            if len(resList) == 0:
                self.showerror('错误提示', '没有找到相关的文件')
                return

    def do_reset(self):
        '''重置'''
        self.fname.set('')
        self.ftype.set('')
        self.fpath.set(value=os.environ['HOME'])
        self.advance.set(False)
        self.result.delete(0, 'end')

    def do_clean(self):
        '''清理结果'''
        self.result.delete(0, 'end')

    def opendir(self, event):
        '''打开所在文件夹'''
        index = self.result.curselection()  # 获取文件列表索引
        print('index', index)
        if index == ():
            self.showerror('错误提示', '没有找到相关的文件')
        else:
            p = self.result.get(index)
            d = os.path.dirname(p)
            # for Mac
            os.system('open ' + d)
예제 #44
0
class BaseWidget(Toplevel):
    def __init__(self, master, name, config, save_config):
        """Create base desktop widget."""
        Toplevel.__init__(self, master, class_=APP_NAME)

        self.rowconfigure(2, weight=1)
        self.columnconfigure(0, weight=1)
        self.minsize(50, 50)
        self.protocol('WM_DELETE_WINDOW', self.withdraw)

        self.ewmh = EWMH()

        self.name = name
        self.config = config  # configparser
        self.save_config = save_config  # save config method

        # get splash window type compatibility
        if CONFIG.getboolean('General', 'splash_supported', fallback=True):
            self.attributes('-type', 'splash')
        else:
            self.attributes('-type', 'toolbar')

        # control main menu checkbutton
        self.variable = BooleanVar(self, False)
        # save widget's position
        self._position = StringVar(
            self, self.config.get(name, 'position', fallback='normal'))
        add_trace(self._position, 'write', self._position_trace)

        self.title('feedagregator.widget.{}'.format(name.replace(' ', '_')))
        self.withdraw()

        # window dragging
        self.x = None
        self.y = None

        # --- menu
        self._create_menu()

        # --- elements
        # --- --- title bar
        frame = Frame(self, style='widget.TFrame')
        Button(frame, style='widget.close.TButton',
               command=self.withdraw).pack(side='left')
        self.label = Label(frame,
                           text=name,
                           style='widget.title.TLabel',
                           anchor='center')
        self.label.pack(side='left', fill='x', expand=True)
        frame.grid(row=0, columnspan=2, padx=4, pady=4, sticky='ew')

        sep = Separator(self, style='widget.Horizontal.TSeparator')
        sep.grid(row=1, columnspan=2, sticky='ew')
        # --- --- widget body
        self.canvas = Canvas(self, highlightthickness=0)
        self.canvas.grid(row=2,
                         column=0,
                         sticky='ewsn',
                         padx=(2, 8),
                         pady=(2, 4))
        scroll = AutoScrollbar(self,
                               orient='vertical',
                               style='widget.Vertical.TScrollbar',
                               command=self.canvas.yview)
        scroll.grid(row=2, column=1, sticky='ns', pady=(2, 14))
        self.canvas.configure(yscrollcommand=scroll.set)
        self.display = Frame(self.canvas, style='widget.TFrame')
        self.canvas.create_window(0,
                                  0,
                                  anchor='nw',
                                  window=self.display,
                                  tags=('display', ))

        self.display.columnconfigure(0, weight=1)

        # --- style
        self.style = Style(self)
        self._font_size = 10
        self.update_style()

        # --- resizing and geometry
        corner = Sizegrip(self, style="widget.TSizegrip")
        corner.place(relx=1, rely=1, anchor='se', bordermode='outside')

        geometry = self.config.get(self.name, 'geometry')
        if geometry:
            self.geometry(geometry)
        self.update_idletasks()
        if self.config.getboolean(self.name, 'visible', fallback=True):
            self.deiconify()

        # --- bindings
        self.bind('<3>', lambda e: self.menu.tk_popup(e.x_root, e.y_root))
        for widget in [self.label, self.canvas, sep]:
            widget.bind('<ButtonPress-1>', self._start_move)
            widget.bind('<ButtonRelease-1>', self._stop_move)
            widget.bind('<B1-Motion>', self._move)
        self.label.bind('<Map>', self._change_position)
        self.bind('<Configure>', self._on_configure)
        self.bind('<4>', lambda e: self._scroll(-1))
        self.bind('<5>', lambda e: self._scroll(1))

        self.update_idletasks()
        self.canvas.configure(scrollregion=self.canvas.bbox('all'))

        self.populate_widget()

        if not CONFIG.getboolean('General', 'splash_supported',
                                 fallback=True) and self.config.getboolean(
                                     self.name, 'visible', fallback=True):
            Toplevel.withdraw(self)
            Toplevel.deiconify(self)

    def _create_menu(self):
        self.menu = Menu(self, tearoff=False)
        self.menu_sort = Menu(self.menu, tearoff=False)

        menu_pos = Menu(self.menu, tearoff=False)
        menu_pos.add_radiobutton(label=_('Normal'),
                                 value='normal',
                                 variable=self._position,
                                 command=self._change_position)
        menu_pos.add_radiobutton(label=_('Above'),
                                 value='above',
                                 variable=self._position,
                                 command=self._change_position)
        menu_pos.add_radiobutton(label=_('Below'),
                                 value='below',
                                 variable=self._position,
                                 command=self._change_position)
        self.menu.add_cascade(label=_('Sort'), menu=self.menu_sort)
        self.menu.add_cascade(label=_('Position'), menu=menu_pos)
        self.menu.add_command(label=_('Hide'), command=self.withdraw)
        self.menu.add_command(label=_('Open all'), command=self.open_all)
        self.menu.add_command(label=_('Close all'), command=self.close_all)

    def populate_widget(self):
        pass  # to be overriden by subclass

    def open_all(self):
        pass  # to be overriden by subclass

    def close_all(self):
        pass  # to be overriden by subclass

    def entry_add(self, title, date, summary, url):
        """Display entry and return the toggleframe and htmlframe."""
        def unwrap(event):
            l.update_idletasks()
            try:
                h = l.html.bbox()[-1]
            except TclError:
                pass
            else:
                l.configure(height=h + 2)

        def resize(event):
            if l.winfo_viewable():
                try:
                    h = l.html.bbox()[-1]
                except TclError:
                    pass
                else:
                    l.configure(height=h + 2)

        # convert date to locale time
        formatted_date = format_datetime(datetime.strptime(
            date, '%Y-%m-%d %H:%M').astimezone(tz=None),
                                         'short',
                                         locale=getlocale()[0])

        tf = ToggledFrame(self.display,
                          text="{} - {}".format(title, formatted_date),
                          style='widget.TFrame')
        l = HtmlFrame(tf.interior, height=50, style='widget.interior.TFrame')
        l.set_content(summary)
        l.set_style(self._stylesheet)
        l.set_font_size(self._font_size)
        tf.interior.configure(style='widget.interior.TFrame')
        tf.interior.rowconfigure(0, weight=1)
        tf.interior.columnconfigure(0, weight=1)
        l.grid(padx=4, sticky='eswn')
        Button(tf.interior,
               text='Open',
               style='widget.TButton',
               command=lambda: webopen(url)).grid(pady=4, padx=6, sticky='e')
        tf.grid(sticky='we', row=len(self.entries), pady=2, padx=(8, 4))
        tf.bind("<<ToggledFrameOpen>>", unwrap)
        l.bind("<Configure>", resize)
        return tf, l

    def update_position(self):
        if self._position.get() == 'normal':
            if CONFIG.getboolean('General', 'splash_supported', fallback=True):
                self.attributes('-type', 'splash')
            else:
                self.attributes('-type', 'toolbar')
        if self.variable.get():
            Toplevel.withdraw(self)
            Toplevel.deiconify(self)

    def update_style(self):
        self.attributes('-alpha', CONFIG.getint('Widget', 'alpha') / 100)
        text_font = Font(self, font=CONFIG.get('Widget', 'font')).actual()
        bg = CONFIG.get('Widget', 'background')
        feed_bg = CONFIG.get('Widget', 'feed_background', fallback='gray20')
        feed_fg = CONFIG.get('Widget', 'feed_foreground', fallback='white')

        self._stylesheet = """
body {
  background-color: %(bg)s;
  color: %(fg)s;
  font-family: %(family)s;
  font-weight: %(weight)s;
  font-style: %(slant)s;
}

ul {
padding-left: 5px;
}

ol {
padding-left: 5px;
}

#title {
  font-weight: bold;
  font-size: large;
}

a {
  color: %(link)s;
  font-style: italic;
}

code {font-family: monospace;}

a:hover {
  font-style: italic;
  border-bottom: 1px solid %(link)s;
}
""" % (dict(bg=feed_bg,
            fg=feed_fg,
            link=CONFIG.get('Widget', 'link_color', fallback='#89B9F6'),
            **text_font))

        self.configure(bg=bg)
        self.canvas.configure(background=bg)
        self._font_size = text_font['size']

    def withdraw(self):
        Toplevel.withdraw(self)
        self.variable.set(False)

    def deiconify(self):
        Toplevel.deiconify(self)
        self.variable.set(True)

    def _scroll(self, delta):
        top, bottom = self.canvas.yview()
        top += delta * 0.05
        top = min(max(top, 0), 1)
        self.canvas.yview_moveto(top)

    def _position_trace(self, *args):
        self.config.set(self.name, 'position', self._position.get())
        self.save_config()

    def _change_position(self, event=None):
        '''Make widget sticky and set its position with respects to the other windows.'''
        pos = self._position.get()
        splash_supp = CONFIG.getboolean('General',
                                        'splash_supported',
                                        fallback=True)
        try:
            for w in self.ewmh.getClientList():
                if w.get_wm_name() == self.title():
                    self.ewmh.setWmState(w, 1, '_NET_WM_STATE_STICKY')
                    self.ewmh.setWmState(w, 1, '_NET_WM_STATE_SKIP_TASKBAR')
                    self.ewmh.setWmState(w, 1, '_NET_WM_STATE_SKIP_PAGER')
                    if pos == 'above':
                        self.attributes('-type', 'dock')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_ABOVE')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_BELOW')
                    elif pos == 'below':
                        self.attributes('-type', 'desktop')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_ABOVE')
                        self.ewmh.setWmState(w, 1, '_NET_WM_STATE_BELOW')
                    else:
                        if splash_supp:
                            self.attributes('-type', 'splash')
                        else:
                            self.attributes('-type', 'toolbar')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_BELOW')
                        self.ewmh.setWmState(w, 0, '_NET_WM_STATE_ABOVE')
            self.ewmh.display.flush()
            if event is None and not splash_supp:
                Toplevel.withdraw(self)
                Toplevel.deiconify(self)
        except ewmh.display.error.BadWindow:
            pass

    def _on_configure(self, event):
        if event.widget is self:
            geometry = self.geometry()
            if geometry != '1x1+0+0':
                self.config.set(self.name, 'geometry', geometry)
                self.save_config()
        elif event.widget in [self.canvas, self.display]:
            self.canvas.configure(scrollregion=self.canvas.bbox('all'))
            self.canvas.itemconfigure('display',
                                      width=self.canvas.winfo_width() - 4)

    def _start_move(self, event):
        self.x = event.x
        self.y = event.y
        self.configure(cursor='fleur')
        self.display.configure(cursor='fleur')

    def _stop_move(self, event):
        self.x = None
        self.y = None
        self.configure(cursor='arrow')
        self.display.configure(cursor='arrow')

    def _move(self, event):
        if self.x is not None and self.y is not None:
            deltax = event.x - self.x
            deltay = event.y - self.y
            x = self.winfo_x() + deltax
            y = self.winfo_y() + deltay
            self.geometry("+%s+%s" % (x, y))
예제 #45
0
class Xls2kml(object):
    '''
    Interface builted in Tkinter()
    '''

    def __init__(self):
        '''
        None -> None

        Builds the Tkinter window and all his elements.
        '''
        # variables ----------------------------------------------------
        # log file
        open("erros.log", "w").close()  # to open and clean the logfile
        logging.basicConfig(level=logging.DEBUG, filename='erros.log')
        sys.stderr = LogFile('stderr')  # Redirect stderr
        self.original_working_dir = os.getcwd()  # original working dir
        self.master = Tk()  # Tk() object
        self.master.title('EXCEL to KMZ Transformer - ver. 1.6')  # window name
        icons = os.getcwd() + os.sep + "icons" + os.sep  # path to icons
        foto_folder = os.getcwd() + os.sep + "fotos"  # path to fotos
        icon = icons + "compass.ico"
        self.master.iconbitmap(icon)  # window icon
        self.master.resizable(width=FALSE, height=FALSE)
        self.master.geometry("548x314")
        self.file_name = ""  # the name of the EXEL file
        self.last_dir = "C:/"
        # image to decorate the window
        self.img = ImageTk.PhotoImage(Image.open(icons + "excel-kmz.jpg"))
        # to use in frame, message, labels and buttons -----------------
        self.message = StringVar()
        self.message.set("\nSelecciona um ficheiro EXCEL")
        bg = "gray25"
        bg1 = "dark orange"
        fc = "white smoke"
        font = ("Helvetica", "8", "bold")
        text0 = " ----- "  # " ------------------------------------------ "
        text1 = " Boris & Vladimir Software "
        text = text0 + text1 + text0

        # Menu ---------------------------------------------------------
        self.menu = Menu(self.master)
        self.master.config(menu=self.menu)
        filemenu = Menu(self.menu)
        self.menu.add_cascade(label="Ficheiro", menu=filemenu)
        filemenu.add_command(label="Sair", command=self.__callback_3)
        filemenu.add_command(label='Pasta Fotos', command=lambda: (self.__open_folder(foto_folder)))
        # --------------------- NOVO -----------------------------------
        self.openGE = BooleanVar()  # não esquecer de importar BooleanVar
        self.openGE.set(False)
        optionsmenu = Menu(self.menu)
        self.menu.add_cascade(label="Opções", menu=optionsmenu)
        optionsmenu.add_checkbutton(label="Não abrir o Google Earth",
                                    onvalue=True, offvalue=False,
                                    variable=self.openGE)
        docsmenu = Menu(self.menu)
        docs = ["docs\manual.pdf", "docs\icons.pdf", "docs\colors.pdf",
                "docs\GPS.xlsx", "docs\GPS.kmz", "docs\Celulas.xlsx",
                "docs\Celulas.kmz", "docs\Foto.xlsx", "docs\Foto.kmz",
                "docs\Quadrado.xls", "docs\Quadrado.kmz"]
        self.menu.add_cascade(label="Documentação", menu=docsmenu)
        docsmenu.add_command(label="Manual",
                             command=lambda: (self.__open_file(docs[0])))
        docsmenu.add_command(label="Ícones",
                             command=lambda: (self.__open_file(docs[1])))
        docsmenu.add_command(label="Cores",
                             command=lambda: (self.__open_file(docs[2])))

        exemplemenu = Menu(docsmenu)
        docsmenu.add_cascade(label="Exemplos", menu=exemplemenu)

        gpsmenu = Menu(exemplemenu)
        exemplemenu.add_cascade(label="Trajetos", menu=gpsmenu)
        gpsmenu.add_command(label="Excel",
                            command=lambda: (self.__open_file(docs[3])))
        gpsmenu.add_command(label="Google Earth",
                            command=lambda: (self.__open_file(docs[4])))

        cellmenu = Menu(exemplemenu)
        exemplemenu.add_cascade(label="Células Telefónicas", menu=cellmenu)
        cellmenu.add_command(label="Excel",
                             command=lambda: (self.__open_file(docs[5])))
        cellmenu.add_command(label="Google Earth",
                             command=lambda: (self.__open_file(docs[6])))

        fotomenu = Menu(exemplemenu)
        exemplemenu.add_cascade(label="Fotos", menu=fotomenu)
        fotomenu.add_command(label="Excel",
                             command=lambda: (self.__open_file(docs[7])))
        fotomenu.add_command(label="Google Earth",
                             command=lambda: (self.__open_file(docs[8])))

        squaremenu = Menu(exemplemenu)
        exemplemenu.add_cascade(label="Quadrado", menu=squaremenu)
        squaremenu.add_command(label="Excel",
                             command=lambda: (self.__open_file(docs[9])))
        squaremenu.add_command(label="Google Earth",
                             command=lambda: (self.__open_file(docs[10])))

        helpmenu = Menu(self.menu)
        self.menu.add_cascade(label='Ajuda', menu=helpmenu)
        helpmenu.add_command(label="Sobre", command=self.__about)
        helpmenu.add_command(label="Ver erros",
                             command=lambda: (self.__open_file("erros.log")))

        # Frame to suport butons, labels and separators ----------------
        self.f = Frame(self.master, bg=bg)
        self.f.pack_propagate(0)  # don't shrink
        self.f.pack(side=BOTTOM, padx=0, pady=0)

        # Message and Labels -------------------------------------------
        self.l1 = Message(
            self.f, bg=bg1, bd=5, fg=bg, textvariable=self.message,
            font=("Helvetica", "13", "bold italic"), width=500).grid(
            row=0, columnspan=6, sticky=EW, padx=5, pady=5)
        self.l2 = Label(
            self.f, image=self.img, fg=bg
            ).grid(row=1, columnspan=6, padx=5, pady=2)
        self.l6 = Label(
            self.f, text=text, font=("Helvetica", "11", "bold"), bg=bg, fg=bg1
            ).grid(row=3, column=2, columnspan=3, sticky=EW, pady=5)

        # Buttons ------------------------------------------------------
        self.b0 = Button(
            self.f, text="Abrir EXCEL...", command=self.__callback, width=10,
            bg="forest green", fg=fc, font=font
            ).grid(row=3, column=0, padx=5, sticky=W)
        self.b1 = Button(
            self.f, text="Gravar KMZ", command=self.__callback_2, width=10,
            bg="DodgerBlue4", fg=fc, font=font
            ).grid(row=3, column=1, sticky=W)
        self.b2 = Button(
            self.f, text="Sair", command=self.__callback_3, width=10,
            bg="orange red", fg=fc, font=font
            ).grid(row=3, column=5, sticky=E, padx=5)

        # Separator ----------------------------------------------------
        # self.s = ttk.Separator(self.f, orient=HORIZONTAL).grid(
        #    row=4, columnspan=5, sticky=EW, padx=5, pady=5)

        # Progressbar --------------------------------------------------
        # self.pb = Canvas(self.f, width=260, height=10)
        self.s = ttk.Style()
        # themes: winnative, clam, alt, default, classic, vista, xpnative
        self.s.theme_use('winnative')
        self.s.configure("red.Horizontal.TProgressbar", foreground='green',
                         background='forest green')
        self.pb = ttk.Progressbar(self.f, orient='horizontal',
                                  mode='determinate',
                                  style="red.Horizontal.TProgressbar")
        self.pb.grid(row=2, column=0, columnspan=6, padx=5, pady=5, sticky=EW)

        # Mainloop -----------------------------------------------------
        self.master.mainloop()

    def __callback(self):  # "Abrir EXEL..." button handler ------------
        '''
        None -> None

        Opens a new window (filedialog.askopenfilename) to choose the
        EXCEL file that is necessary to make the KMZ file.
        '''
        title = 'Selecciona um ficheiro Excel'
        message = 'Ficheiro EXCEL carregado em memória.\nTransforma-o em KMZ!'
        self.file_name = filedialog.askopenfilename(title=title,
                                                    initialdir=self.last_dir)
        self.last_dir = self.file_name[:self.file_name.rfind('/')]

        if self.file_name[self.file_name.rfind('.')+1:] != 'xls' and \
                self.file_name[self.file_name.rfind('.')+1:] != 'xlsx':
            message = self.file_name + ' não é um ficheiro Excel válido!'
        self.message.set(message)

    def __callback_2(self):  # "Gravar KMZ" button handler ---------------
        '''
        None -> None

        Calls the function self.__threat()
        '''
        sleep(1)
        message = 'Ficheiro EXCEL carregado em memória.\nTransforma-o em KMZ!'
        if self.message.get() != message:
            self.message.set("\nEscolhe um ficheiro EXCEL primeiro")
            self.master.update_idletasks()
        else:
            self.message.set("\nA processar...")
            self.master.update_idletasks()
            sleep(1)
            self.__threads()

    def __callback_3(self):  # "Sair" button handler ---------------------
        '''
        None -> None

        Kills the window
        '''
        self.master.destroy()

    def __threads(self):
        '''
        None -> MyTread() objects

        Creates two threads to run at the same time the functions:
        self.__create_kmz()
        self.__progressbar()
        '''
        funcs = [self.__create_kmz, self.__progressbar]
        threads = []
        nthreads = list(range(len(funcs)))

        for i in nthreads:
            t = MyThread(funcs[i], (), funcs[i].__name__)
            threads.append(t)

        for i in nthreads:
            threads[i].start()

    def __create_kmz(self):
        '''
        None -> None

        Calls the exel_to_kml() atribute of the MotherControl() class
        And when it returns, calls self.__open_Google_Earth()
        '''
        kmz = MotherControl(self.file_name, self.original_working_dir).exel_to_kml()
        if type(kmz) == str:
            self.message.set(kmz)
            self.pb.stop()
            self.master.update_idletasks
        else:
            sleep(2)
            self.pb.stop()
            self.master.update_idletasks()
            self.__open_Google_Earth()

    def __open_Google_Earth(self):
        '''
        None -> None

        Opens the maded KMZ file in Google Earth
        '''
        sleep(1)
        self.master.update_idletasks()
        if not self.openGE.get():
            self.message.set("KMZ gravado com sucesso.\nA abrir o Google Earth...")
        else:
            self.message.set("\nKMZ gravado com sucesso.\n")
        sleep(2)
        self.master.update_idletasks()
        path = self.file_name[:self.file_name.rindex('/')]
        path_1 = self.file_name[self.file_name.rindex('/')+1:self.file_name.rfind('.')]
        kmzs = [x for x in os.listdir(path) if x[-4:] == '.kmz' and x[:-12] ==
                path_1]
        kmzs.sort()
        try:
            if not self.openGE.get():
                os.startfile(path + os.sep + kmzs[-1])
                sleep(2)
            self.message.set("\nSelecciona um ficheiro EXCEL")
        except:
            self.message.set("Instale o Google Earth\nhttp://www.google.com/earth/")
            self.master.update_idletasks()

    def __progressbar(self, ratio=0):
        '''
        None -> None

        Starts the progressbar in the window
        '''
        self.pb.start(50)

    def __about(self):
        '''
        None -> None

        Associated with the Help Menu.
        Creates a new window with the "About" information
        '''
        appversion = "1.6"
        appname = "EXCEL to KML Transformer"
        copyright = 14 * ' ' + '(c) 2013' + 12 * ' ' + \
            'SDATO - DP - UAF - GNR\n' + 34 * ' '\
            + "All Rights Reserved"
        licence = 18 * ' ' + 'http://opensource.org/licenses/GPL-3.0\n'
        contactname = "Nuno Venâncio"
        contactphone = "(00351) 969 564 906"
        contactemail = "*****@*****.**"

        message = "Version: " + appversion + 5 * "\n"
        message0 = "Copyright: " + copyright + "\n" + "Licença: " + licence
        message1 = contactname + '\n' + contactphone + '\n' + contactemail

        icons = os.getcwd() + os.sep + "icons" + os.sep  # path to icons
        icon = icons + "compass.ico"

        tl = Toplevel(self.master)
        tl.configure(borderwidth=5)
        tl.title("Sobre...")
        tl.iconbitmap(icon)
        tl.resizable(width=FALSE, height=FALSE)
        f1 = Frame(tl, borderwidth=2, relief=SUNKEN, bg="gray25")
        f1.pack(side=TOP, expand=TRUE, fill=BOTH)

        l0 = Label(f1, text=appname, fg="white", bg="gray25",
                   font=('courier', 16, 'bold'))
        l0.grid(row=0, column=0, sticky=W, padx=10, pady=5)
        l1 = Label(f1, text=message, justify=CENTER,
                   fg="white", bg="gray25")
        l1.grid(row=2, column=0, sticky=E, columnspan=3, padx=10, pady=0)
        l2 = Label(f1, text=message0,
                   justify=LEFT, fg="white", bg="gray25")
        l2.grid(row=6, column=0, columnspan=2, sticky=W, padx=10, pady=0)
        l3 = Label(f1, text=message1,
                   justify=CENTER, fg="white", bg="gray25")
        l3.grid(row=7, column=0, columnspan=2, padx=10, pady=0)

        button = Button(tl, text="Ok", command=tl.destroy, width=10)
        button.pack(pady=5)

    def __open_file(self, doc):
        try:
            os.startfile(doc)
        except:
            pass
            # os.system(doc)
            # não gosto disto mas os.startfile(doc)
            # faz com que a janela não se desenhe bem

    def __open_folder(self, folder):
        os.system('start explorer "' + folder + '"')