Esempio n. 1
0
    async def shell(asyncState):

        while True:
            if not asyncState.loop_running and not asyncState.restarting:
                systray = SysTrayIcon("grey_icon.ico",
                                      "null_internet",
                                      asyncState.menu_options,
                                      on_quit=quitApplication)
                systray.start()
                asyncState.loop_running = True

            if asyncState.loop_running and asyncState.restarting:
                test_input = ('test_item', None, newMenu)
                await addMenuOption(asyncState, test_input)
                systray.shutdown()
                systray = SysTrayIcon("grey_icon.ico",
                                      "null_internet",
                                      asyncState.menu_options,
                                      on_quit=quitApplication)
                systray.start()
                asyncState.restarting = False

            if systray:
                await ping(systray, asyncState)

            await asyncio.sleep(1)
class TrayIcon(object):
    icon_fn = "icon.png"

    def __init__(self, title, menu=None, on_quit=None, icon=icon_fn):
        """
        Param *menu: Recebe tupla contendo tuplas com ("texto do botão","ícone do menu",função).
        Param icon: Recebe o nome do ícone a ser carregado.
        """

        self.__sysTrayIcon = SysTrayIcon(icon, title, menu, on_quit=on_quit)

    def run(self):
        self.__sysTrayIcon.start()

    def stop(self):
        self.__sysTrayIcon.shutdown()
Esempio n. 3
0
class Tray:

    def __init__(self, MODE, VALUE, MODE_EXERCISES, EXERCISES):
        self.MODE = MODE
        if self.MODE == 0:
            self.menu_options = (
                ("Mode : Repeat", None, self._openConfig),
                ("Every : " + str(VALUE) + "s", None, self._openConfig),
                ("Sequence's type : " + ((MODE_EXERCISES == 1) and "Randomized" or "Ordered"), None, self._openConfig),
                ("Exercises loaded : " + str(EXERCISES), None, self._openConfig),
                ("Reload", None, self._reload))
        elif self.MODE == 1:
            self.menu_options = (
                ("Mode : Intervals", None, self._openConfig),
                ("Hours : " + str(VALUE[0]), None, self._openConfig),
                ("Number of sessions per interval: " + str(VALUE[1]), None, self._openConfig),
                ("Time between two sessions : " + str(VALUE[2]) + "s", None, self._openConfig),
                ("Sequence's type : " + ((MODE_EXERCISES == 1) and "Randomized" or "Ordered"), None, self._openConfig),
                ("Exercises loaded : " + str(EXERCISES), None, self._openConfig),
                ("Reload", None, self._reload))
        
        self.icon = getAbsPath("./config/icon.ico")
        self.name = "Workout Starter Pack"
        self.tray = SysTrayIcon(self.icon, self.name, self.menu_options , on_quit=self.quitTray)


    def init_icon_tray(self):
        self.tray.start()

    #Open the config file
    def _openConfig(self):
        config = getAbsPath("./config/config.ini")
        os.startfile(config)

    #Reload the whole program
    def _reload(self):
        self.tray.shutdown()
        restartProgram()

    #Quit the program and shutdown the tray
    def quitTray(self, t=0):
        notify("Workout Starter Pack", "Quitting.")
        os.kill(os.getpid(), signal.SIGINT)
Esempio n. 4
0
            print("[%.2d] %s" % (i, mat[2]))
            i += 1

        n = int(input("Inserisci il numero di materie da scaricare: "))
        stringa = "MaterialeSelezionato,"
        for j in range(n):
            x = -1
            while x not in range(1, i):
                    x = input("Materia: ")
                    if x.isnumeric():
                        x = int(x)
                        sess.materieDaScaricare.append(x)
                        stringa+=str(x) + " "
                    else:
                       continue

        dizionarioMateriale = {"MaterialeSelezionato": stringa}

        writeVariables(dizionarioMateriale)
    else:
        lista = []
        for element in var.split():
            if element != "":
                lista.append(int(element))
        sess.materieDaScaricare = lista

    # Mostro il menù.
    sess.menu()
    systray.shutdown()

