コード例 #1
0
ファイル: window.py プロジェクト: prusya/fuzzy-eve-notifier
class MainWindow(wx.Frame):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(parent=None,
                                         title='Fuzzy Eve Notifier',
                                         size=(850, 400),
                                         style=wx.MINIMIZE_BOX | wx.SYSTEM_MENU
                                         | wx.CAPTION | wx.CLOSE_BOX)

        self.init_ui()
        self.Centre()
        self.Show(True)
        self.Bind(wx.EVT_CLOSE, self.on_exit)
        self.watcher = Watcher(self.show_popup)
        self.watcher.run_monitor()

    def show_popup(self, message):
        # ShowBalloon is for windows only. If support for other platforms
        # needed, uncomment popup lines and comment out ShowBalloon line.
        # popup = wx.adv.NotificationMessage('Feven Intel', message)
        # popup.Show(timeout=5)
        self.tb_icon.ShowBalloon('Feven Interl', message, 5000)
        if self.play_sound_chk.IsChecked():
            self.sound.Play(wx.adv.SOUND_ASYNC)

    def init_ui(self):
        self.sound = wx.adv.Sound('sound.wav')
        icon = wx.Icon()
        icon.CopyFromBitmap(wx.Bitmap("feven.ico", wx.BITMAP_TYPE_ANY))
        self.SetIcon(icon)
        self.tb_icon = wx.adv.TaskBarIcon()
        self.tb_icon.SetIcon(wx.Icon(wx.Bitmap("feven.ico")),
                             'Fuzzy Eve Notifier')
        self.tb_icon.Bind(wx.adv.EVT_TASKBAR_LEFT_DOWN, self.on_left_down)

        menubar = wx.MenuBar()

        file_menu = wx.Menu()
        file_menu_quit = file_menu.Append(wx.ID_EXIT, 'Quit',
                                          'Quit application')

        # options_menu = wx.Menu()
        # options_load_preset = options_menu.Append(
        #     1, 'Load Preset', 'Load Preset')
        # options_save_preset = options_menu.Append(
        #     2, 'Save Preset', 'Save Preset')
        # options_edit_preset = options_menu.Append(
        #     3, 'Edit Preset', 'Edit Preset')

        help_menu = wx.Menu()
        help_about = help_menu.Append(wx.ID_ABOUT, 'About', 'About')

        menubar.Append(file_menu, '&File')
        # menubar.Append(options_menu, '&Options')
        menubar.Append(help_menu, '&Help')
        self.SetMenuBar(menubar)

        self.Bind(wx.EVT_MENU, self.on_quit, file_menu_quit)
        self.Bind(wx.EVT_MENU, self.on_about, help_about)
        # self.Bind(wx.EVT_MENU, self.on_load_preset, options_load_preset)
        # self.Bind(wx.EVT_MENU, self.on_save_preset, options_save_preset)
        # self.Bind(wx.EVT_MENU, self.on_edit_preset, options_edit_preset)

        panel = wx.Panel(self)
        hbox = wx.BoxSizer(wx.HORIZONTAL)
        # Row based layout.
        # 3 rows with 4 columns, 5xp border horizontally and vertially.
        # buttons buttons button  checkbox
        # caption caption caption caption
        # input   input   input   input
        fgs = wx.FlexGridSizer(3, 4, 5, 5)

        font12 = wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL)

        # First row.
        # Create text captions for columns and assign font.
        directory_caption = wx.StaticText(panel, label="Directory")
        filename_caption = wx.StaticText(panel, label="Filename")
        message_caption = wx.StaticText(panel, label="Keyword")
        ignore_caption = wx.StaticText(panel, label="Ignore Keyword")
        directory_caption.SetFont(font12)
        filename_caption.SetFont(font12)
        message_caption.SetFont(font12)
        ignore_caption.SetFont(font12)

        # Second row.
        # First column.
        panel_row0_col0 = wx.Panel(panel)
        sizer_row0_col0 = wx.BoxSizer(wx.HORIZONTAL)

        self.start_btn = wx.Button(panel_row0_col0,
                                   label="Start",
                                   size=(90, 28))
        # Watcher has been started in __init__, so just disable start button.
        self.start_btn.Disable()
        self.stop_btn = wx.Button(panel_row0_col0, label="Stop", size=(90, 28))
        self.start_btn.Bind(wx.EVT_BUTTON, self.on_start)
        self.stop_btn.Bind(wx.EVT_BUTTON, self.on_stop)
        self.start_btn.SetFont(font12)
        self.stop_btn.SetFont(font12)

        sizer_row0_col0.Add(self.start_btn, 0, wx.ALL, 3)
        sizer_row0_col0.Add(self.stop_btn, 0, wx.ALL, 3)
        panel_row0_col0.SetSizer(sizer_row0_col0)

        # Third column.
        panel_row0_col1 = wx.Panel(panel)
        sizer_row0_col1 = wx.BoxSizer(wx.HORIZONTAL)

        apply_btn = wx.Button(panel_row0_col1,
                              label="Apply Changes",
                              size=(130, 28))
        apply_btn.Bind(wx.EVT_BUTTON, self.on_apply)
        apply_btn.SetFont(font12)

        sizer_row0_col1.Add(apply_btn, 1, wx.ALL, 3)
        panel_row0_col1.SetSizer(sizer_row0_col1)

        # Second column.
        panel_row0_col2 = wx.Panel(panel)
        sizer_row0_col2 = wx.BoxSizer(wx.HORIZONTAL)

        load_btn = wx.Button(panel_row0_col2, label="Load", size=(90, 28))
        save_btn = wx.Button(panel_row0_col2, label="Save", size=(90, 28))
        load_btn.Bind(wx.EVT_BUTTON, self.on_load)
        save_btn.Bind(wx.EVT_BUTTON, self.on_save)
        load_btn.SetFont(font12)
        save_btn.SetFont(font12)

        sizer_row0_col2.Add(load_btn, 1, wx.ALL, 3)
        sizer_row0_col2.Add(save_btn, 1, wx.ALL, 3)
        panel_row0_col2.SetSizer(sizer_row0_col2)

        # Fourth column.
        panel_row0_col3 = wx.Panel(panel)
        sizer_row0_col3 = wx.BoxSizer(wx.HORIZONTAL)

        self.play_sound_chk = wx.CheckBox(panel_row0_col3,
                                          label='Sound',
                                          size=(65, 28))
        # delay_spin = wx.SpinCtrl(panel_row0_col3, value="5", size=(20, 28))
        # delay_label = wx.StaticText(panel_row0_col3, label='Time',
        #                             size=(20, 28))
        self.play_sound_chk.Bind(wx.EVT_CHECKBOX, self.on_sound_chk)
        self.play_sound_chk.SetValue(True)
        # delay_spin.Bind(wx.EVT_SPINCTRL, self.on_spin)
        self.play_sound_chk.SetFont(font12)
        # delay_spin.SetFont(font12)
        # delay_label.SetFont(font12)

        sizer_row0_col3.Add(self.play_sound_chk, 1, wx.ALL, 3)
        # sizer_row0_col3.Add(delay_spin, 1, wx.ALL, 3)
        # sizer_row0_col3.Add(delay_label, 1, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 3)
        panel_row0_col3.SetSizer(sizer_row0_col3)

        # Third row.
        # Create text inputs and assign font.
        self.directory_text = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
        self.filename_text = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
        self.message_text = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
        self.ignore_text = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
        self.directory_text.SetFont(font12)
        self.filename_text.SetFont(font12)
        self.message_text.SetFont(font12)
        self.ignore_text.SetFont(font12)

        # Add captions, buttons, text inputs into grid.
        fgs.AddMany([
            panel_row0_col0, panel_row0_col2, panel_row0_col1, panel_row0_col3,
            directory_caption, filename_caption, message_caption,
            ignore_caption, (self.directory_text, 1, wx.EXPAND),
            (self.filename_text, 1, wx.EXPAND),
            (self.message_text, 1, wx.EXPAND), (self.ignore_text, 1, wx.EXPAND)
        ])

        # Last row and all columns are growable to fill empty space.
        fgs.AddGrowableRow(2, 1)
        # fgs.AddGrowableCol(0, 1)
        # fgs.AddGrowableCol(1, 1)
        fgs.AddGrowableCol(2, 1)
        fgs.AddGrowableCol(3, 1)
        hbox.Add(fgs, proportion=1, flag=wx.ALL | wx.EXPAND, border=5)
        panel.SetSizer(hbox)

    def on_exit(self, e):
        self.tb_icon.RemoveIcon()
        self.watcher.stop_monitor()
        # For unknown reasons MainThread does not stop and process does not
        # finish. Use explicit exit.
        sys.exit(0)

    def on_quit(self, e):
        self.Close()

    def on_left_down(self, e):
        self.Show(True)
        self.SetFocus()
        self.Raise()

    def on_about(self, e):
        pass

    def on_load(self, e):
        openFileDialog = wx.FileDialog(self, "Open Feven file", ".\\presets",
                                       "", "Feven files|*.fen",
                                       wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
        if openFileDialog.ShowModal() == wx.ID_CANCEL:
            return
        with open(openFileDialog.GetPath(), 'r') as file:
            data = json.load(file)
            self.directory_text.SetValue(data.get('directories', ''))
            self.filename_text.SetValue(data.get('files', ''))
            self.message_text.SetValue(data.get('keywords', ''))
            self.ignore_text.SetValue(data.get('ignore', ''))
            self.on_apply(None)

    def on_save(self, e):
        saveFileDialog = wx.FileDialog(self, "Save XYZ file", ".\\presets", "",
                                       "Feven files|*.fen",
                                       wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
        if saveFileDialog.ShowModal() == wx.ID_CANCEL:
            return
        with open(saveFileDialog.GetPath(), 'w+') as file:
            data = {
                'directories': self.directory_text.GetValue(),
                'files': self.filename_text.GetValue(),
                'keywords': self.message_text.GetValue(),
                'ignore': self.ignore_text.GetValue()
            }
            json.dump(data, file)

    def on_apply(self, e):
        paths = self.directory_text.GetValue().strip().split('\n')
        if not paths:
            return
        filenames = self.filename_text.GetValue().strip().split('\n')
        if not filenames:
            return
        keywords = self.message_text.GetValue().strip().split('\n')
        ignore = self.ignore_text.GetValue().strip().split('\n')
        self.watcher.update(paths, filenames, keywords, ignore)

    def on_start(self, e):
        self.watcher.run_monitor()
        self.start_btn.Disable()
        self.stop_btn.Enable()

    def on_stop(self, e):
        self.watcher.stop_monitor()
        self.stop_btn.Disable()
        self.start_btn.Enable()

    def on_sound_chk(self, e):
        pass

    def on_spin(self, e):
        pass
コード例 #2
0
class WatcherTestCase(unittest.TestCase):
    def callback(self, message):
        self.message = message
        return message

    def setUp(self):
        self.watcher = Watcher(self.callback)
        self.message = ''

    def test_callback(self):
        self.assertEqual(self.watcher.callback, self.callback,
                         'watcher.callback != callback')
        message = 'test message'
        self.watcher.callback(message)
        self.assertEqual(message, self.message,
                         'callback didn\'t return same message')

    def test_scan_directories_no_match(self):
        self.watcher.directories = list()
        self.watcher.files = list()
        self.watcher._scan_directories()
        self.assertFalse(self.watcher._scan_results,
                         '_scan_results should be empty')

    def test_scan_directories_match(self):
        self.watcher.directories = ['.', 'tests']
        self.watcher.files = ['txt']
        self.watcher._scan_directories()
        self.assertTrue(self.watcher._scan_results,
                        '_scan_results should not be empty')
        self.assertIn('tests\\ascii_encoded.txt',
                      self.watcher._scan_results.keys())
        self.assertIn('tests\\utf-16_encoded.txt',
                      self.watcher._scan_results.keys())

    def test_scan_files_no_match(self):
        self.message = ''
        self.watcher.directories = ['.', 'tests']
        self.watcher.files = ['txt']
        self.watcher._scan_directories()
        self.assertTrue(self.watcher._scan_results, 'missing scan results')
        self.watcher._scan_files()
        self.assertEqual(self.message, '',
                         'message should not have been modified')

    def test_scan_files_match(self):
        self.message = ''
        self.watcher.directories = ['.', 'tests']
        self.watcher.files = ['txt']
        self.watcher._scan_directories()
        self.assertTrue(self.watcher._scan_results, 'missing scan results')
        self.assertIn('tests\\ascii_encoded.txt',
                      self.watcher._scan_results.keys())
        with open('tests/ascii_encoded.txt', 'a') as file:
            file.write('extra line')
        self.watcher._scan_files()
        self.assertEqual(self.message, 'extra line',
                         'message should have been modified')

    def test_stop_monitor(self):
        thread = StoppableThread(None, None)
        self.watcher._monitor_thread = thread
        self.watcher._scan_thread = thread
        thread.start()
        self.assertTrue(self.watcher._monitor_thread.isAlive(),
                        'thread should be alive')
        self.assertTrue(self.watcher._scan_thread.isAlive(),
                        'thread should be alive')
        self.watcher.stop_monitor()
        self.assertFalse(self.watcher._monitor_thread.isAlive(),
                         'thread should not be alive')
        self.assertFalse(self.watcher._scan_thread.isAlive(),
                         'thread should not be alive')