Esempio n. 5
0
class SnuClipboardManager(NormalApp):
    icon = 'data/icon_small.png'
    tray = None
    tray_thread = None
    window_minimized = BooleanProperty(False)
    shift_pressed = BooleanProperty(False)
    ctrl_pressed = BooleanProperty(False)
    alt_pressed = BooleanProperty(False)
    window_leave_timeout = ObjectProperty(allownone=True)
    on_top = BooleanProperty(False)
    window_min_width = NumericProperty(130)
    window_title = 'Snu Clipboard Manager'
    window_width_target = NumericProperty(200)
    modify_mode = BooleanProperty(False)
    clipboard_updater = ObjectProperty(allownone=True)
    current_clipboard = StringProperty('')
    clipboard_folder = StringProperty('')
    clipboard_folders = ListProperty()
    clipboard_data = ListProperty()
    clipboard_data_display = ListProperty()
    clipboard_history = ListProperty()
    hiddens = ListProperty()
    main_history_length = NumericProperty(1)
    data_directory = StringProperty('')
    show_undo = BooleanProperty(True)
    show_strip = BooleanProperty(False)
    max_history = NumericProperty(20)

    preset_type = StringProperty()
    preset_element = StringProperty()
    preset_second_element = StringProperty()

    edit_type = StringProperty()
    edit_path = StringProperty()
    edit_name = StringProperty()
    edit_name_original = StringProperty()
    edit_section = StringProperty()
    edit_content = StringProperty()

    search_text = StringProperty()
    search_results = ListProperty()
    search_content = BooleanProperty(True)

    def search(self, *_):
        data = []
        if self.search_text:
            search_text = self.search_text.lower()
            for clip in self.clipboard_data:
                if clip['viewtype'] == 'item':
                    if (search_text in clip['text'].lower()) or (
                            self.search_content
                            and search_text in clip['clipboard'].lower()):
                        new_clip = clip.copy()
                        new_clip['hidden'] = False
                        new_clip['show_folder'] = True
                        data.append(new_clip)
        self.search_results = data

    def dismiss_popup(self, *_):
        if self.popup is not None:
            try:
                self.popup.dismiss()
            except:
                pass
            self.popup = None

    def rescale_interface(self, *_, force=False):
        """Called when the window changes resolution, calculates variables dependent on screen size"""

        self.store_window_size()

        if Window.width != self.last_width:
            self.last_width = Window.width
            self.popup_x = min(Window.width, 640)

        if (Window.height != self.last_height) or force:
            self.last_height = Window.height
            self.button_scale = int(
                float(cm(0.85)) *
                (int(self.config.get("Settings", "buttonsize")) / 100))
            self.text_scale = int(
                (self.button_scale / 3) *
                int(self.config.get("Settings", "textsize")) / 100)
            self.display_border = self.button_scale / 3
            self.display_padding = self.button_scale / 4

    def get_application_config(self, **kwargs):
        if platform == 'win':
            self.data_directory = os.getenv(
                'APPDATA') + os.path.sep + "Snu Clipboard Manager"
            if not os.path.isdir(self.data_directory):
                os.makedirs(self.data_directory)
        elif platform == 'linux':
            self.data_directory = os.path.expanduser(
                '~') + os.path.sep + ".snuclipboardmanager"
            if not os.path.isdir(self.data_directory):
                os.makedirs(self.data_directory)
        elif platform == 'macosx':
            self.data_directory = os.path.expanduser(
                '~') + os.path.sep + ".snuclipboardmanager"
            if not os.path.isdir(self.data_directory):
                os.makedirs(self.data_directory)
        elif platform == 'android':
            self.data_directory = self.user_data_dir
        else:
            self.data_directory = os.path.sep
        config_file = os.path.realpath(
            os.path.join(self.data_directory, "snuclipboardmanager.ini"))
        return config_file

    def on_config_change(self, config, section, key, value):
        self.load_config_values()
        self.rescale_interface(force=True)

    def load_config_values(self):
        self.show_undo = self.config.getboolean("Settings", 'showundo')
        self.show_strip = self.config.getboolean("Settings", 'showstrip')
        max_history = int(self.config.get("Settings", 'max_history'))
        if max_history < 1:
            self.max_history = 1
        else:
            self.max_history = max_history
        main_history_length = int(
            self.config.get("Settings", "main_history_length"))
        if main_history_length > self.max_history:
            self.main_history_length = self.max_history
        elif main_history_length < 1:
            self.main_history_length = 1
        else:
            self.main_history_length = main_history_length

    def load_clipboards(self, edit=False):
        self.load_hiddens()
        self.clipboard_data = []
        if edit:
            self.clipboard_data.append({
                'text': 'Add Section',
                'viewtype': 'adder-heading',
                'hidden': False,
                'section': self.clipboard_folder,
                'path': self.clipboard_folder,
                'show_folder': False
            })
        if os.path.isdir(self.clipboard_folder):
            sections = os.listdir(self.clipboard_folder)
            for section in sections:
                if section in self.hiddens and not edit:
                    hidden = True
                else:
                    hidden = False
                section_folder = os.path.join(self.clipboard_folder, section)
                if os.path.isdir(section_folder):
                    self.clipboard_data.append({
                        'text': section,
                        'viewtype': 'heading',
                        'hidden': hidden,
                        'section': section,
                        'path': section_folder,
                        'section_folder': self.clipboard_folder,
                        'show_folder': False
                    })
                    if edit:
                        self.clipboard_data.append({
                            'text': 'Add Item',
                            'viewtype': 'adder-item',
                            'hidden': hidden,
                            'section': section,
                            'path': section_folder,
                            'section_folder': self.clipboard_folder,
                            'show_folder': False
                        })
                    for file in os.listdir(section_folder):
                        fullpath = os.path.join(section_folder, file)
                        if os.path.isfile(fullpath):
                            with open(fullpath, 'r') as datafile:
                                try:
                                    data = datafile.read()
                                except:
                                    continue
                            self.clipboard_data.append({
                                'text':
                                os.path.splitext(file)[0],
                                'viewtype':
                                'item',
                                'clipboard':
                                data,
                                'hidden':
                                hidden,
                                'section':
                                section,
                                'path':
                                fullpath,
                                'section_folder':
                                section_folder,
                                'show_folder':
                                False
                            })
        self.update_display_clipboards()

    def toggle_hide_section(self, section, hide_others=False):
        for data in self.clipboard_data:
            if data['section'] == section:
                if hide_others:
                    data['hidden'] = False
                else:
                    data['hidden'] = not data['hidden']
            elif hide_others:
                data['hidden'] = True
        self.save_hiddens()
        self.root.ids.presets.refresh_from_data()
        self.update_display_clipboards()

    def update_display_clipboards(self, *_):
        data = []
        for clip in self.clipboard_data:
            if not clip['hidden'] or clip['viewtype'] == 'heading':
                data.append(clip)
        self.clipboard_data_display = data

    def clear_history(self):
        self.clipboard_history = self.clipboard_history[:1]

    def remove_history_item(self, index):
        if index > 0:
            self.clipboard_history.pop(index)

    def remove_history_matches(self, clipboard):
        for clip in reversed(self.clipboard_history):
            if clip['text'] == clipboard:
                self.clipboard_history.remove(clip)

    def set_history_item(self, index):
        try:
            history_item = self.clipboard_history.pop(index)
        except:
            return
        self.clipboard_history.insert(0, history_item)
        self.set_clipboard(history_item['text'], skip_history=True)

    def set_clipboard_from_widget(self, widget):
        if widget.focus:
            self.set_clipboard(widget.text, overwrite_history=True)

    def set_clipboard(self, text, skip_history=False, overwrite_history=False):
        #Sets a preset to the clipboard
        if text and text != self.current_clipboard:
            Clipboard.copy(text)
            if overwrite_history:
                if len(self.clipboard_history) == 0:
                    self.clipboard_history.append({'text': text})
                else:
                    self.clipboard_history[0]['text'] = text
                self.current_clipboard = text
                self.refresh_history_areas()
            if skip_history:
                self.current_clipboard = text

    def refresh_history_areas(self):
        self.root.ids.historyFull.refresh_from_data()
        self.root.ids.historyShort.refresh_from_data()

    def update_current_clipboard(self, *_):
        #Sets the current clipboard to a local variable

        clipboard = Clipboard.paste()
        if clipboard and self.current_clipboard != clipboard:
            self.current_clipboard = clipboard
            if self.config.getboolean('Settings', 'no_duplicates'):
                self.remove_history_matches(clipboard)
            self.clipboard_history.insert(0, {'text': clipboard})
            self.clipboard_history = self.clipboard_history[:self.max_history]

    def undo_clipboard(self, *_):
        self.set_history_item(1)

    def strip_clipboard(self, *_):
        Clipboard.copy(self.current_clipboard.strip())

    def settings_mode(self, heading=''):
        self.close_settings()
        if self.modify_mode:
            self.modify_mode = False
            if self.root.ids.editArea.current == 'edit':
                self.load_clipboards()
        else:
            self.modify_mode = True
            if self.root.ids.editArea.current == 'edit':
                self.load_clipboards(edit=True)
        self.size_window()

    def delete_preset(self, preset):
        self.preset_type = preset.viewtype
        self.preset_element = preset.path

        if preset.viewtype == 'heading':
            confirm_text = "This entire section of presets will be deleted permanently"
        else:
            confirm_text = "This single preset will be deleted permanently"
        self.dismiss_popup()
        content = ConfirmPopupContent(text=confirm_text,
                                      yes_text='Delete',
                                      no_text="Don't Delete",
                                      warn_yes=True)
        content.bind(on_answer=self.delete_preset_answer)
        self.popup = NormalPopup(title="Confirm Delete ",
                                 content=content,
                                 size_hint=(1, None),
                                 size=(1000, self.button_scale * 4))
        self.popup.bind(on_dismiss=self.dismiss_popup)
        self.popup.open()

    def delete_preset_answer(self, instance, answer):
        self.dismiss_popup()
        if answer == 'yes':
            if self.preset_type == 'item':
                if os.path.isfile(self.preset_element):
                    os.remove(self.preset_element)
                    self.load_clipboards(edit=True)
            elif self.preset_type == 'heading':
                if os.path.isdir(self.preset_element):
                    shutil.rmtree(self.preset_element)
                    self.load_clipboards(edit=True)

    def edit_preset(self, preset):
        if preset.viewtype == 'item':
            self.edit_type = preset.viewtype
            self.edit_path = preset.path
            self.edit_name = preset.text
            self.edit_name_original = preset.text
            self.edit_section = preset.section_folder
            self.edit_content = preset.clipboard
            self.root.ids.editContentArea.focus = True
        elif preset.viewtype == 'heading':
            self.preset_type = 'heading'
            self.preset_element = preset.section_folder
            self.preset_second_element = preset.text
            content = InputPopupContent(text="Rename folder to:",
                                        input_text=preset.text,
                                        hint='Folder Name')
            content.bind(on_answer=self.rename_folder_answer)
            self.popup = NormalPopup(title="Rename Folder",
                                     content=content,
                                     size_hint=(1, None),
                                     size=(1000, self.button_scale * 5))
            self.popup.bind(on_dismiss=self.dismiss_popup)
            self.popup.open()

    def rename_folder_answer(self, instance, answer):
        new_name = instance.ids["input"].text.strip(' ')
        self.dismiss_popup()
        if not new_name:
            return
        if answer == 'yes':
            old_path = os.path.join(self.preset_element,
                                    self.preset_second_element)
            new_path = os.path.join(self.preset_element, new_name)
            if old_path != new_path:
                try:
                    os.rename(old_path, new_path)
                    if self.edit_section == old_path:
                        self.edit_path = os.path.join(
                            new_path, self.edit_name_original) + '.txt'
                        self.edit_section = new_path
                    self.load_clipboards(edit=True)
                except Exception as e:
                    app.message_popup(text="Unable to rename folder: " +
                                      str(e),
                                      title="Warning")

    def save_edit(self):
        if not self.edit_path or not self.edit_name or not self.edit_section:
            return
        new_file = os.path.join(self.edit_section, self.edit_name) + '.txt'
        if new_file != self.edit_path:
            #rename file
            try:
                os.rename(self.edit_path, new_file)
                self.edit_path = new_file
            except Exception as e:
                app.message_popup(text="Unable to save edit: " + str(e),
                                  title="Warning")
                return
        try:
            file = open(self.edit_path, "w")
            file.write(self.edit_content)
            file.close()
            self.load_clipboards(edit=True)
        except Exception as e:
            app.message_popup(text="Unable to write to file: " + str(e),
                              title="Warning")

    def clear_edit(self, *_):
        self.edit_content = ''
        self.edit_name = ''
        self.edit_name_original = ''
        self.edit_path = ''
        self.edit_section = ''

    def scroll_presets_to(self, section, item):
        scroll_to_index = None
        preset_area = self.root.ids['presets']
        for index, data in enumerate(preset_area.data):
            if not item:
                if data['viewtype'] == 'heading' and data['section'] == section:
                    scroll_to_index = index + 2
                    break
            else:
                if data['section'] == section and data[
                        'viewtype'] == 'item' and data['path'] == item:
                    scroll_to_index = index
                    break
        if scroll_to_index is not None:
            preset_area.scroll_to_index(scroll_to_index)

    def instant_add(self, path, section):
        self.dismiss_popup()
        if not self.modify_mode:
            self.settings_mode()
        self.root.ids.editArea.current = 'edit'
        self.load_clipboards(edit=True)
        self.edit_type = 'item'
        self.edit_path = path
        self.edit_name = ''
        self.edit_name_original = ''
        self.edit_section = section
        self.edit_content = self.current_clipboard
        self.scroll_presets_to(section, '')
        content = InstantAddPresetContent()
        content.bind(on_answer=self.instant_add_preset_answer)
        self.popup = NormalPopup(title='Create File',
                                 content=content,
                                 size_hint=(1, 1),
                                 size=(1000, 2000))
        self.popup.bind(on_dismiss=self.dismiss_popup)
        self.popup.bind(on_dismiss=self.clear_edit)
        self.popup.open()

    def instant_add_preset_answer(self, instance, answer):
        self.dismiss_popup()
        if answer == 'yes':
            filename = os.path.join(self.edit_path, self.edit_name) + '.txt'
            if os.path.exists(filename):
                self.message_popup(text="File already exists!",
                                   title="Warning")
                self.clear_edit()
                return
            file = open(filename, 'w')
            file.write(self.edit_content)
            file.close()
            self.load_clipboards()
        self.clear_edit()

    def add_preset(self, preset_type, preset_location):
        self.preset_type = preset_type
        self.preset_element = preset_location
        if preset_type == 'heading':
            input_text = "Add a folder with the name:"
            hint_text = "Folder Name"
            title_text = "Create Folder"
        else:
            input_text = "Add a preset with the name:"
            hint_text = "Preset Name"
            title_text = "Create File"
        self.dismiss_popup()

        content = InputPopupContent(text=input_text, hint=hint_text)
        content.bind(on_answer=self.add_preset_answer)
        self.popup = NormalPopup(title=title_text,
                                 content=content,
                                 size_hint=(1, None),
                                 size=(1000, self.button_scale * 5))
        self.popup.bind(on_dismiss=self.dismiss_popup)
        self.popup.open()

    def add_preset_answer(self, instance, answer):
        preset_name = instance.ids['input'].text.strip(' ')
        self.dismiss_popup()
        if not preset_name:
            return
        if answer == 'yes':
            preset_type = self.preset_type
            preset_location = self.preset_element
            if preset_type == 'heading':
                path = os.path.join(preset_location, preset_name)
                try:
                    os.makedirs(path)
                except Exception as e:
                    app.message_popup(text="Unable to create folder: " +
                                      str(e),
                                      title="Warning")
                self.load_clipboards(edit=True)
            else:
                filename = os.path.join(preset_location, preset_name) + '.txt'
                if not os.path.isfile(filename):
                    try:
                        file = open(filename, 'w+')
                        file.close()
                        self.edit_type = preset_type
                        self.edit_path = filename
                        self.edit_name = preset_name
                        self.edit_name_original = preset_name
                        self.edit_section = preset_location
                        self.edit_content = ''
                        self.root.ids.editContentArea.focus = True
                    except Exception as e:
                        app.message_popup(text="Unable to create file: " +
                                          str(e),
                                          title="Warning")
                    self.load_clipboards(edit=True)
                else:
                    app.message_popup(text="File already exists!",
                                      title="Warning")

    def load_clipboard_folders(self):
        folders = [self.clipboard_folder]
        folder_items = self.config.items("PresetsPaths")
        for key, folder in folder_items:
            if folder not in folders:
                folders.append(folder)
        folders_data = []
        for folder in folders:
            if folder:
                folders_data.append({'path': folder})
        self.clipboard_folders = folders_data

    def save_clipboard_folders(self):
        self.config.remove_section("PresetsPaths")
        self.config.add_section("PresetsPaths")
        for index, folder_item in enumerate(self.clipboard_folders):
            folder = folder_item['path']
            self.config.set("PresetsPaths", str(index), folder)

    def remove_presets_folder(self, path):
        for index, preset in enumerate(self.clipboard_folders):
            if preset['path'] == path:
                self.clipboard_folders.pop(index)
                self.save_clipboard_folders()

    def set_presets_folder(self, path):
        self.save_hiddens()
        self.clipboard_folder = path
        self.config.set("Settings", "presetsfolder", path)
        self.load_clipboards()

    def add_presets_folder(self, *_):
        self.not_on_top()
        from plyer import filechooser
        try:
            filechooser.choose_dir(on_selection=self.add_presets_folder_finish,
                                   title='Select A Presets Directory')
        except:
            #Filechooser can fail if user selects root
            if self.config.getboolean("Settings", "alwaysontop"):
                self.always_on_top()
            pass

    def add_presets_folder_finish(self, path):
        if self.config.getboolean("Settings", "alwaysontop"):
            self.always_on_top()
        path = path[0]
        if path:
            if path not in self.clipboard_folders:
                self.clipboard_folders.append({'path': path})
                self.save_clipboard_folders()
                self.set_presets_folder(path)
            else:
                self.message("Path Already Added")
        else:
            self.message("No Path Found")

    def browse_presets(self):
        try:
            import webbrowser
            webbrowser.open(self.clipboard_folder)
        except:
            pass

    def size_window(self, *_):
        Window.left = self.window_left
        Window.top = self.window_top
        height = self.window_height
        width = int(self.button_scale * 4 *
                    (float(self.config.get("Settings", "normalwidth")) / 100))
        if width < self.window_min_width:
            width = self.window_min_width
        if self.modify_mode:
            self.window_width_target = width
            width = int(
                self.button_scale * 17 *
                (float(self.config.get("Settings", "expandedwidth")) / 100))
            Window.size = width, height
        else:
            Window.size = width, height
            self.window_width_target = Window.width

    def on_button_scale(self, *_):
        self.size_window()

    def save_hiddens(self):
        if not self.clipboard_folder:
            return
        hiddens = []
        for data in self.clipboard_data:
            if data['hidden'] and data['viewtype'] == 'heading':
                section = data['section']
                if section not in hiddens:
                    hiddens.append(section)

        hiddens_filename = os.path.join(self.clipboard_folder, 'hiddens.txt')
        try:
            hiddens_file = open(hiddens_filename, 'w')
        except:
            return
        for hidden in hiddens:
            hiddens_file.write(hidden + '\n')
        hiddens_file.close()

    def load_hiddens(self):
        hiddens = []
        hiddens_filename = os.path.join(self.clipboard_folder, 'hiddens.txt')
        try:
            hiddens_file = open(hiddens_filename, 'r')
        except:
            self.hiddens = []
            return
        lines = hiddens_file.readlines()
        hiddens_file.close()
        for line in lines:
            line = line.strip('\n')
            if line:
                hiddens.append(line)
        self.hiddens = hiddens

    def build_config(self, config):
        """Setup config file if it is not found"""

        window_height, window_width, window_top, window_left = self.get_window_size(
        )
        config.setdefaults(
            'Settings', {
                'buttonsize': 100,
                'textsize': 100,
                'expandedwidth': 100,
                'normalwidth': 100,
                'alwaysontop': 1,
                'minimizestart': 0,
                'minimizetray': 0,
                'showtray': 1,
                'auto_shrink': 0,
                'auto_expand': 0,
                'no_duplicates': 0,
                'showundo': 1,
                'showstrip': 0,
                'presetsfolder': '',
                'max_history': 20,
                'main_history_length': 1,
                'window_height': window_height,
                'window_top': window_top,
                'window_left': window_left,
                'window_width': window_width
            })
        config.setdefaults('PresetsPaths', {})

    def build_settings(self, settings):
        """Kivy settings dialog panel
        settings types: title, bool, numeric, options, string, path"""

        settingspanel = []
        settingspanel.append({
            "type": "label",
            "title": "        Basic Behavior"
        })
        settingspanel.append({
            "type": "numeric",
            "title": "Max Clipboard History",
            "desc":
            "Number of entries to keep in clipboard history. Defaluts to 20.",
            "section": "Settings",
            "key": "max_history"
        })
        settingspanel.append({
            "type": "bool",
            "title": "Auto-Shrink Window",
            "desc": "Automatically shrink the window when the mouse leaves.",
            "section": "Settings",
            "key": "auto_shrink"
        })
        settingspanel.append({
            "type": "bool",
            "title": "Auto-Expand Window",
            "desc": "Automatically expand the window when the mouse enters.",
            "section": "Settings",
            "key": "auto_expand"
        })
        settingspanel.append({
            "type": "bool",
            "title": "Minimize On Startup",
            "desc": "Automatically minimize the program as soon as it starts.",
            "section": "Settings",
            "key": "minimizestart"
        })
        if platform == 'win':
            settingspanel.append({
                "type": "bool",
                "title": "Always-On-Top",
                "desc":
                "Sets the window to always-on-top mode on startup.  Changing requires a program restart.",
                "section": "Settings",
                "key": "alwaysontop"
            })
            settingspanel.append({
                "type": "bool",
                "title": "Show Tray Icon",
                "desc":
                "A tray icon will be shown with options.  Changing requires program restart.",
                "section": "Settings",
                "key": "showtray"
            })
            settingspanel.append({
                "type": "bool",
                "title": "Minimize To Tray",
                "desc":
                "Minimize to tray when minimizing the window.  Only available when tray icon is enabled.",
                "section": "Settings",
                "key": "minimizetray"
            })
        settingspanel.append({
            "type": "bool",
            "title": "Disallow Duplicates",
            "desc":
            "Prevent duplicates from being added to clipboard history, removes the previous item when a new duplicate is added.",
            "section": "Settings",
            "key": "no_duplicates"
        })

        settingspanel.append({
            "type": "label",
            "title": "        Main Window Appearance"
        })
        settingspanel.append({
            "type": "bool",
            "title": "Show Undo Clipboard Button",
            "desc":
            "Shows a button to undo the clipboard to the previous state.",
            "section": "Settings",
            "key": "showundo"
        })
        settingspanel.append({
            "type": "bool",
            "title": "Show Strip Clipboard Button",
            "desc":
            "Shows a button to remove all formatting and extra spaces from clipboard text.",
            "section": "Settings",
            "key": "showstrip"
        })
        settingspanel.append({
            "type": "numeric",
            "title": "History In Main Window",
            "desc":
            "Number of history elements to show in main window. Defaults to 1.",
            "section": "Settings",
            "key": "main_history_length"
        })

        settingspanel.append({
            "type": "label",
            "title": "        Interface Scaling"
        })
        settingspanel.append({
            "type": "numeric",
            "title": "Shrunk Width Scale",
            "desc":
            "Scale of the window when it is in normal mode. Expects a percentage, defaults to 100",
            "section": "Settings",
            "key": "normalwidth"
        })
        settingspanel.append({
            "type": "numeric",
            "title": "Expanded Width Scale",
            "desc":
            "Scale of the window when it is in expanded mode. Expects a percentage, defaults to 100",
            "section": "Settings",
            "key": "expandedwidth"
        })
        settingspanel.append({
            "type": "numeric",
            "title": "Button Scale",
            "desc": "Button scale, expects a percentage, defaults to 100.",
            "section": "Settings",
            "key": "buttonsize"
        })
        settingspanel.append({
            "type": "numeric",
            "title": "Text Scale",
            "desc": "Font scale, expects a percentage, defaults to 100.",
            "section": "Settings",
            "key": "textsize"
        })
        settings.add_json_panel('Settings',
                                self.config,
                                data=json.dumps(settingspanel))

    def build(self):
        global app
        app = self
        if platform == 'win' and self.config.getboolean(
                "Settings", "showtray"):
            #setup system tray
            from infi.systray import SysTrayIcon
            tray_menu = (
                ("Toggle Minimize", None, self.tray_click),
                ("Undo Clipboard", None, self.undo_clipboard),
                ("Strip Clipboard", None, self.strip_clipboard),
            )
            icon_file = kivy.resources.resource_find('icon.ico')
            self.tray = SysTrayIcon(icon_file,
                                    'Snu Clipboard Manager',
                                    tray_menu,
                                    on_quit=self.tray_quit)
            self.tray.start()
        else:
            self.tray = None

        self.clipboard_folder = self.config.get("Settings", "presetsfolder")
        self.load_clipboard_folders()
        self.load_clipboards()
        Window.bind(on_key_down=self.key_down)
        Window.bind(on_key_up=self.key_up)
        Window.bind(on_cursor_leave=self.window_exited)
        Window.bind(on_cursor_enter=self.window_entered)
        Window.bind(on_minimize=self.on_minimize)
        Window.bind(on_restore=self.on_restore)
        return MainScreen()

    def tray_quit(self, tray):
        Clock.schedule_once(self.stop)

    def tray_click(self, tray):
        if self.window_minimized:
            Clock.schedule_once(self.restore)
        else:
            Clock.schedule_once(self.minimize)

    def restore(self, *_):
        Window.restore()

    def minimize(self, *_):
        Window.minimize()

    def on_restore(self, window):
        self.window_minimized = False
        Window.show()

    def on_minimize(self, window):
        self.window_minimized = True
        if self.config.getboolean("Settings",
                                  "minimizetray") and self.tray is not None:
            Window.hide()

    def window_exited(self, window):
        self.window_leave_timeout = Clock.schedule_once(
            self.window_exited_finish, 1)

    def window_entered(self, window):
        self.window_entered_finish()
        if self.window_leave_timeout is not None:
            self.window_leave_timeout.cancel()
            self.window_leave_timeout = None

    def window_exited_finish(self, *_):
        if self.config.getboolean("Settings", 'auto_shrink'):
            if self.modify_mode and self.popup is None and self.root.ids.editArea.current != 'edit':
                self.settings_mode()

    def window_entered_finish(self, *_):
        if self.config.getboolean("Settings", 'auto_expand'):
            if not self.modify_mode:
                self.settings_mode()

    def on_start(self):
        EventLoop.window.bind(on_keyboard=self.hook_keyboard)
        self.load_config_values()
        Window.set_title(self.window_title)
        if self.config.getboolean("Settings", "alwaysontop"):
            self.always_on_top()
        self.load_window_size()
        self.clipboard_updater = Clock.schedule_interval(
            self.update_current_clipboard, 0.1)
        if not self.clipboard_folder:
            self.root.ids.editArea.current = 'select'
            self.modify_mode = True
            Clock.schedule_once(self.add_presets_folder)
        else:
            self.modify_mode = False
        self.size_window()
        if self.config.getboolean("Settings", "minimizestart"):
            self.minimize()

    def always_on_top(self, *_):
        #Set on top mode
        self.on_top = True
        from KivyOnTop import register_topmost
        register_topmost(Window, self.window_title)

    def not_on_top(self, *_):
        self.on_top = False
        from KivyOnTop import unregister_topmost
        unregister_topmost(Window, self.window_title)

    def toggle_on_top(self):
        if self.on_top:
            self.not_on_top()
        else:
            self.always_on_top()

    def get_window_size(self):
        #Get window size
        if platform == 'win':
            SPI_GETWORKAREA = 48
            SM_CXSCREEN = 0
            SM_CYSCREEN = 1  #The height of the screen of the primary display monitor, in pixels.
            SM_CYCAPTION = 4  #The height of a caption area, in pixels.
            SM_CYBORDER = 6  #The height of a window border, in pixels.
            SM_CYFIXEDFRAME = 8  #The thickness of the frame around the perimeter of a window that has a caption but is not sizable, in pixels.

            from win32api import GetSystemMetrics
            taskbar_height = GetSystemMetrics(SPI_GETWORKAREA)
            screen_height = GetSystemMetrics(SM_CYSCREEN)
            screen_width = GetSystemMetrics(SM_CXSCREEN)
            window_frame_size = GetSystemMetrics(
                SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYBORDER)
            window_left_offset = window_frame_size
            window_top_offset = GetSystemMetrics(
                SM_CYCAPTION) + window_frame_size
            window_height = screen_height - window_top_offset - window_left_offset - taskbar_height
            window_width = screen_width - window_left_offset - window_left_offset
            return window_height, window_width, window_top_offset, window_left_offset
        else:
            return 680, self.window_min_width, 30, 5

    def on_pause(self):
        self.save_hiddens()
        self.config.write()
        return True

    def on_stop(self):
        if not (self.modify_mode and self.root.ids.editArea.current == 'edit'):
            self.save_hiddens()
        self.config.write()
        if self.tray is not None:
            self.tray.shutdown()

    def toggle_area(self, area):
        self.close_settings()
        if not self.modify_mode:
            self.root.ids.editArea.current = area
            self.modify_mode = True
            if area == 'edit':
                self.load_clipboards(edit=True)
            self.size_window()
        else:
            if self.root.ids.editArea.current == area:
                self.modify_mode = False
                self.load_clipboards()
                self.size_window()
            else:
                self.root.ids.editArea.current = area
                if area == 'edit':
                    self.load_clipboards(edit=True)

    def text_input_active(self):
        """Checks if any 'NormalInput' or 'FloatInput' widgets are currently active (being typed in).
        Returns: True or False
        """

        input_active = False
        for widget in self.root.walk(restrict=True):
            if widget.__class__.__name__ == 'NormalInput' or widget.__class__.__name__ == 'FloatInput' or widget.__class__.__name__ == 'IntegerInput':
                if widget.focus:
                    input_active = True
                    break
        return input_active

    def check_for_active_input(self, root):
        #Walks widget tree and checks for an active multiline text input, returns that input if found, otherwise returns None

        has_input = None
        for widget in root.walk(restrict=True):
            if isinstance(widget, TextInput):
                if widget.focus:
                    return widget
        return has_input

    def hook_keyboard(self, window, scancode, *_):
        """This function receives keyboard events"""

        #print(scancode)
        if scancode == 282:
            #f1 key
            if not self.modify_mode:
                self.settings_mode()
        if scancode == 27:
            #escape key
            if self.popup:
                self.popup.content.dispatch('on_answer', 'no')
                return True
        if scancode == 13:
            #enter key
            if self.popup:
                has_input = self.check_for_active_input(self.popup)
                if has_input is not None:
                    self.popup.content.dispatch('on_answer', 'yes')
        if scancode == 96:
            #tilde key
            if self.alt_pressed or self.ctrl_pressed or not self.text_input_active(
            ):
                self.settings_mode()
        if scancode == 283:
            #f2 key
            self.toggle_area('history')
        if scancode == 284:
            #f3 key
            self.toggle_area('edit')
        if scancode == 285:
            #f4 key
            self.toggle_area('select')
        if scancode == 97:
            #a key
            if self.alt_pressed:
                self.toggle_on_top()
        if scancode == 109:
            #m key
            if self.alt_pressed:
                self.minimize()

    def key_down(self, key, scancode=None, *_):
        """Intercepts various key presses and sends commands to the current screen."""

        del key
        if scancode == 307 or scancode == 308:
            #alt keys
            self.alt_pressed = True
        if scancode == 305 or scancode == 306:
            #ctrl keys
            self.ctrl_pressed = True
        if scancode == 303 or scancode == 304:
            #shift keys
            self.shift_pressed = True

    def key_up(self, key, scancode=None, *_):
        """Checks for the shift key released."""

        del key
        if scancode == 307 or scancode == 308:
            self.alt_pressed = False
        if scancode == 305 or scancode == 306:
            self.ctrl_pressed = False
        if scancode == 303 or scancode == 304:
            self.shift_pressed = False
Esempio n. 6
0
class ProjectApp(App):
    def build(self):
        # delete unnecessary default config file to avoid overloading App.get_application_config
        try:
            remove('project.ini')
        except:
            pass
        # check if config file in app dir exists
        self.custom_config_name = 'pppm.ini'
        self.app_folder = dirname(realpath(__file__))
        self.app_folder_config_fn = join(self.app_folder,
                                         self.custom_config_name)
        if isfile(self.app_folder_config_fn):
            # config is in app dir
            self.config.filename = self.app_folder_config_fn
        else:
            # config is in user dir
            self.config.filename = join(self.user_data_dir,
                                        self.custom_config_name)
        # title
        self.title = '3PM'
        # initialize settings
        self.use_kivy_settings = False
        self.settings_cls = SettingsWithTabbedPanel
        self.icon = join('data', 'icon.ico')
        # read configuration file
        self.config.read(self.config.filename)
        # initialize projects
        self.projects = Projects(name='projects', config=self.config)
        self.load_projects()
        # initialize ebs history
        self.velocity_history = []
        self.load_velocity_history()
        # initialize timer
        self.timer = Timer(self.config)
        self.simulation_string = StringProperty()
        # screen management and transition
        self.transition = SlideTransition(duration=.35)
        root = ScreenManager(transition=self.transition)
        root.add_widget(self.projects)
        return root

    def build_config(self, config):
        if platform in ['android', 'ios']:
            # smartphone defaults
            config.setdefaults(
                'timer', {
                    'start_sound': 1,
                    'end_sound': 1,
                    'vibrate': 1,
                    'notification': 0,
                    'notification_timeout': 10,
                    'session_length': 25,
                    'use_notepad': 0
                })
            config.setdefaults('ebs', {
                'use_ebs': 1,
                'number_history': 30,
                'log_activity': 0
            })
            config.setdefaults('system', {
                'enable_tray': 0,
                'hide_window': 0,
                'store_in_app': 0
            })
        else:
            # defaults for desktop computers
            config.setdefaults(
                'timer', {
                    'start_sound': 1,
                    'end_sound': 1,
                    'vibrate': 0,
                    'notification': 1,
                    'notification_timeout': 10,
                    'session_length': 25,
                    'use_notepad': 1
                })
            config.setdefaults('ebs', {
                'use_ebs': 1,
                'number_history': 30,
                'log_activity': 1
            })
            config.setdefaults('system', {
                'enable_tray': 1,
                'hide_window': 0,
                'store_in_app': 0
            })

    def build_settings(self, settings):
        settings.add_json_panel('Timer',
                                self.config,
                                data=settings_info.timer_settings_json)
        settings.add_json_panel('Simulation',
                                self.config,
                                data=settings_info.ebs_settings_json)
        settings.add_json_panel('System',
                                self.config,
                                data=settings_info.system_settings_json)

    def on_config_change(self, config, section, key, value):
        # react on store_in_app config change
        if section == 'system' and key == 'store_in_app':
            if value == '0':
                try:
                    # move data to user folder
                    move_if_exists(join(self.app_folder, 'projects.json'),
                                   join(self.user_data_dir, 'projects.json'))
                    move_if_exists(
                        join(self.app_folder, 'velocity_history.json'),
                        join(self.user_data_dir, 'velocity_history.json'))
                    move_if_exists(
                        join(self.app_folder, 'daily_activity.txt'),
                        join(self.user_data_dir, 'daily_activity.txt'))
                    # write config to user folder
                    self.config.filename = join(self.user_data_dir,
                                                self.custom_config_name)
                    self.config.write()
                    # remove old config file
                    remove(self.app_folder_config_fn)
                except:
                    # failed to move to new dir, undo config change
                    self.config.set('system', 'store_in_app', '1')
            else:
                try:
                    # move data to app folder
                    move_if_exists(join(self.user_data_dir, 'projects.json'),
                                   join(self.app_folder, 'projects.json'))
                    move_if_exists(
                        join(self.user_data_dir, 'velocity_history.json'),
                        join(self.app_folder, 'velocity_history.json'))
                    move_if_exists(
                        join(self.user_data_dir, 'daily_activity.txt'),
                        join(self.app_folder, 'daily_activity.txt'))
                    # write config to app folder
                    self.config.filename = join(self.app_folder,
                                                self.custom_config_name)
                    self.config.write()
                    # remove old config file
                    remove(join(self.user_data_dir, self.custom_config_name))
                except:
                    # failed to move to new dir, undo config change
                    self.config.set('system', 'store_in_app', '0')

        # react on enable_tray config change
        if section == 'system' and key == 'enable_tray' and platform == 'win':
            if value == '0':
                # shutdown tray icon
                try:
                    self.systray.shutdown()
                except:
                    pass
            else:
                # initialize system tray - todo: encapsulate
                menu_options = (("Show Session Info",
                                 "Show current task and remaining time.",
                                 self.systray_show_info), )
                hover_text = "Personal Project Productivity Manager - 3PM"
                self.systray = SysTrayIcon("data/icon.ico",
                                           hover_text,
                                           menu_options,
                                           default_menu_index=0,
                                           on_quit=self.systray_close_window)
                self.systray.start()

        # reinitialize timer
        self.timer.init(config)
        # reinitialize projects
        self.projects = Projects(name='projects', config=config)
        self.load_projects()
        # update projects view config
        self.projects.use_ebs = config.get('ebs', 'use_ebs') == '1'
        self.root.remove_widget(self.root.get_screen('projects'))
        self.root.add_widget(self.projects)
        self.root.current = 'projects'

    def on_start(self):
        # no current project index
        self.current_project_index = -1
        if platform == 'win' and self.config.get('system',
                                                 'enable_tray') == '1':
            # initialize system tray - todo: encapsulate
            menu_options = (("Show Session Info",
                             "Show current task and remaining time.",
                             self.systray_show_info), )
            hover_text = "Personal Project Productivity Manager - 3PM"
            self.systray = SysTrayIcon("data/icon.ico",
                                       hover_text,
                                       menu_options,
                                       default_menu_index=0,
                                       on_quit=self.systray_close_window)
            self.systray.start()

    def on_stop(self):
        self.config.write()
        if platform == 'win':
            # shutdown tray icon
            try:
                self.systray.shutdown()
            except:
                pass

    def systray_show_info(self, sysTrayIcon):
        # remaining time
        if self.timer.running_down:
            message_time = '%s remaining.' % self.timer.time_string
        elif self.timer.running_up:
            message_time = 'On break since %s.' % self.timer.time_string
        else:
            message_time = 'No session running.'
        # project string
        if self.current_project_index == -1:
            project_title = 'Quick Session'
        else:
            project_title = self.projects.data[
                self.current_project_index]['title']
        # show notification
        self.timer.notification_wrapper.notify(
            title=project_title,
            message=message_time,
            timeout=self.timer.notification_timeout)

    def systray_close_window(self, sysTrayIcon):
        # stop app if not called from traybar menu (not settings change)
        if self.config.get('system', 'enable_tray') == '1':
            try:
                App.get_running_app().stop()
            except:
                exit(0)

    def load_velocity_history(self):
        # load velocity history from file
        if isfile(self.velocity_history_fn):
            with open(self.velocity_history_fn) as fd:
                self.velocity_history = json.load(fd)
        else:
            # assume bad estimation
            self.velocity_history = [
                1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9
            ]

    def save_velocity_history(self):
        # save velocity history to file
        with open(self.velocity_history_fn, 'w') as fd:
            json.dump(self.velocity_history, fd)

    def load_projects(self):
        # load projects from file
        if not isfile(self.projects_fn):
            return
        with open(self.projects_fn) as fd:
            data = json.load(fd)
        self.projects.data = data

    def save_projects(self):
        # save projects to file
        with open(self.projects_fn, 'w') as fd:
            json.dump(self.projects.data, fd)

    def delete_project(self, project_index):
        # go to project list
        self.go_projects(project_index)
        # delete project
        del self.projects.data[project_index]
        self.save_projects()
        self.refresh_projects()

    def finish_project(self, project_index):
        # go to project list
        self.go_projects(project_index)
        if self.config.get('ebs', 'use_ebs') == '1':
            # get velocity rating
            vel_rating = self.projects.data[project_index][
                'logged'] / self.projects.data[project_index]['estimated']
            if vel_rating > 0:
                # save velocity rating to history
                self.velocity_history.append(vel_rating)
                self.save_velocity_history()
        # delete project
        del self.projects.data[project_index]
        self.save_projects()
        self.refresh_projects()

    def edit_project(self, project_index):
        self.current_project_index = project_index
        project = self.projects.data[project_index]
        name = 'project{}'.format(project_index)

        if self.root.has_screen(name):
            self.root.remove_widget(self.root.get_screen(name))

        if self.config.get('ebs', 'use_ebs') == '1':
            if self.config.get('timer', 'use_notepad') == '0':
                view = ProjectViewWithoutNotepad(
                    name=name,
                    project_index=project_index,
                    project_title=project.get('title'),
                    project_estimated=project.get('estimated'),
                    project_logged=project.get('logged'))
            else:
                view = ProjectView(name=name,
                                   project_index=project_index,
                                   project_title=project.get('title'),
                                   project_content=project.get('content'),
                                   project_estimated=project.get('estimated'),
                                   project_logged=project.get('logged'))

        else:
            if self.config.get('timer', 'use_notepad') == '0':
                view = ProjectViewSimpleWithoutNotepad(
                    name=name,
                    project_index=project_index,
                    project_title=project.get('title'))
            else:
                view = ProjectViewSimple(
                    name=name,
                    project_index=project_index,
                    project_title=project.get('title'),
                    project_content=project.get('content'))

        # add widget to root
        self.root.add_widget(view)
        self.transition.direction = 'left'
        self.root.current = view.name
        # update timer logged view
        self.timer.update_logged_string(project.get('logged'))
        # update simulation string
        self.update_simulation_string(project_index)

    def quick_session(self):
        if not self.root.current == '':
            # remove previous quick view screen
            if self.root.has_screen(''):
                self.root.remove_widget(self.root.get_screen(''))
            view = QuickView(project_content='')
            self.root.add_widget(view)
            self.transition.direction = 'left'
            self.root.current = view.name
            self.current_project_index = -1
        self.start_timer()

    def add_project(self):
        self.projects.data.append({
            'title': 'Unnamed Task',
            'content': '',
            'logged': 0,
            'estimated': 1
        })
        project_index = len(self.projects.data) - 1
        self.edit_project(project_index)

    def set_project_content(self, project_index, project_content):
        self.projects.data[project_index]['content'] = project_content
        data = self.projects.data
        self.projects.data = []
        self.projects.data = data
        self.save_projects()
        self.refresh_projects()

    def set_project_title(self, project_index, project_title):
        self.projects.data[project_index]['title'] = project_title
        self.save_projects()
        self.refresh_projects()

    def set_project_estimated(self, project_index, estimated):
        new_estimate = float(estimated)
        # sanity check
        if not new_estimate > 0:
            new_estimate = 1.0
        # save new estimate to project
        self.projects.data[project_index]['estimated'] = new_estimate
        self.save_projects()
        self.refresh_projects()
        # update simulation string
        self.update_simulation_string(project_index)

    def set_project_logged(self, project_index, logged):
        self.projects.data[project_index]['logged'] = float(logged)
        self.save_projects()
        self.refresh_projects()

    def refresh_projects(self):
        data = self.projects.data
        self.projects.data = []
        self.projects.data = data

    def go_projects(self, project_index):
        # stop in- or decrementing time
        Clock.unschedule(self.increment_time)
        Clock.unschedule(self.decrement_time)
        if project_index == -1:
            # quick session view; stop timer
            self.stop_timer()
        else:
            # project view; log work and stop timer
            if self.timer.running_down:
                self.stop_work(project_index)
        # go to project view
        self.transition.direction = 'right'
        self.root.current = 'projects'
        self.current_project_index = -1

    def start_work(self, project_index):
        # start new session if timer completely stopped
        if not self.timer.running_down and not self.timer.running_up:
            # start timer
            self.start_timer()
            # set current project index
            self.current_project_index = project_index
        # or reset and start new session if timer runs up
        if self.timer.running_up:
            # stop counting up
            self.stop_timer()
            # start timer
            self.start_timer()

    def stop_work(self, project_index):
        # only log work when timer running down
        if self.timer.running_down:
            if not project_index == -1:
                # log work
                self.log_work(project_index)
                # save log
                self.refresh_projects()
                self.save_projects()
        # stop timer
        self.stop_timer()

    def log_work(self, project_index):
        # get logged fractional unit: (full session time - remaining time) /  full session time
        full_session_time = float(self.config.get('timer', 'session_length'))
        logged_new = (full_session_time * 60. - (self.timer.minutes * 60. + self.timer.seconds)) / \
                     (full_session_time * 60.)
        logged_total = self.projects.data[project_index]['logged'] + logged_new
        # update logged
        self.set_project_logged(project_index, logged_total)
        # update logged view
        self.timer.update_logged_string(logged_total)
        # update simulation view
        self.update_simulation_string(project_index)

    def start_timer(self):
        # stop in- or decrementing time
        Clock.unschedule(self.increment_time)
        Clock.unschedule(self.decrement_time)
        # start decrementing time
        Clock.schedule_interval(self.decrement_time, 1)
        # store flags that timer is running down
        self.timer.running_up = False
        self.timer.running_down = True
        # play start sound if file found
        if self.timer.start_sound_activated and self.timer.start_sound:
            self.timer.start_sound.play()
        # hide main window if option activated
        if platform == 'win' and self.config.get('system',
                                                 'hide_window') == '1':
            self.root_window.hide()

    def stop_timer(self):
        # stop in- or decrementing time
        Clock.unschedule(self.increment_time)
        Clock.unschedule(self.decrement_time)
        # store flag that timer is not running down or up
        self.timer.running_down = False
        self.timer.running_up = False
        # reinitialize timer
        self.timer.minutes = self.timer.session_length
        self.timer.seconds = 0
        self.timer.update_time_string()

    def decrement_time(self, interval):
        # decrement time of timer
        self.timer.seconds -= 1
        if self.timer.seconds < 0:
            self.timer.minutes -= 1
            self.timer.seconds = 59
        if self.timer.minutes < 0:
            self.timer_alarm()
        self.timer.update_time_string()

    def increment_time(self, interval):
        # increment time of timer
        self.timer.seconds += 1
        if self.timer.seconds > 60:
            self.timer.minutes += 1
            self.timer.seconds = 0
        self.timer.update_time_string()

    def timer_alarm(self):
        # stop decrementing time
        Clock.unschedule(self.decrement_time)
        # set timer to 0:00
        self.timer.minutes = 0
        self.timer.seconds = 0
        # update time string
        self.timer.update_time_string()
        # log work
        if not self.current_project_index == -1:
            self.log_work(self.current_project_index)
        # save log
        self.refresh_projects()
        self.save_projects()
        if platform == 'win' and self.config.get('system',
                                                 'hide_window') == '1':
            # show main window again
            self.root_window.show()
        # log date of completed session to file
        if self.config.get('ebs', 'log_activity') == '1':
            # date and count for this session
            date_today = datetime.datetime.today().strftime('%Y-%m-%d')
            count_today = 1
            # read old file
            if isfile(self.activity_fn):
                with open(self.activity_fn, 'r') as f:
                    # read lines
                    lines = f.readlines()
                    # get date and count
                    date_file, count_file = lines[-1].split()
                    if date_file == date_today:
                        # add count from earlier sessions today
                        count_today += int(count_file)
                        # remove last line with current log for today
                        lines = lines[:-1]
            else:
                lines = []
            # append new last line
            lines.append("%s\t%s\n" % (date_today, str(count_today)))
            # write new file
            with open(self.activity_fn, 'w') as f:
                f.writelines(lines)

        # store flags that timer is not running down but up
        self.timer.running_down = False
        self.timer.running_up = True
        # start incrementing time
        Clock.schedule_interval(self.increment_time, 1)
        # show notification
        if self.timer.notification_activated:
            self.timer.notification_wrapper.notify(
                title="3PM",
                message="Session finished!",
                timeout=self.timer.notification_timeout)
        # play alarm sound if file found
        if self.timer.start_sound_activated and self.timer.alarm_sound:
            self.timer.alarm_sound.play()
        # vibrate on smartphone
        if self.timer.vibration_activated and platform in ['android', 'ios']:
            vibrator.vibrate(2)

    def simulate_completion(self, project_index):
        # only use most recent histories
        number_history = int(self.config.get('ebs', 'number_history'))
        if len(self.velocity_history) > number_history:
            velocity_history = self.velocity_history[-number_history:]
        else:
            velocity_history = self.velocity_history
        # MC simulate completion of project
        sessions_needed = []
        for i in range(0, 100):
            # randomly choose a velocity rating
            vel = random.choice(velocity_history)
            # simulate necessity sessions
            sessions_needed.append(
                vel * self.projects.data[project_index]['estimated'])
        # sort
        sessions_needed = sorted(sessions_needed)
        # pick quartiles
        quartiles = [sessions_needed[i] for i in [24, 49, 74, 99]]
        # calc completion
        logged = float(self.projects.data[project_index]['logged'])
        completion = [logged * 100 / quartiles[i] for i in [0, 1, 2, 3]]
        return quartiles, completion

    def update_simulation_string(self, project_index):
        # simulate completion of project
        quartiles, completion = self.simulate_completion(project_index)
        simulation_string = "%i/%i/%i/%i\n%i%%/%i%%/%i%%/%i%%" % tuple(
            quartiles + completion)
        self.timer.update_simulation_string(simulation_string)

    @property
    def data_dir(self):
        # get settings and data dir
        if self.config.get('system', 'store_in_app') == '1':
            return dirname(realpath(__file__))
        else:
            return self.user_data_dir

    @property
    def projects_fn(self):
        return join(self.data_dir, 'projects.json')

    @property
    def velocity_history_fn(self):
        return join(self.data_dir, 'velocity_history.json')

    @property
    def activity_fn(self):
        return join(self.data_dir, 'daily_activity.txt')
Esempio n. 7
0
class WindowsSystemTray(object):
    def __init__(self):
        self.image_dir = os.path.join(plexpy.PROG_DIR, 'data/interfaces/',
                                      plexpy.CONFIG.INTERFACE, 'images')
        self.icon = os.path.join(self.image_dir, 'logo-circle.ico')

        if plexpy.UPDATE_AVAILABLE:
            self.hover_text = common.PRODUCT + ' - Update Available!'
            self.update_title = 'Check for Updates - Update Available!'
        else:
            self.hover_text = common.PRODUCT
            self.update_title = 'Check for Updates'

        if plexpy.CONFIG.LAUNCH_STARTUP:
            launch_start_icon = os.path.join(self.image_dir, 'check-solid.ico')
        else:
            launch_start_icon = None
        if plexpy.CONFIG.LAUNCH_BROWSER:
            launch_browser_icon = os.path.join(self.image_dir,
                                               'check-solid.ico')
        else:
            launch_browser_icon = None

        self.menu = [['Open Tautulli', None, self.tray_open, 'default'],
                     ['', None, 'separator', None],
                     [
                         'Start Tautulli at Login', launch_start_icon,
                         self.tray_startup, None
                     ],
                     [
                         'Open Browser when Tautulli Starts',
                         launch_browser_icon, self.tray_browser, None
                     ], ['', None, 'separator', None],
                     [self.update_title, None, self.tray_check_update, None],
                     ['Restart', None, self.tray_restart, None]]
        if not plexpy.FROZEN:
            self.menu.insert(6, ['Update', None, self.tray_update, None])

        self.tray_icon = SysTrayIcon(self.icon,
                                     self.hover_text,
                                     self.menu,
                                     on_quit=self.tray_quit)

    def start(self):
        logger.info("Launching Windows system tray icon.")
        try:
            self.tray_icon.start()
        except Exception as e:
            logger.error("Unable to launch system tray icon: %s." % e)

    def shutdown(self):
        self.tray_icon.shutdown()

    def update(self, **kwargs):
        self.tray_icon.update(**kwargs)

    def tray_open(self, tray_icon):
        plexpy.launch_browser(plexpy.CONFIG.HTTP_HOST, plexpy.HTTP_PORT,
                              plexpy.HTTP_ROOT)

    def tray_startup(self, tray_icon):
        plexpy.CONFIG.LAUNCH_STARTUP = not plexpy.CONFIG.LAUNCH_STARTUP
        set_startup()

    def tray_browser(self, tray_icon):
        plexpy.CONFIG.LAUNCH_BROWSER = not plexpy.CONFIG.LAUNCH_BROWSER
        set_startup()

    def tray_check_update(self, tray_icon):
        versioncheck.check_update()

    def tray_update(self, tray_icon):
        if plexpy.UPDATE_AVAILABLE:
            plexpy.SIGNAL = 'update'
        else:
            self.hover_text = common.PRODUCT + ' - No Update Available'
            self.update_title = 'Check for Updates - No Update Available'
            self.menu[5][0] = self.update_title
            self.update(hover_text=self.hover_text, menu_options=self.menu)

    def tray_restart(self, tray_icon):
        plexpy.SIGNAL = 'restart'

    def tray_quit(self, tray_icon):
        plexpy.SIGNAL = 'shutdown'

    def change_tray_update_icon(self):
        if plexpy.UPDATE_AVAILABLE:
            self.hover_text = common.PRODUCT + ' - Update Available!'
            self.update_title = 'Check for Updates - Update Available!'
        else:
            self.hover_text = common.PRODUCT + ' - No Update Available'
            self.update_title = 'Check for Updates'
        self.menu[5][0] = self.update_title
        self.update(hover_text=self.hover_text, menu_options=self.menu)

    def change_tray_icons(self):
        if plexpy.CONFIG.LAUNCH_STARTUP:
            launch_start_icon = os.path.join(self.image_dir, 'check-solid.ico')
        else:
            launch_start_icon = None
        if plexpy.CONFIG.LAUNCH_BROWSER:
            launch_browser_icon = os.path.join(self.image_dir,
                                               'check-solid.ico')
        else:
            launch_browser_icon = None
        self.menu[2][1] = launch_start_icon
        self.menu[3][1] = launch_browser_icon
        self.update(menu_options=self.menu)
Esempio n. 8
0
class TaskTray():
    def __init__(self, wallcord):
        global credit_text

        self.window = wallcord
        self.root = self.window.root
        self.version = self.window.version

        with open("data.json", "r") as f:
            self.data = load(f)
        credit_text = credit_text.replace("!version!", self.version)

        if self.version in ["1.1.1", "1.1.0", "1.0.0"]:
            messagebox.showwarning(
                "FreedomWall",
                "バージョンとFreedomWallのプログラムがあいませんでした。\n再ダウンロードしてください。")
            self.window.onoff = False
            self.window.q.append(self.exit)

        # メインスレッドじゃないとTkinterメソッドを実行できない。
        # だからメインスレッドのFreedomWallクラスのself.qに実行したいのを追加する。
        # そしてメインスレッドから実行する。
        # だから lambda がある。
        self.icon = SysTrayIcon(
            "icon.ico",
            "FreedomWall",
            (("FreedomWall", None,
              lambda sysTrayIcon: self.window.q.append(self.credit)),
             ("Set", None,
              lambda sysTrayIcon: self.window.q.append(self.setting)),
             ("Del", None,
              lambda sysTrayIcon: self.window.q.append(self.delete)),
             ("List", None,
              lambda sysTrayIcon: self.window.q.append(self.setting_list))),
            on_quit=lambda sysTrayIcon: self.window.q.append(self.exit))

    # 壁紙の設定。
    def setting(self):
        # simpledialog.askstringで入力ボックスを表示する。
        # それを使い設定をする。

        title = simpledialog.askstring("FreedomWall",
                                       "設定したいウィンドウのタイトルにある文字を入力してください。")
        if not title:
            return

        alpha = simpledialog.askstring(
            "FreedomWall",
            "壁紙の透明度を入力してください。\nデフォルトは0.2です。\n元の背景が白の場合は0.3あたりの数値が良いです。\n元の背景が黒の場合は0.1あたりの数値が良いです。"
        )
        if not alpha:
            return
        try:
            alpha = float(alpha)
        except:
            messagebox.showwarning("FreedomWall", "0.1 ~ 1 の間を設定してください。")
            return

        exception = simpledialog.askstring(
            "FreedomWall",
            "例外ウィンドウのタイトルにある文字を入力してください。\nコンマ( , )を使うことで複数追加できます。\n\n例えばLINEを登録したあとにLINEについてのウェブサイトを閲覧したとします。\nするとブラウザのタイトルにLINEが入り被りが発生します。\nそれを防ぐためにブラウザのタイトルを入れることをおすすめします。"
        )
        exception = exception.split(",") if exception else []

        # 壁紙ファイルを取得する。
        file_path = filedialog.askopenfilename(
            filetypes=[("壁紙ファイル", "*.png;*.jpg;*.mp4")])
        if not file_path:
            return

        # 存在確認をする。
        if not GetWindow(title, "bubun"):
            messagebox.showwarning("FreedomWall",
                                   f"{title}があるタイトルのウィンドウが見つかりませんでした。")
            return

        self.data["windows"][title] = {
            "path": file_path,
            "alpha": alpha,
            "exception": exception
        }
        with open("data.json", "w") as f:
            dump(self.data, f, indent=4)

        # メインスレッドのdataを再読み込みさせる。
        self.window.reload()

        self.window.now = {"path": "", "alpha": 0, "exception": []}
        messagebox.showinfo("FreedomWall", "設定しました。")

    # 壁紙の削除。
    def delete(self):
        title = simpledialog.askstring("FreedomWall", "削除したい設定名を入力してください。")
        if not title:
            return
        if not title in self.data["windows"]:
            messagebox.showwarning("FreedomWall", "その設定が見つかりませんでした。")
            return

        del self.data["windows"][title]
        with open("data.json", "w") as f:
            dump(self.data, f, indent=4)

        # メインスレッドのdataを再読み込みさせる。
        self.window.reload()

        self.window.now = {"path": "", "alpha": 0, "exception": []}
        messagebox.showinfo("FreedomWall", "その設定を削除しました。")

    # 壁紙一覧。
    def setting_list(self):
        desc = ", ".join(data for data in self.data["windows"].keys())
        messagebox.showinfo("FreedomWall", desc)

    # クレジット。
    def credit(self):
        messagebox.showinfo("FreedomWall", credit_text)

    # 終了。
    def exit(self):
        self.root.quit()
        self.window.video = None
        self.icon.shutdown()

    # 実行。
    def run(self):
        self.icon.start()
Esempio n. 9
0
        Home[f'E{i+2}'] = f'=DetailledHome!F{i+2}'
        Home[f'G{i+2}'] = f'=DetailledHome!E{i+2}'
        Home[f'H{i+2}'] = f'=DetailledHome!I{i+2}'
    Home['K1'] = '=DetailledHome!V1'

    #Fill Values sheet
    for i in range(len(prices)):
        values[f'A{i+2}'] = prices[i].get('symbol')
        values[f'B{i+2}'] = prices[i].get('price')
    values['D1'] = "Last update at " + str(
        datetime.now().strftime("%H:%M:%S %d-%m-%Y"))

    #Save Excel
    try:
        workbook.save('trading.xlsx')
        print('Saved !')
    except:
        print('Not saved because file is open...')
        pass


while run:
    modify()
    for i in range(refresh):
        if run == True:
            sleep(1)
        else:
            break

tray.shutdown()
Esempio n. 10
0
class TrayIcon(Pipeable):
    """
    Non-blocking tray icon.

    Tray icons require blocking due to having to wait for button clicks.
    To prevent blocking on the main thread, a tread is spawned for the tray
    icon and click events are send through `Pipeable` pipes.
    """

    MenuOptionCallback = Callable[[SysTrayIcon], None]
    MenuOption = tuple[str, Optional[str], MenuOptionCallback]

    _thread: Thread
    _icon: SysTrayIcon
    _menu_options: list[MenuOption] = []
    _stop_event: Event

    _icon_image: str
    _hover_text: str

    def __init__(self, icon_image: str = "icon.ico", hover_text: str = "Hover text", stop_event: Event = Event()):
        """
        Initialize system tray icon.

        Args:
            icon_image (str, optional): Name of image to use as tray icon. Defaults to "icon.ico".
            hover_text (str, optional): Text displayed when the tray icon is hovered. Defaults to "Hover text".
            stop_event (Event, optional): Flag is set when the tray icon process exits. Defaults to Event().
        """
        super().__init__()

        self._stop_event = stop_event

        self._icon_image = icon_image
        self._hover_text = hover_text

        self._menu_options = [
            ("Show QR code", None, lambda icon: self._pipe.send("show_qr_code")),
            ("Show debug logs", None, lambda icon: self._pipe.send("show_debug_logs"))
        ]

    def run(self):
        """
        Display the tray icon in the system tray.

        Tray icon thread is spawned and the tray loop is executed.
        """
        self._icon = SysTrayIcon(
            self._icon_image, self._hover_text, tuple(self._menu_options), on_quit=self.handle_quit)

        self._thread = Thread(target=self._loop)
        self._thread.start()

    def handle_quit(self, icon: SysTrayIcon):
        """
        Set the stop flag.

        Called when the quit option is selected from the icons context menu.

        Args:
            icon (SysTrayIcon): SysTrayIcon reference
        """
        self._stop_event.set()

    def join(self):
        """Join the thread that runs the TrayIcon."""
        self._thread.join()

    def _loop(self):
        """
        Listen to events on the system tray icon.

        @NOTE This should not be run directly and will block the main thread.
        It is automatically executed on a spawned worker thread internally.
        """
        self._icon.start()

        while True:
            if self._stop_event.is_set():
                self._icon.shutdown()
                return

            sleep(SLEEP_INTERVAL)
Esempio n. 11
0
class WinShutdownTimer(GridLayout, ToggleButtonBehavior):
    # Define default layout attributes
    font_size = 20
    widget_padding = (25, 10, 25, 10)
    spacer_width = 10
    abort_disabled = BooleanProperty(True)
    abort_background_color = ListProperty([1, 1, 1, 1])
    popup_active = BooleanProperty(False)
    # Define default cmd button attributes
    shutdown_btn_disabled = BooleanProperty(False)
    shutdown_btn_state = StringProperty('normal')
    restart_btn_disabled = BooleanProperty(False)
    restart_btn_state = StringProperty('normal')
    hibernate_btn_disabled = BooleanProperty(False)
    hibernate_btn_state = StringProperty('normal')
    logoff_btn_disabled = BooleanProperty(False)
    logoff_btn_state = StringProperty('normal')
    # Define default time button attributes
    set20_disabled = BooleanProperty(False)
    set20_state = StringProperty('normal')
    set40_disabled = BooleanProperty(False)
    set40_state = StringProperty('normal')
    set60_disabled = BooleanProperty(False)
    set60_state = StringProperty('normal')
    set90_disabled = BooleanProperty(False)
    set90_state = StringProperty('normal')
    set120_disabled = BooleanProperty(False)
    set120_state = StringProperty('normal')
    preset_status = BooleanProperty(True)
    preset_keybinding_enabled = BooleanProperty(True)
    # Define -15min/+15min buttons' status
    sub_time_disabled = BooleanProperty(True)
    add_time_disabled = BooleanProperty(False)
    # Establish countdown variable
    countdown = NumericProperty(0)
    # Define Start/Pause button attributes
    start_pause = StringProperty('Start')
    start_pause_disabled = BooleanProperty(True)
    # Establish final cmd string variable
    final_cmd = StringProperty('')

    # Retrieve default settings if the file exists, else create the file and
    # set defaults
    try:
        with open(user_settings_file, 'r') as f:
            user_settings = ast.literal_eval(f.read())
    except FileNotFoundError:
        user_settings = {
            'default_cmd': 'shutdown',
            'default_time': 'set20',
        }
        with open(user_settings_file, 'w+') as f:
            json.dump(user_settings, f, indent=4)

    def __init__(self):
        super(WinShutdownTimer, self).__init__()
        self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
        self._keyboard.bind(on_key_down=self._on_keyboard_down)

        # Define system tray icon
        icon_path = os.path.join(os.path.dirname(__file__),
                                 '.\Images\powerbutton_UAh_icon.ico')

        # Context Menu Options -- NOTE: Quit is REQUIRED
        def on_quit(systray):
            App.get_running_app().stop()

        def on_help(systray):
            ctypes.windll.user32.MessageBoxW(
                None, u'Help options to be defined in a future release',
                u'Help', 0)

        # def on_abort(systray):
        #     self.reset()

        def on_about(systray):
            ctypes.windll.user32.MessageBoxW(None,
                                             u'WinShutdown\n\nBy: WutDuk?',
                                             u'About', 0)

        menu_options = (
            ('Help', None, on_help),
            # ('Abort', None, on_abort),
            ('About', None, on_about))

        # # Set tray icon options
        self.systray = SysTrayIcon(icon_path, 'WinShutdown', menu_options,
                                   on_quit)

        # Bind to closing the window
        Window.bind(on_close=self.close_systray)

    # Close system tray icon
    def close_systray(self, *args):
        self.systray.shutdown()

    def apply_defaults(self):
        default_cmd = self.user_settings['default_cmd']
        default_time = self.user_settings['default_time']
        # cmd_group buttons
        if default_cmd == 'shutdown':
            self.shutdown_btn_state = 'down'
        elif default_cmd == 'restart':
            self.restart_btn_state = 'down'
        elif default_cmd == 'hibernate':
            self.hibernate_btn_state = 'down'
        elif default_cmd == 'log off':
            self.logoff_btn_state = 'down'
        # time buttons
        if default_time == 'set20':
            self.set20_state = 'down'
            self.countdown = 20 * 60
        elif default_time == 'set40':
            self.set40_state = 'down'
            self.countdown = 40 * 60
        elif default_time == 'set60':
            self.set60_state = 'down'
            self.countdown = 60 * 60
        elif default_time == 'set90':
            self.set90_state = 'down'
            self.countdown = 90 * 60
        elif default_time == 'set120':
            self.set120_state = 'down'
            self.countdown = 120 * 60
        # Enable Start/Pause and -15 min buttons
        self.start_pause_disabled = False
        self.sub_time_disabled = False

    # Method to get the current cmd value
    def get_cmd(self):
        if self.ids.shutdown.state == 'down':
            self.cmd = 'Shutdown'
        elif self.ids.restart.state == 'down':
            self.cmd = 'Restart'
        elif self.ids.hibernate.state == 'down':
            self.cmd = 'Hibernate'
        elif self.ids.logoff.state == 'down':
            self.cmd = 'Log Off'
        return self.cmd

    # Method to get the current time value
    def get_time(self):
        if self.ids.set20.state == 'down':
            self.time = 'set20'
        elif self.ids.set40.state == 'down':
            self.time = 'set40'
        elif self.ids.set60.state == 'down':
            self.time = 'set60'
        elif self.ids.set90.state == 'down':
            self.time = 'set90'
        elif self.ids.set120.state == 'down':
            self.time = 'set120'
        return self.time

    def set_app_settings(self):
        with open(user_settings_file, 'w') as f:
            json.dump(self.user_settings, f, indent=4)

    def get_curr_settings(self):
        self.user_settings['default_cmd'] = self.get_cmd().lower()
        self.user_settings['default_time'] = self.get_time()

    def _keyboard_closed(self):
        self._keyboard.unbind(on_key_down=self._on_keyboard_down)
        self._keyboard = None

    # See \kivy\core\window\__init__.py for keycode details
    def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
        if self.preset_keybinding_enabled == True:
            # cmd buttons
            if keycode[0] == 115:
                self.ids.shutdown.trigger_action(0)
            elif keycode[0] == 114:
                self.ids.restart.trigger_action(0)
            elif keycode[0] == 104:
                self.ids.hibernate.trigger_action(0)
            elif keycode[0] == 108:
                self.ids.logoff.trigger_action(0)
            # preset duration buttons
            elif keycode[0] in (50, 258):
                self.ids.set20.trigger_action(0)
            elif keycode[0] in (52, 260):
                self.ids.set40.trigger_action(0)
            elif keycode[0] in (54, 262):
                self.ids.set60.trigger_action(0)
            elif keycode[0] in (57, 265):
                self.ids.set90.trigger_action(0)
            elif keycode[0] in (49, 257):
                self.ids.set120.trigger_action(0)

        # subtract time / add time buttons
        if self.sub_time_disabled == False:
            if keycode[0] in (45, 269, 274, 276):
                self.ids.minus15.trigger_action(0)

        if self.add_time_disabled == False:
            if keycode[0] in (61, 270, 273, 275):
                self.ids.plus15.trigger_action(0)

        # If there's no active popup, then
        if self.popup_active == False:
            # Start/Stop buttons
            if self.countdown > 0 and self.start_pause_disabled == False:
                if keycode[0] in (13, 16, 32, 271):
                    self.ids.start_pause.trigger_action(0)

            # Abort button
            if self.abort_disabled == False:
                if keycode[0] == 97:
                    self.ids.abort.trigger_action(0)

        # If there is an active popop, then
        if self.popup_active == True:
            # ImminentPopup Yes/No buttons
            if keycode[0] == 121:
                self.imminent_popup.ids.yes.trigger_action(0)
            elif keycode[0] == 110:
                self.imminent_popup.ids.no.trigger_action(0)

    def toggle_keybinding_allowed(self):
        if self.ids.start_pause.state == 'down':
            self.preset_keybinding_enabled = False
        else:
            self.preset_keybinding_enabled = True

    # Method called when countdown reaches 0 to execute the selected
    # cmd from the cmd_group togglebuttons
    def initiate_shutdown(self, *args):
        cmd = self.cmd
        # Provide the reason for the restart or shutdown. These events are
        # documented as "Other Planned"
        d_cmd = '/d p:0:0'
        # Comment on the reason for the restart or shutdown.
        c_cmd = f'/c "Automated User-initiated {cmd} via WinShutdown"'
        # If the Start/Pause button is down (should say 'Pause') and the
        # countdown is at 0, then
        if self.countdown == 0:
            # If the Shutdown button is down, then
            if cmd == 'Shutdown':
                # Compile the cmd string for a shutdown
                # final_cmd = f'shutdown /s' + ' ' + d_cmd + ' ' + c_cmd
                # final_cmd = f'shutdown /s /f' + ' ' + d_cmd + ' ' + c_cmd
                self.final_cmd = f'shutdown /p {d_cmd} {c_cmd}'
            # Else, if the Restart button is down, then
            elif cmd == 'Restart':
                # Compile the cmd string for a restart
                self.final_cmd = f'shutdown /r {d_cmd} {c_cmd}'
            # Else, if the Hibernate button is down, then
            elif cmd == 'Hibernate':
                # Compile the cmd string for a hibernate
                self.final_cmd = 'shutdown /h'
            # Else, if none of the above, compile a cmd string for logoff
            elif cmd == 'Log Off':
                self.final_cmd = 'shutdown /l'
            # Instantiate and open the final popup then start final timer
            self.final_popup = FinalPopup()
            self.final_popup.open()
            self.popup_active = True
            self.final_popup.start_final_timer()

    # Method called by FinalPopup to execute self.final_cmd
    def exec_cmd(self, *args):
        # send final cmd to cmd shell
        subprocess.call(final_cmd, shell=True)

    # Method to set the countdown timer. This doesn't add time.
    # Instead it replaces time.
    def set_timer(self, button_time):
        # If the countdown is at 0, then
        if self.countdown == 0:
            # Then set the countdown to the time of the button that
            # initiated the call
            self.countdown = button_time

    # Method to clear the timer to 0
    def clear_timer(self):
        self.countdown = 0

    # Method to toggle the '-15 min' button's state
    def toggle_sub_time_status(self):
        # If the countdown is less than 15 minutes, then
        if self.countdown < 15 * 60:
            # The '-15 min' button is disabled because there's
            # no time to subtract
            self.sub_time_disabled = True
        # Otherwise, the button is active
        else:
            self.sub_time_disabled = False

    # Method to toggle the '+ 15 min' button status
    def toggle_add_time_status(self):
        # If '+ 15 min' button is not disabled, set to disabled
        if self.add_time_disabled == False:
            self.add_time_disabled = True
        # Else, if countdown is 0 and '+ 15 min' button is disabled,
        # make it active
        elif self.countdown == 0 or self.add_time_disabled == True:
            self.add_time_disabled = False

    # Method to toggle the Start/Pause button status
    def toggle_start_pause_status(self):
        # If the countdown is greater than 0
        if self.countdown > 0:
            # The Start/Pause button is active and can be clicked
            self.start_pause_disabled = False
        else:
            # Otherwise the timer is at 0 and there's no function for
            # this button, so it's disabled
            self.start_pause_disabled = True

    # Method to toggle the Abort button state
    def toggle_abort_status(self):
        # If countdown is greater than 0 and the Start/Pause button
        # is down, then
        if self.countdown > 0 and self.ids.start_pause.state == 'down':
            # The Abort button is active, and colored red
            self.abort_disabled = False
            self.abort_background_color = [1, 0, 0, 1]
        # Else the button is disabled and returns to default gray
        else:
            self.abort_disabled = True
            self.abort_background_color = [1, 1, 1, 1]

    # Method to toggle the status of preset cmd buttons
    # (20, 40, 60, 90, 120)
    def toggle_cmd_status(self):
        # If the Start/Pause button is down (countdown is active), then
        if self.ids.start_pause.state == 'down':
            # Then preset cmd buttons are down. To apply a preset, Pause or
            # Abort the countdown.
            self.preset_status = True
        # Otherwise they are available and can be selected at any time
        else:
            self.preset_status = False
        self.shutdown_btn_disabled = self.preset_status
        self.restart_btn_disabled = self.preset_status
        self.hibernate_btn_disabled = self.preset_status
        self.logoff_btn_disabled = self.preset_status

    # Method to toggle the status of preset time buttons
    # (20, 40, 60, 90, 120)
    def toggle_preset_status(self):
        # If the Start/Pause button is down (countdown is active), then
        if self.ids.start_pause.state == 'down':
            # Then preset time buttons are down. To apply a preset, Pause or
            # Abort the countdown.
            self.preset_status = True
        # Otherwise they are available and can be selected at any time
        else:
            self.preset_status = False
        self.set20_disabled = self.preset_status
        self.set40_disabled = self.preset_status
        self.set60_disabled = self.preset_status
        self.set90_disabled = self.preset_status
        self.set120_disabled = self.preset_status

    # Method to toggle the Start/Pause button state (up or down)
    def toggle_start_pause_state(self):
        # If Start/Pause says 'Start', then
        if self.start_pause == 'Start':
            # Set the button to 'up'
            self.ids.start_pause.state = 'normal'
        # Else the button is down
        else:
            self.ids.start_pause.state = 'down'

    # Method to toggle the state of presets (up or down)
    def toggle_preset_state(self):
        # If countdown is at 0, the presets are in the 'up' state
        if self.countdown == 0:
            self.ids.set20.state = 'normal'
            self.ids.set40.state = 'normal'
            self.ids.set60.state = 'normal'
            self.ids.set90.state = 'normal'
            self.ids.set120.state = 'normal'

    # Method to toggle the state cmd buttons (up or down)
    def toggle_cmd_state(self):
        self.ids.shutdown.state = 'normal'
        self.ids.restart.state = 'normal'
        self.ids.hibernate.state = 'normal'
        self.ids.logoff.state = 'normal'

    # Method to toggle the Start/Pause text label of the button
    def toggle_start_pause_text(self):
        # If the Start/Pause button is down and the countdown is above 0, then
        if self.ids.start_pause.state == 'down' and self.countdown > 0:
            # The countdown is active, so set the button text to 'Pause'
            self.start_pause = 'Pause'
        # Else, set the text to 'Start'
        else:
            self.start_pause = 'Start'

    def start_stop_timer(self):
        # Cancel any current animation in progress
        Animation.cancel_all(self)
        # Define the rules for Animation; i.e., (where we are going, where
        # we're coming from)
        self.anim = Animation(
            countdown=0,
            duration=self.countdown,
        )
        # on_release of Start/Pause button, if it's down and there is still
        # time on the clock, then
        if self.ids.start_pause.state == 'down' and self.countdown > 0:
            # Set current cmd value
            self.get_cmd()
            # On completion of the countdown, call method to initiate the
            # shutdown process
            self.anim.bind(on_complete=self.initiate_shutdown)
            # Start the animation
            self.anim.start(self)

    # Method to add time to the current countdown (as opposed to resetting)
    # v1.1 introduced the ability to edit a live countdown, so Start/Pause
    # state is no longer checked
    def add_time(self, button_time):
        # The timer must be stopped in order to add time
        self.start_stop_timer()
        # Add to the current countdown time the time of the button that
        # initiated the call
        self.countdown += button_time
        # The timer is then restarted again
        self.start_stop_timer()

    # Method to subtract time from the current countdown (as opposed to
    # resetting)
    def sub_time(self, button_time):
        # If subtracting time would set the countdown to 0 or less, then
        if button_time >= self.countdown:
            # If the Start/Pause button is 'down', then
            if self.ids.start_pause.state == 'down':
                # Instantiate ImminentPopup
                self.imminent_popup = ImminentPopup(self.cmd)
                # Toggle '+ 15 min' button status
                self.toggle_add_time_status()
                # Disable '- 15 min button'
                self.sub_time_disabled = True
                # Stop the countdown, then
                Animation.cancel_all(self)
                # Call the pop-up to notify User of imminent shutdown,
                # restart, etc.
                self.imminent_popup.open()
                self.popup_active = True
            # Else, Start/Pause is 'normal' and the countdown isn't active, so
            else:
                # Set the countdown to 0
                self.countdown = 0
                # Disable '- 15 min' button
                self.sub_time_disabled = True
        # Else, the timer will remain above 0, so
        else:
            # The timer must be stopped in order to add time, then
            self.start_stop_timer()
            # Subtract from the current countdown time the time of the button
            # that initiated the call
            self.countdown -= button_time
            # The timer is then restarted again
            self.start_stop_timer()

    # Method to initiate shutdown on 'Yes' response to pop-up
    def popup_yes(self):
        self.countdown = 0
        self.initiate_shutdown()
        self.popup_active = False

    # Method to dismiss the pop-up and restart the countdown
    def popup_no(self):
        self.anim.start(self)
        self.toggle_add_time_status()
        self.sub_time_disabled = False
        self.popup_active = False

    # Method to reset the entire app
    def reset(self):
        Animation.cancel_all(self),
        self.clear_timer(),
        self.toggle_start_pause_status(),
        self.toggle_start_pause_text(),
        self.toggle_start_pause_state(),
        self.toggle_preset_status(),
        self.toggle_cmd_status(),
        self.toggle_sub_time_status(),
        self.toggle_abort_status(),
        self.toggle_keybinding_allowed(),
        self.apply_defaults()
Esempio n. 12
0
class SysTrayPlugin(plugins.SimplePlugin):
    '''
    CherryPy plugin that creates a system tray icon for Windows.

    Because SysTrayIcon always fires off on_quit, we can't have on_quit
        execute cherrypy.engine.exit() if the exit command is what triggered
        SysTrayIcon to close. So conditions are set to only fire on_quit when
        the quit_method == 'menu'.

    This way, when the menu option is called, it destroys SysTrayIcon then
        closes cherrypy. Cherrypy will try to close SysTrayIcon by calling
        stop(), so stop() gets reassigned to None.

    If the app is closed by cherrypy (whether catching a kb interrupt or the GUI
        shutdown button), cherrypy stops the plugin by calling stop(). Stop()
        reassigns SysTrayIcon._on_quit to None and calls SysTrayIcon.shutdown().
        SysTrayIcon is then destroyed (twice for reasons I can't figure out),
        then cherrypy finishes up the engine.stop() and engine.exit().

    The chain is as such:

    Trigger == systray menu 'Quit':
    SysTrayIcon._destroy() >
    SysTrayIcon._on_quit() > set SysTrayPlugin.quit_method = 'menu'
    cherrypy.engine.exit() >
    SysTrayPlugin.stop()   > does nothing
    sys.exit()

    Trigger == KBInterrupt or GUI Shutdown:
    cherrypy.engine.stop() >
    SysTrayPlugin.stop()   > disable SysTrayIcon._on_quit()
    SysTrayIcon.shutdown() >
    SysTrayIcon._destroy() >
    SysTrayIcon._destroy() >
    cherrypy.engine.exit() >
    sys.exit()

    '''

    def __init__(self, bus):
        plugins.SimplePlugin.__init__(self, bus)
        menu_options = (('Open Browser', None, self.open),)
        self.systray = SysTrayIcon('core/favicon.ico', 'Watcher',
                                   menu_options, on_quit=self.on_quit)
        self.quit_method = None
        return

    def start(self):
        self.systray.start()
        return

    def stop(self):
        if self.quit_method == 'menu':
            return
        else:
            self.systray._on_quit = None
            self.systray.shutdown()
            return

    def on_quit(self, systray):
        self.quit_method = 'menu'
        cherrypy.engine.exit()
        sys.exit(0)

    # sys tray functions:
    def open(self, systray):
        webbrowser.open(u'http://{}:{}{}'.format(
            core.SERVER_ADDRESS, core.SERVER_PORT, core.URL_BASE))
        return
Esempio n. 13
0
        actualWindow.resizeRel(0, int((a - b) * 1.60))

        #print('2188?\t',c)
        #printuj_staty_kurwo()
        #print(c-a)

    else:
        actualWindow = gw.getWindowsWithTitle(
            win32gui.GetWindowText(win32gui.GetForegroundWindow()))[0]
        win32gui.SetWindowPos(win32gui.GetForegroundWindow(),
                              win32con.HWND_TOP, argv[1][0], int(y),
                              argv[1][1], int(h1), 0)
        actualWindow.moveRel(-10, 0)


monitory = []
menu_options = (("Status", None, say_hello), )
systray = SysTrayIcon(
    'reSize.ico', 'Ready to reSize!',
    menu_options)  #Icon made by Freepik from www.flaticon.com
systray.shutdown(
)  #https://www.flaticon.com/free-icon/maximize_1141984#term=resize&page=1&position=64
systray.start()

platform = pyglet.window.get_platform()
display = platform.get_default_display()
for screen in display.get_screens():
    monitory.append(screen)
zakresy_var = zakresy(monitory)

keyboard.add_hotkey('ctrl+f1', callback, (zakresy_var))
Esempio n. 14
0
class SysTrayPlugin(plugins.SimplePlugin):
    '''
    CherryPy plugin that creates a system tray icon for Windows.

    Because SysTrayIcon always fires off on_quit, we can't have on_quit
        execute cherrypy.engine.exit() if cherrypy.engine.exit() is what
        triggered SysTrayIcon to close. So conditions are set to only fire
        on_quit when the quit_method == 'men'.

    This way, when the menu option is called, it destroys SysTrayIcon then
        closes cherrypy. Cherrypy will try to close SysTrayIcon by calling
        stop(), so _on_quit() gets reassigned to None.

    If the app is closed by cherrypy (whether catching a kb interrupt or the GUI
        shutdown button), cherrypy stops the plugin by calling stop(). Stop()
        reassigns SysTrayIcon._on_quit to None and calls SysTrayIcon.shutdown().
        SysTrayIcon is then destroyed (twice for reasons I can't figure out),
        then cherrypy finishes up the engine.stop() and engine.exit().

    The chain is as such:

    Trigger == systray menu 'Quit':
    SysTrayIcon._destroy() >
    SysTrayIcon._on_quit() > set SysTrayPlugin.quit_method = 'men'
    cherrypy.engine.exit() >
    SysTrayPlugin.stop()   > does nothing
    sys.exit()

    Trigger == KBInterrupt or GUI Shutdown:
    cherrypy.engine.stop() >
    SysTrayPlugin.stop()   > disable SysTrayIcon._on_quit()
    SysTrayIcon.shutdown() >
    SysTrayIcon._destroy() >
    SysTrayIcon._destroy() >
    cherrypy.engine.exit() >
    sys.exit()

    '''

    def __init__(self, bus, icon, name, menu_options, on_quit=lambda: None):
        if not callable(on_quit):
            raise TypeError('on_quit not a callable object.')
        self.on_quit = on_quit

        plugins.SimplePlugin.__init__(self, bus)
        self.systray = SysTrayIcon(icon, name, menu_options, on_quit=self._on_quit)
        self.quit_method = None
        return

    def start(self):
        self.systray.start()
        return

    def stop(self):
        if self.quit_method == 'men':
            return
        else:
            self.systray._on_quit = None
            self.systray.shutdown()
            return

    def _on_quit(self, systray):
        self.on_quit()
        self.quit_method = 'men'
        cherrypy.engine.exit()
        sys.exit(0)
Esempio n. 15
0
class TrayIcon:
    def __init__(self):
        menuOptions = (('Audio', None, (('Select Alert Sound', None,
                                         self._onSelectAlertSound),
                                        ('Play', None, self._onPlayAlert),
                                        ('Stop', None, self._onStopAlert))),
                       ('Open Maps File', None, self._onOpenMapsFile),
                       ('Select Path of Exile folder', None,
                        self._onSelectPathOfExileDirectory))
        self._icon = SysTrayIcon(iconPath,
                                 'Map Alert',
                                 menu_options=menuOptions,
                                 on_quit=self._onQuit)
        self._callbackQueue = queue.Queue()

    async def show(self):
        self._icon.start()
        while True:
            try:
                callback = self._callbackQueue.get(False)
                callback()
            except queue.Empty:
                await asyncio.sleep(0.1)

    def close(self):
        self._icon.shutdown()

    def onSelectAlertSound(self):
        pass

    def onPlayAlert(self):
        pass

    def onStopAlert(self):
        pass

    def onOpenMapsFile(self):
        pass

    def onSelectPathOfExileDirectory(self):
        pass

    def onQuit(self):
        pass

    def _onSelectAlertSound(self, sysTray):
        self._callbackQueue.put(self.onSelectAlertSound)

    def _onPlayAlert(self, sysTray):
        self._callbackQueue.put(self.onPlayAlert)

    def _onStopAlert(self, sysTray):
        self._callbackQueue.put(self.onStopAlert)

    def _onOpenMapsFile(self, sysTray):
        self._callbackQueue.put(self.onOpenMapsFile)

    def _onSelectPathOfExileDirectory(self, sysTray):
        self._callbackQueue.put(self.onSelectPathOfExileDirectory)

    def _onQuit(self, sysTray):
        self._callbackQueue.put(sysTray.shutdown)
        self._callbackQueue.put(self.onQuit)