From b8b0182cc38bd7c8eb6b6a6811b0052d525d9a30 Mon Sep 17 00:00:00 2001 From: Thykof Date: Fri, 18 Mar 2016 19:56:04 +0100 Subject: [PATCH 01/22] Remove requirements --- requirements.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index c95cfcb..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -cx_Freeze From d6d24370c2fb81c0b50ebb4f4d49a60773debd2e Mon Sep 17 00:00:00 2001 From: Thykof Date: Sat, 19 Mar 2016 17:09:53 +0100 Subject: [PATCH 02/22] Create interface --- docs/index.rst | 6 ++-- {smw_core => interface}/__init__.py | 0 interface/interface.py | 54 +++++++++++++++++++++++++++++ interface/interface.ui | 26 ++++++++++++++ interface/menu.py | 54 +++++++++++++++++++++++++++++ interface/tools.py | 16 +++++++++ main.py | 12 ++++--- tests/test_conf.py | 3 +- tests/test_mod.py | 4 ++- tests/test_watcher.py | 4 ++- watcher/__init__.py | 0 {smw_core => watcher}/conf.py | 1 + {smw_core => watcher}/data.py | 1 + {smw_core => watcher}/mod.py | 2 ++ {smw_core => watcher}/watcher.py | 46 ++++++++++++------------ 15 files changed, 195 insertions(+), 34 deletions(-) rename {smw_core => interface}/__init__.py (100%) create mode 100644 interface/interface.py create mode 100644 interface/interface.ui create mode 100644 interface/menu.py create mode 100644 interface/tools.py create mode 100644 watcher/__init__.py rename {smw_core => watcher}/conf.py (99%) rename {smw_core => watcher}/data.py (92%) rename {smw_core => watcher}/mod.py (97%) rename {smw_core => watcher}/watcher.py (78%) diff --git a/docs/index.rst b/docs/index.rst index 009df80..c285663 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -18,19 +18,19 @@ How it work Main body +++++++++ -.. automodule:: smw_core.watcher +.. automodule:: watcher.watcher :members: :undoc-members: Managing configurations +++++++++++++++++++++++ -.. automodule:: smw_core.conf +.. automodule:: watcher.conf :members: :undoc-members: A module for simple functions +++++++++++++++++++++++++++++ -.. automodule:: smw_core.mod +.. automodule:: watcher.mod :members: :undoc-members: diff --git a/smw_core/__init__.py b/interface/__init__.py similarity index 100% rename from smw_core/__init__.py rename to interface/__init__.py diff --git a/interface/interface.py b/interface/interface.py new file mode 100644 index 0000000..2d566d8 --- /dev/null +++ b/interface/interface.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/python3 + +from gi.repository import Gtk +from threading import Timer + +from .menu import create_menus +from .tools import about + +class Interface(Gtk.Window): + def __init__(self): + Gtk.Window.__init__(self, title='SafeMyWork 1.0') + self.set_default_size(800, 400) + self.connect('destroy', Gtk.main_quit) + + grid = Gtk.Grid() + self.add(grid) + + menus = create_menus(self) + grid.add(menus[0]) + grid.attach(menus[1], 0, 0, 1, 1) + + def set_watcher(self, watcher): + self.watcher = watcher + + def run(self): + self.show_all() + Gtk.main() + + def start_watching(self, *args): + self.watcher.watch() + self.thread = Timer(self.watcher.config['time_delta'], self.start_watching) + self.thread.start() + + def stop_watching(self, *args): + self.thread.cancel() + + def add_dir(self, *args): + pass + + def show_saved(self, *args): + pass + + def quit(self, *args): + Gtk.main_quit() + + def settings(self, *args): + pass + + def check_now(self, *args): + self.watcher.watch() + + def about(self, *args): + about() diff --git a/interface/interface.ui b/interface/interface.ui new file mode 100644 index 0000000..7d08555 --- /dev/null +++ b/interface/interface.ui @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface/menu.py b/interface/menu.py new file mode 100644 index 0000000..b9da72c --- /dev/null +++ b/interface/menu.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/python3 + +from gi.repository import Gtk + +def create_menus(self): + action_group = Gtk.ActionGroup(name='menu') + + action_FileMenu = Gtk.Action(name="FileMenu", label="Fichier") + action_group.add_action(action_FileMenu) + + action_Settings = Gtk.Action(name='Settings', label='Préférences') + action_Settings.connect('activate', self.settings) + action_group.add_action(action_Settings) + + action_AddFolder = Gtk.Action(name='AddFolder', label='Ajouter un dossier') + action_AddFolder.connect('activate', self.add_dir) + action_group.add_action(action_AddFolder) + + action_Quit = Gtk.Action(name='Quit', label='Quitter') + action_Quit.connect('activate', self.quit) + action_group.add_action(action_Quit) + + action_ActionMenu = Gtk.Action(name="ActionMenu", label="Action") + action_group.add_action(action_ActionMenu) + + action_Start = Gtk.Action(name='Start', label='Démmarer le scan') + action_Start.connect('activate', self.start_watching) + action_group.add_action(action_Start) + + action_Stop = Gtk.Action(name='Stop', label='Arrêter le scan') + action_Stop.connect('activate', self.stop_watching) + action_group.add_action(action_Stop) + + action_CheckNow = Gtk.Action(name='CheckNow', label='Scanner maintenant') + action_CheckNow.connect('activate', self.check_now) + action_group.add_action(action_CheckNow) + + action_OpenSaved = Gtk.Action(name='OpenSaved', label='Afficher les fichiers sauvegardés') + action_OpenSaved.connect('activate', self.show_saved) + action_group.add_action(action_OpenSaved) + + action_HelpMenu = Gtk.Action(name="HelpMenu", label="Aide") + action_group.add_action(action_HelpMenu) + + action_About = Gtk.Action(name='About', label='À propos') + action_About.connect('activate', self.about) + action_group.add_action(action_About) + + uimanager = Gtk.UIManager() + uimanager.add_ui_from_file('interface/interface.ui') + uimanager.insert_action_group(action_group) + + return uimanager.get_widget("/MenuBar"), uimanager.get_widget("/Toolbar") diff --git a/interface/tools.py b/interface/tools.py new file mode 100644 index 0000000..faef9b5 --- /dev/null +++ b/interface/tools.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/python3 + +from gi.repository import Gtk + +def about(): + dialog = Gtk.AboutDialog() + dialog.set_program_name('SafeMyWork') + dialog.set_version('1.0') + dialog.set_website('https://github.com/Thykof/SafeMyWork') + dialog.set_authors(['Nathan Seva']) + dialog.set_comments('Utilitaire SafeMyWork') + dialog.set_license('SafeMyWork est sous la license GNU GPL(v3). \n\n https://github.com/Thykof/SafeMyWork/blob/master/LICENSE') + + dialog.run() + dialog.destroy() diff --git a/main.py b/main.py index e3cb39b..d0f9c2e 100644 --- a/main.py +++ b/main.py @@ -1,11 +1,13 @@ # -*- coding: utf-8 -*- +#!/usr/bin/python3 import atexit import sys -from smw_core import conf -from smw_core import mod -from smw_core.watcher import Watcher +from watcher import conf +from watcher import mod +from watcher.watcher import Watcher +from interface.interface import Interface def quit_(config): mod.tell('Save config') @@ -22,4 +24,6 @@ def quit_(config): sys.exit() atexit.register(quit_, config) watcher = Watcher(config) - watcher.start() + root = Interface() + root.set_watcher(watcher) + root.run() diff --git a/tests/test_conf.py b/tests/test_conf.py index 3c0dc24..a701ea8 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- +#!/usr/bin/python3 -from smw_core import conf +from watcher import conf class BaseTestConf(object): def setup_method(self, test_method): diff --git a/tests/test_mod.py b/tests/test_mod.py index 9a494da..79bcc1f 100644 --- a/tests/test_mod.py +++ b/tests/test_mod.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- +#!/usr/bin/python3 -from smw_core import mod from os import path +from watcher import mod + class BaseTestMod(object): def setup_method(self, test_method): pass diff --git a/tests/test_watcher.py b/tests/test_watcher.py index cf13b33..45ba3b1 100644 --- a/tests/test_watcher.py +++ b/tests/test_watcher.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- +#!/usr/bin/python3 -from smw_core import watcher from os import path, mkdir +from watcher import watcher + class BaseTestWatcher(object): def setup_method(self, test_method): self.default_config = { diff --git a/watcher/__init__.py b/watcher/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/smw_core/conf.py b/watcher/conf.py similarity index 99% rename from smw_core/conf.py rename to watcher/conf.py index 6b5f105..c985a83 100644 --- a/smw_core/conf.py +++ b/watcher/conf.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +#!/usr/bin/python3 """Monitoring configuration variables.""" diff --git a/smw_core/data.py b/watcher/data.py similarity index 92% rename from smw_core/data.py rename to watcher/data.py index fc5b995..c83b627 100644 --- a/smw_core/data.py +++ b/watcher/data.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +#!/usr/bin/python3 CONF_FILE = 'SMW_conf_file.ini' DEFAULT_CONFIG = { diff --git a/smw_core/mod.py b/watcher/mod.py similarity index 97% rename from smw_core/mod.py rename to watcher/mod.py index 4000e03..721880d 100644 --- a/smw_core/mod.py +++ b/watcher/mod.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- +#!/usr/bin/python3 """Define some fonctions.""" from os import path, mkdir +from time import sleep, time def tell(message, target='output.log'): """Tell to user a message. diff --git a/smw_core/watcher.py b/watcher/watcher.py similarity index 78% rename from smw_core/watcher.py rename to watcher/watcher.py index d0848f4..fc00d04 100644 --- a/smw_core/watcher.py +++ b/watcher/watcher.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- +#!/usr/bin/python3 from os import path, walk, stat, mkdir from time import sleep import shutil -from smw_core import mod +from .mod import tell, create_archive_dir, combine_list class Watcher(object): """A class that manage safing files.""" @@ -14,9 +15,9 @@ def __init__(self, config): self.delicate_dir = config['delicate_dirs'] # Directory watch self.archive_dir = config['archive_dir'] - mod.create_archive_dir(self.archive_dir, self.delicate_dir) + create_archive_dir(self.archive_dir, self.delicate_dir) - def start(self): + def watch(self): """Start **watching**. - list unsaved files @@ -25,20 +26,17 @@ def start(self): - archive the new files - wait for the *time_delta* setting """ - while True: - mod.tell('===WATCHING===') - for delicate_dir in self.delicate_dir: - unsaved_files = self.list_files(delicate_dir) - saved_files = self.list_files(path.join(self.archive_dir, path.basename(delicate_dir))) - files_to_save = self.compare_files(unsaved_files, saved_files, delicate_dir) - if len(files_to_save) > 0: - self.create_safe_dirs(delicate_dir) - for filename in files_to_save: - archived_file = self.archive_file(filename, delicate_dir) - mod.tell('Archived: ' + archived_file) - - mod.tell('Done') - sleep(self.config['time_delta']) + tell('===WATCHING===') + for delicate_dir in self.delicate_dir: + unsaved_files = self.list_files(delicate_dir) + saved_files = self.list_files(path.join(self.archive_dir, path.basename(delicate_dir))) + files_to_save = self.compare_files(unsaved_files, saved_files, delicate_dir) + if len(files_to_save) > 0: + self.create_safe_dirs(delicate_dir) + for filename in files_to_save: + archived_file = self.archive_file(filename, delicate_dir) + tell('Archived: ' + archived_file) + tell('Done') def list_files(self, path_dir): """List all files in the given *path_dir*. @@ -110,25 +108,25 @@ def compare_files(self, unsaved_files, saved_files, delicate_dir): for unsaved_file in unsaved_files: if unsaved_file not in saved_files: if self.filter_files(unsaved_file): - mod.tell('Add: ' + unsaved_file) + tell('Add: ' + unsaved_file) files_to_save.append(unsaved_file) else: - mod.tell('Exclude: ' + unsaved_file) + tell('Exclude: ' + unsaved_file) - list_files = mod.combine_list(unsaved_files, saved_files) + list_files = combine_list(unsaved_files, saved_files) for filename in list_files: saved_file_stat = stat(path.join(self.archive_dir, delicate_dir, filename)) unsaved_file_stat = stat(path.join(delicate_dir, filename)) if saved_file_stat.st_mtime < unsaved_file_stat.st_mtime: if self.filter_files(filename): - mod.tell('Update: ' + filename) + tell('Update: ' + filename) files_to_save.append(filename) else: - mod.tell('Exclude: ' + filename) + tell('Exclude: ' + filename) elif saved_file_stat.st_mtime > unsaved_file_stat.st_mtime: - mod.tell('Saved file have been modified !') + tell('Saved file have been modified !') else: - mod.tell('Skipping: ' + filename) + tell('Skipping: ' + filename) return files_to_save def create_safe_dirs(self, delicate_dir): From a629f85a79e2f8fc7a00bc9d40805873cad5954a Mon Sep 17 00:00:00 2001 From: Thykof Date: Sun, 20 Mar 2016 12:01:07 +0100 Subject: [PATCH 03/22] Improve interface --- interface/interface.py | 48 +++++++++++++++++++------- interface/{menu.py => menubar.py} | 10 ++---- interface/{interface.ui => menubar.ui} | 10 +----- watcher/mod.py | 1 - watcher/watcher.py | 5 ++- 5 files changed, 41 insertions(+), 33 deletions(-) rename interface/{menu.py => menubar.py} (82%) rename interface/{interface.ui => menubar.ui} (64%) diff --git a/interface/interface.py b/interface/interface.py index 2d566d8..b855b0b 100644 --- a/interface/interface.py +++ b/interface/interface.py @@ -4,21 +4,44 @@ from gi.repository import Gtk from threading import Timer -from .menu import create_menus +from .menubar import create_menus from .tools import about class Interface(Gtk.Window): def __init__(self): Gtk.Window.__init__(self, title='SafeMyWork 1.0') - self.set_default_size(800, 400) - self.connect('destroy', Gtk.main_quit) + self.set_position(Gtk.WindowPosition.CENTER) + self.connect('delete-event', self.quit_app) - grid = Gtk.Grid() - self.add(grid) + self.grid = Gtk.Grid(column_spacing=20, row_spacing=20) + self.add(self.grid) - menus = create_menus(self) - grid.add(menus[0]) - grid.attach(menus[1], 0, 0, 1, 1) + self.create_buttons() + self.grid.add(create_menus(self)) + + self.thread = None + + def create_buttons(self): + button_show_saved = Gtk.Button.new_with_label('Fichiers sauvés') + button_show_saved.connect('clicked', self.show_saved) + button_check_now = Gtk.Button.new_with_label('Scanner maintenant') + button_check_now.connect('clicked', self.check_now) + label_watch = Gtk.Label('Scan :') + switch_start = Gtk.Switch() + switch_start.connect('notify::active', self.on_switch_activated) + switch_start.set_active(False) + + self.grid.attach(button_show_saved, 0, 0, 1, 1) + self.grid.attach(button_check_now, 1, 0 , 1, 1) + self.grid.attach(label_watch, 0, 1 , 1, 1) + self.grid.attach(switch_start, 1, 1 , 1 , 1) + switch_start.do_grab_focus(switch_start) + + def on_switch_activated(self, switch, *args): + if switch.get_active(): + self.start_watching() + else: + self.stop_watching() def set_watcher(self, watcher): self.watcher = watcher @@ -33,16 +56,15 @@ def start_watching(self, *args): self.thread.start() def stop_watching(self, *args): - self.thread.cancel() - - def add_dir(self, *args): - pass + if self.thread is not None: + self.thread.cancel() def show_saved(self, *args): pass - def quit(self, *args): + def quit_app(self, *args): Gtk.main_quit() + self.stop_watching() def settings(self, *args): pass diff --git a/interface/menu.py b/interface/menubar.py similarity index 82% rename from interface/menu.py rename to interface/menubar.py index b9da72c..7fb2e65 100644 --- a/interface/menu.py +++ b/interface/menubar.py @@ -13,12 +13,8 @@ def create_menus(self): action_Settings.connect('activate', self.settings) action_group.add_action(action_Settings) - action_AddFolder = Gtk.Action(name='AddFolder', label='Ajouter un dossier') - action_AddFolder.connect('activate', self.add_dir) - action_group.add_action(action_AddFolder) - action_Quit = Gtk.Action(name='Quit', label='Quitter') - action_Quit.connect('activate', self.quit) + action_Quit.connect('activate', self.quit_app) action_group.add_action(action_Quit) action_ActionMenu = Gtk.Action(name="ActionMenu", label="Action") @@ -48,7 +44,7 @@ def create_menus(self): action_group.add_action(action_About) uimanager = Gtk.UIManager() - uimanager.add_ui_from_file('interface/interface.ui') + uimanager.add_ui_from_file('interface/menubar.ui') uimanager.insert_action_group(action_group) - return uimanager.get_widget("/MenuBar"), uimanager.get_widget("/Toolbar") + return uimanager.get_widget("/MenuBar") diff --git a/interface/interface.ui b/interface/menubar.ui similarity index 64% rename from interface/interface.ui rename to interface/menubar.ui index 7d08555..6fe5a20 100644 --- a/interface/interface.ui +++ b/interface/menubar.ui @@ -2,25 +2,17 @@ + - - - - - - - - - diff --git a/watcher/mod.py b/watcher/mod.py index 721880d..5b93268 100644 --- a/watcher/mod.py +++ b/watcher/mod.py @@ -4,7 +4,6 @@ """Define some fonctions.""" from os import path, mkdir -from time import sleep, time def tell(message, target='output.log'): """Tell to user a message. diff --git a/watcher/watcher.py b/watcher/watcher.py index fc00d04..bb73624 100644 --- a/watcher/watcher.py +++ b/watcher/watcher.py @@ -12,10 +12,9 @@ class Watcher(object): def __init__(self, config): super(Watcher, self).__init__() self.config = config - self.delicate_dir = config['delicate_dirs'] # Directory watch self.archive_dir = config['archive_dir'] - create_archive_dir(self.archive_dir, self.delicate_dir) + create_archive_dir(self.archive_dir, self.config['delicate_dirs']) def watch(self): """Start **watching**. @@ -27,7 +26,7 @@ def watch(self): - wait for the *time_delta* setting """ tell('===WATCHING===') - for delicate_dir in self.delicate_dir: + for delicate_dir in self.config['delicate_dirs']: unsaved_files = self.list_files(delicate_dir) saved_files = self.list_files(path.join(self.archive_dir, path.basename(delicate_dir))) files_to_save = self.compare_files(unsaved_files, saved_files, delicate_dir) From 74d7dbea663bdebe485b72e2693350e0ec9d0f5b Mon Sep 17 00:00:00 2001 From: Thykof Date: Sun, 20 Mar 2016 12:44:15 +0100 Subject: [PATCH 04/22] Improve get config, reorganize interface initialization --- interface/interface.py | 53 +++++++++++++++++------------------------- interface/tools.py | 19 +++++++++++++++ main.py | 16 +------------ watcher/conf.py | 3 +-- watcher/watcher.py | 12 ++++------ 5 files changed, 47 insertions(+), 56 deletions(-) diff --git a/interface/interface.py b/interface/interface.py index b855b0b..cb0b1f9 100644 --- a/interface/interface.py +++ b/interface/interface.py @@ -5,37 +5,37 @@ from threading import Timer from .menubar import create_menus -from .tools import about +from .tools import about, initialize_interface +import watcher +from watcher.watcher import Watcher class Interface(Gtk.Window): - def __init__(self): + def __init__(self, config): Gtk.Window.__init__(self, title='SafeMyWork 1.0') self.set_position(Gtk.WindowPosition.CENTER) self.connect('delete-event', self.quit_app) - self.grid = Gtk.Grid(column_spacing=20, row_spacing=20) - self.add(self.grid) - - self.create_buttons() + self.grid = initialize_interface(self) self.grid.add(create_menus(self)) + self.add(self.grid) + self.thread = None + self.config = config + self.watcher = Watcher(config) - def create_buttons(self): - button_show_saved = Gtk.Button.new_with_label('Fichiers sauvés') - button_show_saved.connect('clicked', self.show_saved) - button_check_now = Gtk.Button.new_with_label('Scanner maintenant') - button_check_now.connect('clicked', self.check_now) - label_watch = Gtk.Label('Scan :') - switch_start = Gtk.Switch() - switch_start.connect('notify::active', self.on_switch_activated) - switch_start.set_active(False) - - self.grid.attach(button_show_saved, 0, 0, 1, 1) - self.grid.attach(button_check_now, 1, 0 , 1, 1) - self.grid.attach(label_watch, 0, 1 , 1, 1) - self.grid.attach(switch_start, 1, 1 , 1 , 1) - switch_start.do_grab_focus(switch_start) + def run(self): + self.show_all() + Gtk.main() + + def quit_app(self, *args): + Gtk.main_quit() + self.save_config(self.config) + self.stop_watching() + + def save_config(self, config=watcher.data.DEFAULT_CONFIG): + watcher.mod.tell('Save config') + watcher.conf.save_config(config) def on_switch_activated(self, switch, *args): if switch.get_active(): @@ -43,13 +43,6 @@ def on_switch_activated(self, switch, *args): else: self.stop_watching() - def set_watcher(self, watcher): - self.watcher = watcher - - def run(self): - self.show_all() - Gtk.main() - def start_watching(self, *args): self.watcher.watch() self.thread = Timer(self.watcher.config['time_delta'], self.start_watching) @@ -62,10 +55,6 @@ def stop_watching(self, *args): def show_saved(self, *args): pass - def quit_app(self, *args): - Gtk.main_quit() - self.stop_watching() - def settings(self, *args): pass diff --git a/interface/tools.py b/interface/tools.py index faef9b5..05f7da6 100644 --- a/interface/tools.py +++ b/interface/tools.py @@ -14,3 +14,22 @@ def about(): dialog.run() dialog.destroy() + +def initialize_interface(self): + grid = Gtk.Grid(column_spacing=20, row_spacing=20) + button_show_saved = Gtk.Button.new_with_label('Fichiers sauvés') + button_show_saved.connect('clicked', self.show_saved) + button_check_now = Gtk.Button.new_with_label('Scanner maintenant') + button_check_now.connect('clicked', self.check_now) + label_watch = Gtk.Label('Scan :') + switch_start = Gtk.Switch() + switch_start.connect('notify::active', self.on_switch_activated) + switch_start.set_active(False) + + grid.attach(button_show_saved, 0, 0, 1, 1) + grid.attach(button_check_now, 1, 0 , 1, 1) + grid.attach(label_watch, 0, 1 , 1, 1) + grid.attach(switch_start, 1, 1 , 1 , 1) + switch_start.do_grab_focus(switch_start) + + return grid diff --git a/main.py b/main.py index d0f9c2e..6fbf4a7 100644 --- a/main.py +++ b/main.py @@ -1,29 +1,15 @@ # -*- coding: utf-8 -*- #!/usr/bin/python3 -import atexit import sys from watcher import conf from watcher import mod -from watcher.watcher import Watcher from interface.interface import Interface -def quit_(config): - mod.tell('Save config') - conf.save_config(config) - if __name__ == '__main__': myfile = open('stderr.log', 'a') sys.stderr = myfile - config = conf.get_config() - if config is None: - mod.tell('No delicate directory') - mod.tell('Save config') - sys.exit() - atexit.register(quit_, config) - watcher = Watcher(config) - root = Interface() - root.set_watcher(watcher) + root = Interface(config) root.run() diff --git a/watcher/conf.py b/watcher/conf.py index c985a83..a95fe37 100644 --- a/watcher/conf.py +++ b/watcher/conf.py @@ -80,6 +80,5 @@ def get_config(conf_file=CONF_FILE): delicate_dirs = get_dir_from_argv() config['delicate_dirs'].extend(delicate_dirs) if config['delicate_dirs'] == []: - return None - + return dict() return config diff --git a/watcher/watcher.py b/watcher/watcher.py index bb73624..f66466e 100644 --- a/watcher/watcher.py +++ b/watcher/watcher.py @@ -12,9 +12,6 @@ class Watcher(object): def __init__(self, config): super(Watcher, self).__init__() self.config = config - self.archive_dir = config['archive_dir'] - - create_archive_dir(self.archive_dir, self.config['delicate_dirs']) def watch(self): """Start **watching**. @@ -25,10 +22,11 @@ def watch(self): - archive the new files - wait for the *time_delta* setting """ + create_archive_dir(self.config['archive_dir'], self.config['delicate_dirs']) tell('===WATCHING===') for delicate_dir in self.config['delicate_dirs']: unsaved_files = self.list_files(delicate_dir) - saved_files = self.list_files(path.join(self.archive_dir, path.basename(delicate_dir))) + saved_files = self.list_files(path.join(self.config['archive_dir'], path.basename(delicate_dir))) files_to_save = self.compare_files(unsaved_files, saved_files, delicate_dir) if len(files_to_save) > 0: self.create_safe_dirs(delicate_dir) @@ -114,7 +112,7 @@ def compare_files(self, unsaved_files, saved_files, delicate_dir): list_files = combine_list(unsaved_files, saved_files) for filename in list_files: - saved_file_stat = stat(path.join(self.archive_dir, delicate_dir, filename)) + saved_file_stat = stat(path.join(self.config['archive_dir'], delicate_dir, filename)) unsaved_file_stat = stat(path.join(delicate_dir, filename)) if saved_file_stat.st_mtime < unsaved_file_stat.st_mtime: if self.filter_files(filename): @@ -136,7 +134,7 @@ def create_safe_dirs(self, delicate_dir): """ dirs = self.list_dirs(delicate_dir) for directory in dirs: - path_dir = path.join(self.archive_dir, path.basename(delicate_dir), directory) + path_dir = path.join(self.config['archive_dir'], path.basename(delicate_dir), directory) if not path.exists(path_dir): mkdir(path_dir) @@ -149,6 +147,6 @@ def archive_file(self, filename, delicate_dir): :type delicate_dir: ``str`` """ src = path.join(delicate_dir, filename) - dst = path.join(self.archive_dir, path.basename(delicate_dir), filename) + dst = path.join(self.config['archive_dir'], path.basename(delicate_dir), filename) archived_file = shutil.copy2(src, dst) return archived_file From 210ab3490996c489502b18ba9775e19be2a727f5 Mon Sep 17 00:00:00 2001 From: Thykof Date: Wed, 23 Mar 2016 16:20:38 +0100 Subject: [PATCH 05/22] improve interface --- interface/dialog.py | 17 ++++++++++ interface/interface.py | 71 ++++++++++++++++++++++++++++++++++-------- interface/menubar.py | 2 +- interface/tools.py | 61 +++++++++++++++++++++++++++--------- tests/test_conf.py | 2 +- tests/test_watcher.py | 2 +- watcher/conf.py | 12 +++---- watcher/data.py | 2 +- watcher/mod.py | 8 ++--- watcher/watcher.py | 50 ++++++++++++++--------------- 10 files changed, 160 insertions(+), 67 deletions(-) create mode 100644 interface/dialog.py diff --git a/interface/dialog.py b/interface/dialog.py new file mode 100644 index 0000000..5563291 --- /dev/null +++ b/interface/dialog.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/python3 + +from gi.repository import Gtk + +def show_watched_dialog(self): + dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO, + Gtk.ButtonsType.OK, "Dossiers surveillés") + dialog.format_secondary_text(str(self.config)) + dialog.run() + dialog.destroy() + +def del_dir_dialog(self, directory): + dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, + Gtk.ButtonsType.YES_NO, "Ne plus surveiller " + directory + " ?") + response = dialog.run() + return response == Gtk.ResponseType.YES, dialog diff --git a/interface/interface.py b/interface/interface.py index cb0b1f9..5c13da7 100644 --- a/interface/interface.py +++ b/interface/interface.py @@ -2,10 +2,12 @@ #!/usr/bin/python3 from gi.repository import Gtk -from threading import Timer +import threading +from os import path from .menubar import create_menus from .tools import about, initialize_interface +from .dialog import show_watched_dialog, del_dir_dialog import watcher from watcher.watcher import Watcher @@ -13,17 +15,26 @@ class Interface(Gtk.Window): def __init__(self, config): Gtk.Window.__init__(self, title='SafeMyWork 1.0') self.set_position(Gtk.WindowPosition.CENTER) + self.set_border_width(5) self.connect('delete-event', self.quit_app) - self.grid = initialize_interface(self) + initialize_interface(self) + self.switch_start.do_grab_focus(self.switch_start) self.grid.add(create_menus(self)) - self.add(self.grid) self.thread = None self.config = config self.watcher = Watcher(config) + self.initialize_config() + + def initialize_config(self): + for watched_dir in self.config['watched_dirs']: + self.watched_list.append_text(watched_dir) + for ext in self.config['exclude_ext']: + self.ext_list.append_text(ext) + def run(self): self.show_all() Gtk.main() @@ -37,29 +48,63 @@ def save_config(self, config=watcher.data.DEFAULT_CONFIG): watcher.mod.tell('Save config') watcher.conf.save_config(config) - def on_switch_activated(self, switch, *args): - if switch.get_active(): - self.start_watching() - else: - self.stop_watching() - def start_watching(self, *args): + if not self.switch_start.get_active(): + self.switch_start.set_active(True) + + def watching(self, *args): + self.text.set_text('Scan en cours') + self.spinner.start() self.watcher.watch() - self.thread = Timer(self.watcher.config['time_delta'], self.start_watching) + self.spinner.stop() + self.thread = threading.Timer(self.watcher.config['time_delta'], self.watching) self.thread.start() - def stop_watching(self, *args): + def stop_watching(self, action=None): + if self.switch_start.get_active(): + self.switch_start.set_active(False) + + def cancel_watching(self): + self.text.set_text('Scan annulé') if self.thread is not None: self.thread.cancel() def show_saved(self, *args): pass + def show_watched(self, *args): + show_watched_dialog(self) + def settings(self, *args): - pass + self.show_watched() - def check_now(self, *args): + def watch_now(self, *args): + self.spinner.start() self.watcher.watch() + self.spinner.stop() + + def add_watched_dir(self, button): + tree_iter = self.watched_list.get_active_iter() + if tree_iter is None: + new_dir = self.watched_list.get_child().get_text() + if new_dir != '' and new_dir not in self.config['watched_dirs'] and path.exists(new_dir): + print("add dir: " + new_dir) + self.watched_list.append_text(new_dir) + self.config['watched_dirs'].append(new_dir) + self.text.set_text('Dossier ajouté') + + def del_watched_dir(self, button): + tree_iter = self.watched_list.get_active_iter() + if tree_iter is not None: + model = self.watched_list.get_model() + directory = model[tree_iter][0] + must_del, dialog = del_dir_dialog(self, directory) + dialog.destroy() + if must_del: + print("delete dir :" + directory) + self.config['watched_dirs'].remove(directory) + self.watched_list.remove(int(self.watched_list.get_active())) + self.text.set_text('Dossier supprimé') def about(self, *args): about() diff --git a/interface/menubar.py b/interface/menubar.py index 7fb2e65..ac2e45a 100644 --- a/interface/menubar.py +++ b/interface/menubar.py @@ -29,7 +29,7 @@ def create_menus(self): action_group.add_action(action_Stop) action_CheckNow = Gtk.Action(name='CheckNow', label='Scanner maintenant') - action_CheckNow.connect('activate', self.check_now) + action_CheckNow.connect('activate', self.watch_now) action_group.add_action(action_CheckNow) action_OpenSaved = Gtk.Action(name='OpenSaved', label='Afficher les fichiers sauvegardés') diff --git a/interface/tools.py b/interface/tools.py index 05f7da6..c260bf1 100644 --- a/interface/tools.py +++ b/interface/tools.py @@ -16,20 +16,53 @@ def about(): dialog.destroy() def initialize_interface(self): - grid = Gtk.Grid(column_spacing=20, row_spacing=20) + self.grid = Gtk.Grid(column_spacing=5, row_spacing=5) + self.text = Gtk.Label('En attente...') + # Toolbar: button_show_saved = Gtk.Button.new_with_label('Fichiers sauvés') button_show_saved.connect('clicked', self.show_saved) button_check_now = Gtk.Button.new_with_label('Scanner maintenant') - button_check_now.connect('clicked', self.check_now) - label_watch = Gtk.Label('Scan :') - switch_start = Gtk.Switch() - switch_start.connect('notify::active', self.on_switch_activated) - switch_start.set_active(False) - - grid.attach(button_show_saved, 0, 0, 1, 1) - grid.attach(button_check_now, 1, 0 , 1, 1) - grid.attach(label_watch, 0, 1 , 1, 1) - grid.attach(switch_start, 1, 1 , 1 , 1) - switch_start.do_grab_focus(switch_start) - - return grid + button_check_now.connect('clicked', self.watch_now) + # Watching: + self.switch_start = Gtk.Switch() + self.switch_start.connect('notify::active', on_switch_activated, self) + self.switch_start.set_active(False) + # Watched dirs: + self.watched_list = Gtk.ComboBoxText.new_with_entry() + self.watched_list.connect('changed', on_changed_watched) + button_add_watched = Gtk.Button.new_with_label('Ajouter') + button_add_watched.connect('clicked', self.add_watched_dir) + button_del_watched = Gtk.Button.new_with_label('Supprimer') + button_del_watched.connect('clicked', self.del_watched_dir) + self.spinner = Gtk.Spinner() + + # pack: + hbox = Gtk.Box(spacing=6) + hbox.pack_start(self.text, True, True, 0) + hbox.pack_start(self.switch_start, True, True, 0) + hbox.pack_start(self.spinner, True, True, 0) + self.grid.attach(hbox, 0, 1, 2, 1) + + self.grid.attach(button_show_saved, 0, 0, 1, 1) + self.grid.attach(button_check_now, 1, 0 , 1, 1) + self.grid.attach(self.watched_list, 0, 2, 2, 1) + self.grid.attach(button_add_watched, 0, 3, 1, 1) + self.grid.attach(button_del_watched, 1, 3, 1, 1) + +def on_changed_ext(ext_list): + tree_iter = ext_list.get_active_iter() + if tree_iter != None: + model = ext_list.get_model() + print(model) + else: + entry = ext_list.get_child() + print("Entered: " + entry.get_text()) + +def on_changed_watched(watched_list): + pass + +def on_switch_activated(switch, active, self): + if switch.get_active(): + self.watching() + else: + self.cancel_watching() diff --git a/tests/test_conf.py b/tests/test_conf.py index a701ea8..13cf4b6 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -8,7 +8,7 @@ def setup_method(self, test_method): self.default_config = { 'time_delta': 20, 'archive_dir': 'safe_docs', - 'delicate_dirs': ["a_delicate_dir/folderA"], + 'watched_dirs': ["a_delicate_dir/folderA"], 'exclude_dirs': ['a_delicate_dir/notthatfolder'], 'exclude_files': ['a_delicate_dir/notthatfile.txt'], 'exclude_ext': ['pdf', 'JSON'] diff --git a/tests/test_watcher.py b/tests/test_watcher.py index 45ba3b1..b85bbc8 100644 --- a/tests/test_watcher.py +++ b/tests/test_watcher.py @@ -10,7 +10,7 @@ def setup_method(self, test_method): self.default_config = { 'time_delta': 20, 'archive_dir': 'safe_docs', - 'delicate_dirs': ["a_delicate_dir/folderA"], + 'watched_dirs': ["a_delicate_dir/folderA"], 'exclude_dirs': ['a_delicate_dir/notthatfolder'], 'exclude_files': ['a_delicate_dir/notthatfile.txt'], 'exclude_ext': ['pdf', 'json'] diff --git a/watcher/conf.py b/watcher/conf.py index a95fe37..30ceb9a 100644 --- a/watcher/conf.py +++ b/watcher/conf.py @@ -54,11 +54,11 @@ def get_dir_from_argv(argv=None): if len(argv) == 1: return [] else: - delicate_dirs = list() + watched_dirs = list() for directory in argv[1:]: if path.exists(directory): - delicate_dirs.append(directory) - return delicate_dirs + watched_dirs.append(directory) + return watched_dirs def get_config(conf_file=CONF_FILE): """Manage getting settings. @@ -77,8 +77,6 @@ def get_config(conf_file=CONF_FILE): return None else: config = read_config(conf_file) - delicate_dirs = get_dir_from_argv() - config['delicate_dirs'].extend(delicate_dirs) - if config['delicate_dirs'] == []: - return dict() + watched_dirs = get_dir_from_argv() + config['watched_dirs'].extend(watched_dirs) return config diff --git a/watcher/data.py b/watcher/data.py index c83b627..c50fc46 100644 --- a/watcher/data.py +++ b/watcher/data.py @@ -5,7 +5,7 @@ DEFAULT_CONFIG = { 'time_delta': 600, 'archive_dir': 'safe_docs', - 'delicate_dirs': [], + 'watched_dirs': [], 'exclude_dirs': [], 'exclude_files': [], 'exclude_ext': [] diff --git a/watcher/mod.py b/watcher/mod.py index 5b93268..2f856b3 100644 --- a/watcher/mod.py +++ b/watcher/mod.py @@ -41,17 +41,17 @@ def combine_list(list1, list2): list3.append(value) return list3 -def create_archive_dir(archive_dir, delicate_dir): +def create_archive_dir(archive_dir, watched_dir): """Create all directories use for archiving. :param archive_dir: the archive directory :type archive_dir: ``str`` - :param delicate_dir: directories to watch - :type delicate_dir: ``list`` + :param watched_dir: directories to watch + :type watched_dir: ``list`` """ if not path.exists(archive_dir): mkdir(archive_dir) - for directory in delicate_dir: + for directory in watched_dir: dir_to_create = path.join(archive_dir, path.basename(directory)) if not path.exists(dir_to_create): mkdir(dir_to_create) diff --git a/watcher/watcher.py b/watcher/watcher.py index f66466e..52ecea6 100644 --- a/watcher/watcher.py +++ b/watcher/watcher.py @@ -22,16 +22,16 @@ def watch(self): - archive the new files - wait for the *time_delta* setting """ - create_archive_dir(self.config['archive_dir'], self.config['delicate_dirs']) + create_archive_dir(self.config['archive_dir'], self.config['watched_dirs']) tell('===WATCHING===') - for delicate_dir in self.config['delicate_dirs']: - unsaved_files = self.list_files(delicate_dir) - saved_files = self.list_files(path.join(self.config['archive_dir'], path.basename(delicate_dir))) - files_to_save = self.compare_files(unsaved_files, saved_files, delicate_dir) + for watched_dir in self.config['watched_dirs']: + unsaved_files = self.list_files(watched_dir) + saved_files = self.list_files(path.join(self.config['archive_dir'], path.basename(watched_dir))) + files_to_save = self.compare_files(unsaved_files, saved_files, watched_dir) if len(files_to_save) > 0: - self.create_safe_dirs(delicate_dir) + self.create_safe_dirs(watched_dir) for filename in files_to_save: - archived_file = self.archive_file(filename, delicate_dir) + archived_file = self.archive_file(filename, watched_dir) tell('Archived: ' + archived_file) tell('Done') @@ -60,9 +60,9 @@ def list_dirs(self, path_dir): list_dirs = list() for root, directories, files in walk(path_dir): for directory in directories: - delicate_dir = path.join(root, directory) + watched_dir = path.join(root, directory) position = len(path_dir) - list_dirs.append(delicate_dir[position+1:]) + list_dirs.append(watched_dir[position+1:]) return list_dirs def filter_files(self, filename): @@ -88,15 +88,15 @@ def filter_files(self, filename): else: return False - def compare_files(self, unsaved_files, saved_files, delicate_dir): + def compare_files(self, unsaved_files, saved_files, watched_dir): """List all files that need to be save. :param unsaved_files: the unsaved files :type unsaved_files: ``list`` :param saved_files: the files already saved :type saved_files: ``list`` - :param delicate_dir: the directory watching - :type delicate_dir: ``str`` + :param watched_dir: the directory watching + :type watched_dir: ``str`` :returns: the files need to ba save :rtype: ``list`` """ @@ -112,8 +112,8 @@ def compare_files(self, unsaved_files, saved_files, delicate_dir): list_files = combine_list(unsaved_files, saved_files) for filename in list_files: - saved_file_stat = stat(path.join(self.config['archive_dir'], delicate_dir, filename)) - unsaved_file_stat = stat(path.join(delicate_dir, filename)) + saved_file_stat = stat(path.join(self.config['archive_dir'], watched_dir, filename)) + unsaved_file_stat = stat(path.join(watched_dir, filename)) if saved_file_stat.st_mtime < unsaved_file_stat.st_mtime: if self.filter_files(filename): tell('Update: ' + filename) @@ -126,27 +126,27 @@ def compare_files(self, unsaved_files, saved_files, delicate_dir): tell('Skipping: ' + filename) return files_to_save - def create_safe_dirs(self, delicate_dir): - """Make all directories from *delicate_dir* in archive directory. + def create_safe_dirs(self, watched_dir): + """Make all directories from *watched_dir* in archive directory. - :param delicate_dir: the directory watching - :type delicate_dir: ``str`` + :param watched_dir: the directory watching + :type watched_dir: ``str`` """ - dirs = self.list_dirs(delicate_dir) + dirs = self.list_dirs(watched_dir) for directory in dirs: - path_dir = path.join(self.config['archive_dir'], path.basename(delicate_dir), directory) + path_dir = path.join(self.config['archive_dir'], path.basename(watched_dir), directory) if not path.exists(path_dir): mkdir(path_dir) - def archive_file(self, filename, delicate_dir): + def archive_file(self, filename, watched_dir): """Copy the *filename* in the archive directory. :param filename: filename of the file to save :type filename: ``str`` - :param delicate_dir: the directory watching - :type delicate_dir: ``str`` + :param watched_dir: the directory watching + :type watched_dir: ``str`` """ - src = path.join(delicate_dir, filename) - dst = path.join(self.config['archive_dir'], path.basename(delicate_dir), filename) + src = path.join(watched_dir, filename) + dst = path.join(self.config['archive_dir'], path.basename(watched_dir), filename) archived_file = shutil.copy2(src, dst) return archived_file From 91048562f4df9731aee54279e52e88db550638f9 Mon Sep 17 00:00:00 2001 From: Thykof Date: Thu, 24 Mar 2016 20:46:31 +0100 Subject: [PATCH 06/22] Show saved, class MainGrid --- interface/dialog.py | 2 +- interface/interface.py | 73 ++++++++++++++++-------------- interface/tools.py | 100 ++++++++++++++++++++++------------------- main.py | 6 +-- watcher/watcher.py | 1 - 5 files changed, 97 insertions(+), 85 deletions(-) diff --git a/interface/dialog.py b/interface/dialog.py index 5563291..4d7b22b 100644 --- a/interface/dialog.py +++ b/interface/dialog.py @@ -3,7 +3,7 @@ from gi.repository import Gtk -def show_watched_dialog(self): +def edit_settings_dialog(self): dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, "Dossiers surveillés") dialog.format_secondary_text(str(self.config)) diff --git a/interface/interface.py b/interface/interface.py index 5c13da7..0e1f3ad 100644 --- a/interface/interface.py +++ b/interface/interface.py @@ -4,12 +4,21 @@ from gi.repository import Gtk import threading from os import path +from platform import system from .menubar import create_menus -from .tools import about, initialize_interface -from .dialog import show_watched_dialog, del_dir_dialog -import watcher +from .tools import about, MainGrid +from .dialog import edit_settings_dialog, del_dir_dialog from watcher.watcher import Watcher +import watcher + +SYSTEM = system() +if SYSTEM == 'Linux': + from subprocess import Popen +elif SYSTEM == 'Windows': + from os import startfile +else: + watcher.mod.tell('Import Error') class Interface(Gtk.Window): def __init__(self, config): @@ -18,8 +27,8 @@ def __init__(self, config): self.set_border_width(5) self.connect('delete-event', self.quit_app) - initialize_interface(self) - self.switch_start.do_grab_focus(self.switch_start) + self.grid = MainGrid(self) + self.grid.switch_start.do_grab_focus(self.grid.switch_start) self.grid.add(create_menus(self)) self.add(self.grid) @@ -31,9 +40,7 @@ def __init__(self, config): def initialize_config(self): for watched_dir in self.config['watched_dirs']: - self.watched_list.append_text(watched_dir) - for ext in self.config['exclude_ext']: - self.ext_list.append_text(ext) + self.grid.watched_list.append_text(watched_dir) def run(self): self.show_all() @@ -49,62 +56,60 @@ def save_config(self, config=watcher.data.DEFAULT_CONFIG): watcher.conf.save_config(config) def start_watching(self, *args): - if not self.switch_start.get_active(): - self.switch_start.set_active(True) + if not self.grid.switch_start.get_active(): + self.grid.switch_start.set_active(True) def watching(self, *args): - self.text.set_text('Scan en cours') - self.spinner.start() + self.grid.text.set_text('Scan en cours') + self.grid.spinner.start() self.watcher.watch() - self.spinner.stop() - self.thread = threading.Timer(self.watcher.config['time_delta'], self.watching) + self.grid.spinner.stop() + self.thread = threading.Timer(self.config['time_delta'], self.watching) self.thread.start() def stop_watching(self, action=None): - if self.switch_start.get_active(): - self.switch_start.set_active(False) + if self.grid.switch_start.get_active(): + self.grid.switch_start.set_active(False) def cancel_watching(self): - self.text.set_text('Scan annulé') + self.grid.text.set_text('Scan annulé') if self.thread is not None: self.thread.cancel() def show_saved(self, *args): - pass - - def show_watched(self, *args): - show_watched_dialog(self) + if SYSTEM == 'Linux': + Popen(['xdg-open', self.config['archive_dir']]) + elif SYSTEM == 'Windows': + startfile(self.config['archive_dir']) def settings(self, *args): - self.show_watched() + edit_settings_dialog(self) def watch_now(self, *args): - self.spinner.start() + self.grid.spinner.start() self.watcher.watch() - self.spinner.stop() + self.grid.spinner.stop() def add_watched_dir(self, button): - tree_iter = self.watched_list.get_active_iter() + tree_iter = self.grid.watched_list.get_active_iter() if tree_iter is None: - new_dir = self.watched_list.get_child().get_text() + new_dir = self.grid.watched_list.get_child().get_text() if new_dir != '' and new_dir not in self.config['watched_dirs'] and path.exists(new_dir): - print("add dir: " + new_dir) - self.watched_list.append_text(new_dir) + self.grid.watched_list.append_text(new_dir) self.config['watched_dirs'].append(new_dir) - self.text.set_text('Dossier ajouté') + self.grid.text.set_text('Dossier ajouté') def del_watched_dir(self, button): - tree_iter = self.watched_list.get_active_iter() + tree_iter = self.grid.watched_list.get_active_iter() if tree_iter is not None: - model = self.watched_list.get_model() + model = self.grid.watched_list.get_model() directory = model[tree_iter][0] must_del, dialog = del_dir_dialog(self, directory) dialog.destroy() if must_del: - print("delete dir :" + directory) self.config['watched_dirs'].remove(directory) - self.watched_list.remove(int(self.watched_list.get_active())) - self.text.set_text('Dossier supprimé') + self.grid.watched_list.remove(int(self.grid.watched_list.get_active())) + self.grid.text.set_text('Dossier supprimé') def about(self, *args): about() diff --git a/interface/tools.py b/interface/tools.py index c260bf1..1bf6e2f 100644 --- a/interface/tools.py +++ b/interface/tools.py @@ -15,54 +15,62 @@ def about(): dialog.run() dialog.destroy() -def initialize_interface(self): - self.grid = Gtk.Grid(column_spacing=5, row_spacing=5) - self.text = Gtk.Label('En attente...') - # Toolbar: - button_show_saved = Gtk.Button.new_with_label('Fichiers sauvés') - button_show_saved.connect('clicked', self.show_saved) - button_check_now = Gtk.Button.new_with_label('Scanner maintenant') - button_check_now.connect('clicked', self.watch_now) - # Watching: - self.switch_start = Gtk.Switch() - self.switch_start.connect('notify::active', on_switch_activated, self) - self.switch_start.set_active(False) - # Watched dirs: - self.watched_list = Gtk.ComboBoxText.new_with_entry() - self.watched_list.connect('changed', on_changed_watched) - button_add_watched = Gtk.Button.new_with_label('Ajouter') - button_add_watched.connect('clicked', self.add_watched_dir) - button_del_watched = Gtk.Button.new_with_label('Supprimer') - button_del_watched.connect('clicked', self.del_watched_dir) - self.spinner = Gtk.Spinner() +class MainGrid(Gtk.Grid): + """docstring for Grid""" + def __init__(self, root): + super(MainGrid, self).__init__() + self.root = root + self.set_column_spacing(5) + self.set_row_spacing(5) + self.initialize_grid() - # pack: - hbox = Gtk.Box(spacing=6) - hbox.pack_start(self.text, True, True, 0) - hbox.pack_start(self.switch_start, True, True, 0) - hbox.pack_start(self.spinner, True, True, 0) - self.grid.attach(hbox, 0, 1, 2, 1) + def initialize_grid(self): + self.text = Gtk.Label('En attente...') + # Toolbar: + button_show_saved = Gtk.Button.new_with_label('Fichiers sauvés') + button_show_saved.connect('clicked', self.root.show_saved) + button_check_now = Gtk.Button.new_with_label('Scanner maintenant') + button_check_now.connect('clicked', self.root.watch_now) + # Watching: + self.switch_start = Gtk.Switch() + self.switch_start.connect('notify::active', self.on_switch_activated) + self.switch_start.set_active(False) + # Watched dirs: + self.watched_list = Gtk.ComboBoxText.new_with_entry() + self.watched_list.connect('changed', self.on_changed_watched) + button_add_watched = Gtk.Button.new_with_label('Ajouter') + button_add_watched.connect('clicked', self.root.add_watched_dir) + button_del_watched = Gtk.Button.new_with_label('Supprimer') + button_del_watched.connect('clicked', self.root.del_watched_dir) + self.spinner = Gtk.Spinner() - self.grid.attach(button_show_saved, 0, 0, 1, 1) - self.grid.attach(button_check_now, 1, 0 , 1, 1) - self.grid.attach(self.watched_list, 0, 2, 2, 1) - self.grid.attach(button_add_watched, 0, 3, 1, 1) - self.grid.attach(button_del_watched, 1, 3, 1, 1) + # pack: + hbox = Gtk.Box(spacing=6) + hbox.pack_start(self.text, True, True, 0) + hbox.pack_start(self.switch_start, True, True, 0) + hbox.pack_start(self.spinner, True, True, 0) + self.attach(hbox, 0, 1, 2, 1) -def on_changed_ext(ext_list): - tree_iter = ext_list.get_active_iter() - if tree_iter != None: - model = ext_list.get_model() - print(model) - else: - entry = ext_list.get_child() - print("Entered: " + entry.get_text()) + self.attach(button_show_saved, 0, 0, 1, 1) + self.attach(button_check_now, 1, 0 , 1, 1) + self.attach(self.watched_list, 0, 2, 2, 1) + self.attach(button_add_watched, 0, 3, 1, 1) + self.attach(button_del_watched, 1, 3, 1, 1) -def on_changed_watched(watched_list): - pass + def on_changed_ext(self, ext_list): + tree_iter = ext_list.get_active_iter() + if tree_iter != None: + model = ext_list.get_model() + print(model) + else: + entry = ext_list.get_child() + print("Entered: " + entry.get_text()) -def on_switch_activated(switch, active, self): - if switch.get_active(): - self.watching() - else: - self.cancel_watching() + def on_changed_watched(self, watched_list): + pass + + def on_switch_activated(self, switch, active): + if switch.get_active(): + self.root.watching() + else: + self.root.cancel_watching() diff --git a/main.py b/main.py index 6fbf4a7..3e3dd69 100644 --- a/main.py +++ b/main.py @@ -4,12 +4,12 @@ import sys from watcher import conf -from watcher import mod from interface.interface import Interface +myfile = open('stderr.log', 'a') +sys.stderr = myfile + if __name__ == '__main__': - myfile = open('stderr.log', 'a') - sys.stderr = myfile config = conf.get_config() root = Interface(config) root.run() diff --git a/watcher/watcher.py b/watcher/watcher.py index 52ecea6..70df5e1 100644 --- a/watcher/watcher.py +++ b/watcher/watcher.py @@ -2,7 +2,6 @@ #!/usr/bin/python3 from os import path, walk, stat, mkdir -from time import sleep import shutil from .mod import tell, create_archive_dir, combine_list From 168d4640af16e511389aca1ae8b9f5fbd455fbf5 Mon Sep 17 00:00:00 2001 From: Thykof Date: Fri, 25 Mar 2016 18:41:52 +0100 Subject: [PATCH 07/22] Fix code --- README.md | 9 +++------ docs/conf.py | 4 ++-- interface/dialog.py | 2 ++ interface/interface.py | 12 +++++++++--- interface/menubar.py | 27 +++++++++++++++++++++++++-- interface/tools.py | 2 ++ setup.py | 7 ++++--- watcher/conf.py | 2 +- 8 files changed, 48 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 60e1a72..76f9411 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,28 @@ # Safe My work -SafeMyWork save all files in the given directory in another directory to keep your work safe and avoid losing data. +SafeMyWork save all files in the given directory in another directory to keep your work safe and avoid loosing data. [![Documentation Status](https://readthedocs.org/projects/safemywork/badge/?version=develop)](http://safemywork.readthedocs.org/en/develop) [![Build Status](https://travis-ci.org/Thykof/SafeMyWork.svg?branch=develop)](https://travis-ci.org/Thykof/SafeMyWork) [![Code Health](https://landscape.io/github/Thykof/SafeMyWork/develop/landscape.svg?style=flat)](https://landscape.io/github/Thykof/SafeMyWork/develop) ## Version -Current version is 0.2. +Current version is 1.0 #### Current state - feature/outline - watch different directories - specify files and extensions to exclude + - interface (gtk) Work in progress... #### TODO - make an history of each files - compress files - - interface (gtk) ## What for ? SafeMyWork is intend for people who handle lot of files which can be texts, images, songs. Run SafeMyWork and give it a directory to watch. Then while you are working, every ten minutes all files in this directory will be copy in another directory. As the result of keeping them safe if you does not save your work or delete accidentally files. -## How to use it ? -Run `python3 main.py ` to start. The given path is the directory watching. You don't need extra requirement. - ## License SafeMyWork is under the GNU GPL v3 license. diff --git a/docs/conf.py b/docs/conf.py index 6f0dd40..9c3396a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -59,9 +59,9 @@ # built documents. # # The short X.Y version. -version = '0.2' +version = '1.0' # The full version, including alpha/beta/rc tags. -release = '0.2' +release = '1.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/interface/dialog.py b/interface/dialog.py index 4d7b22b..c9b9d85 100644 --- a/interface/dialog.py +++ b/interface/dialog.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- #!/usr/bin/python3 +import gi +gi.require_version('Gtk', '3.0') from gi.repository import Gtk def edit_settings_dialog(self): diff --git a/interface/interface.py b/interface/interface.py index 0e1f3ad..1da2fb4 100644 --- a/interface/interface.py +++ b/interface/interface.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- #!/usr/bin/python3 +import gi +gi.require_version('Gtk', '3.0') from gi.repository import Gtk import threading from os import path @@ -28,9 +30,13 @@ def __init__(self, config): self.connect('delete-event', self.quit_app) self.grid = MainGrid(self) - self.grid.switch_start.do_grab_focus(self.grid.switch_start) - self.grid.add(create_menus(self)) self.add(self.grid) + self.grid.switch_start.do_grab_focus(self.grid.switch_start) + + menubar = create_menus(self) + box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + box.pack_start(menubar, False, False, 0) + self.grid.add(box) self.thread = None self.config = config @@ -62,7 +68,7 @@ def start_watching(self, *args): def watching(self, *args): self.grid.text.set_text('Scan en cours') self.grid.spinner.start() - self.watcher.watch() + self.watch_now() self.grid.spinner.stop() self.thread = threading.Timer(self.config['time_delta'], self.watching) self.thread.start() diff --git a/interface/menubar.py b/interface/menubar.py index ac2e45a..ad195d2 100644 --- a/interface/menubar.py +++ b/interface/menubar.py @@ -1,8 +1,30 @@ # -*- coding: utf-8 -*- #!/usr/bin/python3 +import gi +gi.require_version('Gtk', '3.0') from gi.repository import Gtk +UI_INFO = """ + + + + + + + + + + + + + + + + + +""" + def create_menus(self): action_group = Gtk.ActionGroup(name='menu') @@ -44,7 +66,8 @@ def create_menus(self): action_group.add_action(action_About) uimanager = Gtk.UIManager() - uimanager.add_ui_from_file('interface/menubar.ui') + uimanager.add_ui_from_string(UI_INFO) uimanager.insert_action_group(action_group) + menubar = uimanager.get_widget("/MenuBar") - return uimanager.get_widget("/MenuBar") + return menubar diff --git a/interface/tools.py b/interface/tools.py index 1bf6e2f..c992690 100644 --- a/interface/tools.py +++ b/interface/tools.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- #!/usr/bin/python3 +import gi +gi.require_version('Gtk', '3.0') from gi.repository import Gtk def about(): diff --git a/setup.py b/setup.py index 4c0fe81..0a72424 100644 --- a/setup.py +++ b/setup.py @@ -10,8 +10,8 @@ setup( name='SafeMyWork', - version='0.2', - description='Little app to save your work.', + version='1.0', + description='Autosave your work', long_description=readme, author='Thykof', author_email='nathan.seva@outlook.fr', @@ -24,6 +24,7 @@ "Development Status :: 3 - Alpha", "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 'Operating System :: OS Independent', - 'Programming Language :: Python :: 3' + 'Programming Language :: Python :: 3', + 'Environment :: X11 Applications :: GTK' ], ) diff --git a/watcher/conf.py b/watcher/conf.py index 30ceb9a..2f8bba1 100644 --- a/watcher/conf.py +++ b/watcher/conf.py @@ -74,7 +74,7 @@ def get_config(conf_file=CONF_FILE): """ if not path.exists(conf_file): save_config(conf_file=conf_file) - return None + return DEFAULT_CONFIG else: config = read_config(conf_file) watched_dirs = get_dir_from_argv() From f96d4cb549b4af08a42ea1fcc32aca794aa95e45 Mon Sep 17 00:00:00 2001 From: Thykof Date: Sat, 26 Mar 2016 10:44:55 +0100 Subject: [PATCH 08/22] Improve thread --- interface/interface.py | 58 ++++++++++++++++++++++++------------------ interface/menubar.py | 14 +++++++--- interface/menubar.ui | 18 ------------- interface/tools.py | 11 +++++--- watcher/mod.py | 3 ++- watcher/watcher.py | 23 +++++++++++------ 6 files changed, 68 insertions(+), 59 deletions(-) delete mode 100644 interface/menubar.ui diff --git a/interface/interface.py b/interface/interface.py index 1da2fb4..b79f80f 100644 --- a/interface/interface.py +++ b/interface/interface.py @@ -38,9 +38,10 @@ def __init__(self, config): box.pack_start(menubar, False, False, 0) self.grid.add(box) - self.thread = None self.config = config - self.watcher = Watcher(config) + self.watcher = Watcher(self.config) + self.timer = None + self.thread = None self.initialize_config() @@ -56,31 +57,43 @@ def quit_app(self, *args): Gtk.main_quit() self.save_config(self.config) self.stop_watching() + self.abort_watch() def save_config(self, config=watcher.data.DEFAULT_CONFIG): watcher.mod.tell('Save config') watcher.conf.save_config(config) - def start_watching(self, *args): - if not self.grid.switch_start.get_active(): - self.grid.switch_start.set_active(True) - - def watching(self, *args): - self.grid.text.set_text('Scan en cours') + def watch(self, loop): + """Launch watch""" self.grid.spinner.start() - self.watch_now() + self.watcher.watch() self.grid.spinner.stop() - self.thread = threading.Timer(self.config['time_delta'], self.watching) - self.thread.start() - - def stop_watching(self, action=None): - if self.grid.switch_start.get_active(): - self.grid.switch_start.set_active(False) - - def cancel_watching(self): - self.grid.text.set_text('Scan annulé') - if self.thread is not None: - self.thread.cancel() + if loop: + self.timer = threading.Timer(self.config['time_delta'], self.start_watching, args=(loop,)) + self.timer.start() + + def start_watching(self, loop): + """Start watching : watch + timer""" + can = True + for thread in threading.enumerate(): + print(thread) + if thread.name == 'watcher_loop' or thread.name == 'watcher_alone': + if thread.is_alive(): + print('no!') + can = False + if can: + print('yes!') + self.thread = threading.Thread(target=self.watch, name='watcher_loop', args=(loop,)) + self.thread.start() + + def stop_watching(self): + """Cancel timer""" + if self.timer is not None: + self.timer.cancel() + + def abort_watch(self): + """Abort current watch""" + self.watcher.stop = True def show_saved(self, *args): if SYSTEM == 'Linux': @@ -91,11 +104,6 @@ def show_saved(self, *args): def settings(self, *args): edit_settings_dialog(self) - def watch_now(self, *args): - self.grid.spinner.start() - self.watcher.watch() - self.grid.spinner.stop() - def add_watched_dir(self, button): tree_iter = self.grid.watched_list.get_active_iter() if tree_iter is None: diff --git a/interface/menubar.py b/interface/menubar.py index ad195d2..dd9a909 100644 --- a/interface/menubar.py +++ b/interface/menubar.py @@ -43,15 +43,15 @@ def create_menus(self): action_group.add_action(action_ActionMenu) action_Start = Gtk.Action(name='Start', label='Démmarer le scan') - action_Start.connect('activate', self.start_watching) + action_Start.connect('activate', start_watching, self) action_group.add_action(action_Start) action_Stop = Gtk.Action(name='Stop', label='Arrêter le scan') - action_Stop.connect('activate', self.stop_watching) + action_Stop.connect('activate', stop_watching, self) action_group.add_action(action_Stop) action_CheckNow = Gtk.Action(name='CheckNow', label='Scanner maintenant') - action_CheckNow.connect('activate', self.watch_now) + action_CheckNow.connect('activate', lambda arg: self.start_watching(False)) action_group.add_action(action_CheckNow) action_OpenSaved = Gtk.Action(name='OpenSaved', label='Afficher les fichiers sauvegardés') @@ -71,3 +71,11 @@ def create_menus(self): menubar = uimanager.get_widget("/MenuBar") return menubar + +def start_watching(action, self): + if not self.grid.switch_start.get_active(): + self.grid.switch_start.set_active(True) + +def stop_watching(action, self): + if self.grid.switch_start.get_active(): + self.grid.switch_start.set_active(False) diff --git a/interface/menubar.ui b/interface/menubar.ui deleted file mode 100644 index 6fe5a20..0000000 --- a/interface/menubar.ui +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/interface/tools.py b/interface/tools.py index c992690..cb63fa2 100644 --- a/interface/tools.py +++ b/interface/tools.py @@ -32,7 +32,7 @@ def initialize_grid(self): button_show_saved = Gtk.Button.new_with_label('Fichiers sauvés') button_show_saved.connect('clicked', self.root.show_saved) button_check_now = Gtk.Button.new_with_label('Scanner maintenant') - button_check_now.connect('clicked', self.root.watch_now) + button_check_now.connect('clicked', self.on_check_now_clicked) # Watching: self.switch_start = Gtk.Switch() self.switch_start.connect('notify::active', self.on_switch_activated) @@ -61,7 +61,7 @@ def initialize_grid(self): def on_changed_ext(self, ext_list): tree_iter = ext_list.get_active_iter() - if tree_iter != None: + if tree_iter is not None: model = ext_list.get_model() print(model) else: @@ -73,6 +73,9 @@ def on_changed_watched(self, watched_list): def on_switch_activated(self, switch, active): if switch.get_active(): - self.root.watching() + self.root.start_watching(True) else: - self.root.cancel_watching() + self.root.stop_watching() + + def on_check_now_clicked(self, button): + self.root.start_watching(False) diff --git a/watcher/mod.py b/watcher/mod.py index 2f856b3..915c7cf 100644 --- a/watcher/mod.py +++ b/watcher/mod.py @@ -16,7 +16,8 @@ def tell(message, target='output.log'): :type target: ``str`` """ try: - print(message) + #print(message) + pass # -dev- except UnicodeEncodeError: message = message.encode('ascii', 'replace') message = message.decode('ascii', 'replace') diff --git a/watcher/watcher.py b/watcher/watcher.py index 70df5e1..617b5c4 100644 --- a/watcher/watcher.py +++ b/watcher/watcher.py @@ -10,6 +10,7 @@ class Watcher(object): """A class that manage safing files.""" def __init__(self, config): super(Watcher, self).__init__() + self.stop = False self.config = config def watch(self): @@ -24,14 +25,20 @@ def watch(self): create_archive_dir(self.config['archive_dir'], self.config['watched_dirs']) tell('===WATCHING===') for watched_dir in self.config['watched_dirs']: - unsaved_files = self.list_files(watched_dir) - saved_files = self.list_files(path.join(self.config['archive_dir'], path.basename(watched_dir))) - files_to_save = self.compare_files(unsaved_files, saved_files, watched_dir) - if len(files_to_save) > 0: - self.create_safe_dirs(watched_dir) - for filename in files_to_save: - archived_file = self.archive_file(filename, watched_dir) - tell('Archived: ' + archived_file) + if not self.stop: + unsaved_files = self.list_files(watched_dir) + saved_files = self.list_files(path.join(self.config['archive_dir'], path.basename(watched_dir))) + files_to_save = self.compare_files(unsaved_files, saved_files, watched_dir) + if len(files_to_save) > 0: + self.create_safe_dirs(watched_dir) + for filename in files_to_save: + if not self.stop: + archived_file = self.archive_file(filename, watched_dir) + tell('Archived: ' + archived_file) + else: + break + else: + break tell('Done') def list_files(self, path_dir): From 411ea2b0d653cac59a149e6fb139fb1def82ccca Mon Sep 17 00:00:00 2001 From: Thykof Date: Sat, 26 Mar 2016 11:19:10 +0100 Subject: [PATCH 09/22] Avoid multiple threads launch --- interface/interface.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/interface/interface.py b/interface/interface.py index b79f80f..44ecb07 100644 --- a/interface/interface.py +++ b/interface/interface.py @@ -54,10 +54,12 @@ def run(self): Gtk.main() def quit_app(self, *args): - Gtk.main_quit() + self.grid.text.set_text('Fermeture') self.save_config(self.config) + self.grid.switch_start.set_active(False) self.stop_watching() - self.abort_watch() + Gtk.main_quit() + #self.abort_watch() def save_config(self, config=watcher.data.DEFAULT_CONFIG): watcher.mod.tell('Save config') @@ -75,6 +77,8 @@ def watch(self, loop): def start_watching(self, loop): """Start watching : watch + timer""" can = True + if loop: + can = self.grid.switch_start.get_active() for thread in threading.enumerate(): print(thread) if thread.name == 'watcher_loop' or thread.name == 'watcher_alone': From 3d2065723822307db055d49150270fc9422bb5c2 Mon Sep 17 00:00:00 2001 From: Thykof Date: Sat, 2 Apr 2016 13:05:35 +0200 Subject: [PATCH 10/22] Add settings dialog --- interface/dialog.py | 122 +++++++++++++++++++++++++++++++++++++++-- interface/interface.py | 13 +++-- interface/tools.py | 13 ----- 3 files changed, 123 insertions(+), 25 deletions(-) diff --git a/interface/dialog.py b/interface/dialog.py index c9b9d85..16e0fc2 100644 --- a/interface/dialog.py +++ b/interface/dialog.py @@ -5,15 +5,125 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk -def edit_settings_dialog(self): - dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO, - Gtk.ButtonsType.OK, "Dossiers surveillés") - dialog.format_secondary_text(str(self.config)) - dialog.run() - dialog.destroy() +from os import path def del_dir_dialog(self, directory): dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Ne plus surveiller " + directory + " ?") response = dialog.run() return response == Gtk.ResponseType.YES, dialog + +class Settings(Gtk.Dialog): + """docstring for Settings""" + def __init__(self, root): + Gtk.Dialog.__init__(self, 'Préférences', root, 0) + self.root = root + self.set_modal(True) + self.set_resizable(False) + self.set_border_width(10) + self.connect('delete-event', self.close) + box = self.get_content_area() + + button_close = Gtk.Button.new_with_label('Femrer') + button_close.connect('clicked', self.close) + + # Set timedelta: + box_time = Gtk.Box(spacing=6) + adjustment = Gtk.Adjustment(10, 1, 60, 10, 10, 0) + self.spinbutton = Gtk.SpinButton(adjustment=adjustment) + self.spinbutton.set_digits(0) + self.spinbutton.set_value(self.root.config['time_delta']) + timedelta_button = Gtk.Button.new_with_label('Changer') + timedelta_button.connect('clicked', self.change_timedelta) + box_time.pack_start(Gtk.Label('Scan tous les :'), False, False, 0) + box_time.pack_start(self.spinbutton, False, False, 0) + box_time.pack_start(Gtk.Label('Minutes. '), False, False, 0) + box_time.pack_start(timedelta_button, False, False, 0) + + # Exclude extenstions: + box_ext = Gtk.Box(spacing=6) + box_ext.pack_start(Gtk.Label('Extensions : '), False, False, 0) + ext_list = Gtk.ComboBoxText.new_with_entry() + button_add_ext = Gtk.Button.new_with_label('Ajouter') + button_add_ext.connect('clicked', lambda arg: self.add('exclude_ext', ext_list)) + button_del_ext = Gtk.Button.new_with_label('Supprimer') + button_del_ext.connect('clicked', lambda arg: self.delete('exclude_ext', ext_list)) + box_ext.pack_start(ext_list, False, False, 0) + box_ext.pack_start(button_add_ext, False, False, 0) + box_ext.pack_start(button_del_ext, False, False, 0) + for ext in self.root.config['exclude_ext']: + ext_list.append_text(ext) + + # Exclude files: + box_files = Gtk.Box(spacing=6) + box_files.pack_start(Gtk.Label('Fichiers : '), False, False, 0) + file_list = Gtk.ComboBoxText.new_with_entry() + button_add_file = Gtk.Button.new_with_label('Ajouter') + button_add_file.connect('clicked', lambda arg: self.add('exclude_files', file_list)) + button_del_file = Gtk.Button.new_with_label('Supprimer') + button_del_file.connect('clicked', lambda arg: self.delete('exclude_files', file_list)) + box_files.pack_start(file_list, False, False, 0) + box_files.pack_start(button_add_file, False, False, 0) + box_files.pack_start(button_del_file, False, False, 0) + for file in self.root.config['exclude_files']: + file_list.append_text(file) + + # Exclude directories: + box_dirs = Gtk.Box(spacing=6) + box_dirs.pack_start(Gtk.Label('Dossiers : '), False, False, 0) + dirs_list = Gtk.ComboBoxText.new_with_entry() + button_add_dirs = Gtk.Button.new_with_label('Ajouter') + button_add_dirs.connect('clicked', lambda arg: self.add('exclude_dirs', dirs_list)) + button_del_dirs = Gtk.Button.new_with_label('Supprimer') + button_del_dirs.connect('clicked', lambda arg: self.delete('exclude_dirs', dirs_list)) + box_dirs.pack_start(dirs_list, False, False, 0) + box_dirs.pack_start(button_add_dirs, False, False, 0) + box_dirs.pack_start(button_del_dirs, False, False, 0) + for dirs in self.root.config['exclude_dirs']: + dirs_list.append_text(dirs) + + # Archive directory: + box_archive_dir = Gtk.Box(spacing=6) + self.archive_entry = Gtk.Entry() + self.archive_entry.set_text(self.root.config['archive_dir']) + archive_button = Gtk.Button.new_with_label('Changer') + archive_button.connect('clicked', self.change_archive_dir) + box_archive_dir.pack_start(self.archive_entry, False, False, 0) + box_archive_dir.pack_start(archive_button, False, False, 0) + + # Pack boxes + box.pack_start(box_time, False, False, 0) + box.pack_start(box_ext, False, False, 0) + box.pack_start(box_files, False, False, 0) + box.pack_start(box_dirs, False, False, 0) + box.pack_start(box_archive_dir, False, False, 0) + box.pack_start(button_close, False, False, 0) + self.show_all() + + def close(self, *args): + self.destroy() + + def add(self, elt, combo_list): + tree_iter = combo_list.get_active_iter() + if tree_iter is None: + new = combo_list.get_child().get_text() + if new not in self.root.config[elt]: + combo_list.append_text(new) + self.root.config[elt].append(new) + + def delete(self, elt, combo_list): + tree_iter = combo_list.get_active_iter() + if tree_iter is not None: + model = combo_list.get_model() + new = model[tree_iter][0] + combo_list.remove(int(combo_list.get_active())) + self.root.config[elt].remove(new) + + def change_timedelta(self, button): + timedelta = int(self.spinbutton.get_value()) + self.root.config['time_delta'] = timedelta + + def change_archive_dir(self, button): + new = self.archive_entry.get_text() + if path.exists(path.dirname(new)) or path.dirname(new) == '': + self.root.config['archive_dir'] = new diff --git a/interface/interface.py b/interface/interface.py index 44ecb07..6ef7f93 100644 --- a/interface/interface.py +++ b/interface/interface.py @@ -10,7 +10,7 @@ from .menubar import create_menus from .tools import about, MainGrid -from .dialog import edit_settings_dialog, del_dir_dialog +from .dialog import del_dir_dialog, Settings from watcher.watcher import Watcher import watcher @@ -71,7 +71,7 @@ def watch(self, loop): self.watcher.watch() self.grid.spinner.stop() if loop: - self.timer = threading.Timer(self.config['time_delta'], self.start_watching, args=(loop,)) + self.timer = threading.Timer(self.config['time_delta']*60, self.start_watching, args=(loop,)) self.timer.start() def start_watching(self, loop): @@ -80,20 +80,20 @@ def start_watching(self, loop): if loop: can = self.grid.switch_start.get_active() for thread in threading.enumerate(): - print(thread) if thread.name == 'watcher_loop' or thread.name == 'watcher_alone': if thread.is_alive(): - print('no!') can = False if can: - print('yes!') self.thread = threading.Thread(target=self.watch, name='watcher_loop', args=(loop,)) self.thread.start() + if loop: + self.grid.text.set_text('Surveillance active') def stop_watching(self): """Cancel timer""" if self.timer is not None: self.timer.cancel() + self.grid.text.set_text('En attente...') def abort_watch(self): """Abort current watch""" @@ -106,7 +106,8 @@ def show_saved(self, *args): startfile(self.config['archive_dir']) def settings(self, *args): - edit_settings_dialog(self) + dialog_settings = Settings(self) + dialog_settings.run() def add_watched_dir(self, button): tree_iter = self.grid.watched_list.get_active_iter() diff --git a/interface/tools.py b/interface/tools.py index cb63fa2..5d4471a 100644 --- a/interface/tools.py +++ b/interface/tools.py @@ -39,7 +39,6 @@ def initialize_grid(self): self.switch_start.set_active(False) # Watched dirs: self.watched_list = Gtk.ComboBoxText.new_with_entry() - self.watched_list.connect('changed', self.on_changed_watched) button_add_watched = Gtk.Button.new_with_label('Ajouter') button_add_watched.connect('clicked', self.root.add_watched_dir) button_del_watched = Gtk.Button.new_with_label('Supprimer') @@ -59,18 +58,6 @@ def initialize_grid(self): self.attach(button_add_watched, 0, 3, 1, 1) self.attach(button_del_watched, 1, 3, 1, 1) - def on_changed_ext(self, ext_list): - tree_iter = ext_list.get_active_iter() - if tree_iter is not None: - model = ext_list.get_model() - print(model) - else: - entry = ext_list.get_child() - print("Entered: " + entry.get_text()) - - def on_changed_watched(self, watched_list): - pass - def on_switch_activated(self, switch, active): if switch.get_active(): self.root.start_watching(True) From 3099c15158bc205f5ce2f31b0252230d9208cfb4 Mon Sep 17 00:00:00 2001 From: Thykof Date: Sun, 3 Apr 2016 10:30:35 +0200 Subject: [PATCH 11/22] Clean code --- interface/dialog.py | 62 ++++++++++++++++++++++++++---------------- interface/interface.py | 6 ++-- interface/menubar.py | 28 +++++++++---------- interface/tools.py | 16 +++++------ watcher/data.py | 2 +- 5 files changed, 65 insertions(+), 49 deletions(-) diff --git a/interface/dialog.py b/interface/dialog.py index 16e0fc2..a690cea 100644 --- a/interface/dialog.py +++ b/interface/dialog.py @@ -7,39 +7,56 @@ from os import path -def del_dir_dialog(self, directory): - dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, +def del_dir_dialog(parent, directory): + dialog = Gtk.MessageDialog(parent, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, "Ne plus surveiller " + directory + " ?") response = dialog.run() return response == Gtk.ResponseType.YES, dialog class Settings(Gtk.Dialog): """docstring for Settings""" - def __init__(self, root): - Gtk.Dialog.__init__(self, 'Préférences', root, 0) - self.root = root + def __init__(self, parent): + Gtk.Dialog.__init__(self, 'Préférences', parent, 0) + self.parent = parent self.set_modal(True) self.set_resizable(False) self.set_border_width(10) self.connect('delete-event', self.close) box = self.get_content_area() + box_time = self.create_box_time() + box_ext = self.create_box_ext() + box_files = self.create_box_files() + box_dirs = self.create_box_dirs() + box_archive_dir = self.create_box_archive_dir() button_close = Gtk.Button.new_with_label('Femrer') button_close.connect('clicked', self.close) + # Pack boxes + box.pack_start(box_time, False, False, 0) + box.pack_start(box_ext, False, False, 0) + box.pack_start(box_files, False, False, 0) + box.pack_start(box_dirs, False, False, 0) + box.pack_start(box_archive_dir, False, False, 0) + box.pack_start(button_close, False, False, 0) + self.show_all() + + def create_box_time(self): # Set timedelta: box_time = Gtk.Box(spacing=6) adjustment = Gtk.Adjustment(10, 1, 60, 10, 10, 0) self.spinbutton = Gtk.SpinButton(adjustment=adjustment) self.spinbutton.set_digits(0) - self.spinbutton.set_value(self.root.config['time_delta']) + self.spinbutton.set_value(self.parent.config['time_delta']) timedelta_button = Gtk.Button.new_with_label('Changer') timedelta_button.connect('clicked', self.change_timedelta) box_time.pack_start(Gtk.Label('Scan tous les :'), False, False, 0) box_time.pack_start(self.spinbutton, False, False, 0) box_time.pack_start(Gtk.Label('Minutes. '), False, False, 0) box_time.pack_start(timedelta_button, False, False, 0) + return box_time + def create_box_ext(self): # Exclude extenstions: box_ext = Gtk.Box(spacing=6) box_ext.pack_start(Gtk.Label('Extensions : '), False, False, 0) @@ -51,9 +68,11 @@ def __init__(self, root): box_ext.pack_start(ext_list, False, False, 0) box_ext.pack_start(button_add_ext, False, False, 0) box_ext.pack_start(button_del_ext, False, False, 0) - for ext in self.root.config['exclude_ext']: + for ext in self.parent.config['exclude_ext']: ext_list.append_text(ext) + return box_ext + def create_box_files(self): # Exclude files: box_files = Gtk.Box(spacing=6) box_files.pack_start(Gtk.Label('Fichiers : '), False, False, 0) @@ -65,9 +84,11 @@ def __init__(self, root): box_files.pack_start(file_list, False, False, 0) box_files.pack_start(button_add_file, False, False, 0) box_files.pack_start(button_del_file, False, False, 0) - for file in self.root.config['exclude_files']: + for file in self.parent.config['exclude_files']: file_list.append_text(file) + return box_files + def create_box_dirs(self): # Exclude directories: box_dirs = Gtk.Box(spacing=6) box_dirs.pack_start(Gtk.Label('Dossiers : '), False, False, 0) @@ -79,26 +100,21 @@ def __init__(self, root): box_dirs.pack_start(dirs_list, False, False, 0) box_dirs.pack_start(button_add_dirs, False, False, 0) box_dirs.pack_start(button_del_dirs, False, False, 0) - for dirs in self.root.config['exclude_dirs']: + for dirs in self.parent.config['exclude_dirs']: dirs_list.append_text(dirs) + return box_dirs + def create_box_archive_dir(self): # Archive directory: box_archive_dir = Gtk.Box(spacing=6) self.archive_entry = Gtk.Entry() - self.archive_entry.set_text(self.root.config['archive_dir']) + self.archive_entry.set_text(self.parent.config['archive_dir']) archive_button = Gtk.Button.new_with_label('Changer') archive_button.connect('clicked', self.change_archive_dir) box_archive_dir.pack_start(self.archive_entry, False, False, 0) box_archive_dir.pack_start(archive_button, False, False, 0) + return box_archive_dir - # Pack boxes - box.pack_start(box_time, False, False, 0) - box.pack_start(box_ext, False, False, 0) - box.pack_start(box_files, False, False, 0) - box.pack_start(box_dirs, False, False, 0) - box.pack_start(box_archive_dir, False, False, 0) - box.pack_start(button_close, False, False, 0) - self.show_all() def close(self, *args): self.destroy() @@ -107,9 +123,9 @@ def add(self, elt, combo_list): tree_iter = combo_list.get_active_iter() if tree_iter is None: new = combo_list.get_child().get_text() - if new not in self.root.config[elt]: + if new not in self.parent.config[elt]: combo_list.append_text(new) - self.root.config[elt].append(new) + self.parent.config[elt].append(new) def delete(self, elt, combo_list): tree_iter = combo_list.get_active_iter() @@ -117,13 +133,13 @@ def delete(self, elt, combo_list): model = combo_list.get_model() new = model[tree_iter][0] combo_list.remove(int(combo_list.get_active())) - self.root.config[elt].remove(new) + self.parent.config[elt].remove(new) def change_timedelta(self, button): timedelta = int(self.spinbutton.get_value()) - self.root.config['time_delta'] = timedelta + self.parent.config['time_delta'] = timedelta def change_archive_dir(self, button): new = self.archive_entry.get_text() if path.exists(path.dirname(new)) or path.dirname(new) == '': - self.root.config['archive_dir'] = new + self.parent.config['archive_dir'] = new diff --git a/interface/interface.py b/interface/interface.py index 6ef7f93..8279d83 100644 --- a/interface/interface.py +++ b/interface/interface.py @@ -61,7 +61,7 @@ def quit_app(self, *args): Gtk.main_quit() #self.abort_watch() - def save_config(self, config=watcher.data.DEFAULT_CONFIG): + def save_config(self, config): watcher.mod.tell('Save config') watcher.conf.save_config(config) @@ -105,7 +105,7 @@ def show_saved(self, *args): elif SYSTEM == 'Windows': startfile(self.config['archive_dir']) - def settings(self, *args): + def settings(self, action): dialog_settings = Settings(self) dialog_settings.run() @@ -130,5 +130,5 @@ def del_watched_dir(self, button): self.grid.watched_list.remove(int(self.grid.watched_list.get_active())) self.grid.text.set_text('Dossier supprimé') - def about(self, *args): + def about(self, action): about() diff --git a/interface/menubar.py b/interface/menubar.py index dd9a909..2126490 100644 --- a/interface/menubar.py +++ b/interface/menubar.py @@ -25,44 +25,44 @@ """ -def create_menus(self): +def create_menus(parent): action_group = Gtk.ActionGroup(name='menu') action_FileMenu = Gtk.Action(name="FileMenu", label="Fichier") action_group.add_action(action_FileMenu) action_Settings = Gtk.Action(name='Settings', label='Préférences') - action_Settings.connect('activate', self.settings) + action_Settings.connect('activate', parent.settings) action_group.add_action(action_Settings) action_Quit = Gtk.Action(name='Quit', label='Quitter') - action_Quit.connect('activate', self.quit_app) + action_Quit.connect('activate', parent.quit_app) action_group.add_action(action_Quit) action_ActionMenu = Gtk.Action(name="ActionMenu", label="Action") action_group.add_action(action_ActionMenu) action_Start = Gtk.Action(name='Start', label='Démmarer le scan') - action_Start.connect('activate', start_watching, self) + action_Start.connect('activate', lambda arg: start_watching(parent)) action_group.add_action(action_Start) action_Stop = Gtk.Action(name='Stop', label='Arrêter le scan') - action_Stop.connect('activate', stop_watching, self) + action_Stop.connect('activate', lambda arg: stop_watching(parent)) action_group.add_action(action_Stop) action_CheckNow = Gtk.Action(name='CheckNow', label='Scanner maintenant') - action_CheckNow.connect('activate', lambda arg: self.start_watching(False)) + action_CheckNow.connect('activate', lambda arg: parent.start_watching(False)) action_group.add_action(action_CheckNow) action_OpenSaved = Gtk.Action(name='OpenSaved', label='Afficher les fichiers sauvegardés') - action_OpenSaved.connect('activate', self.show_saved) + action_OpenSaved.connect('activate', parent.show_saved) action_group.add_action(action_OpenSaved) action_HelpMenu = Gtk.Action(name="HelpMenu", label="Aide") action_group.add_action(action_HelpMenu) action_About = Gtk.Action(name='About', label='À propos') - action_About.connect('activate', self.about) + action_About.connect('activate', parent.about) action_group.add_action(action_About) uimanager = Gtk.UIManager() @@ -72,10 +72,10 @@ def create_menus(self): return menubar -def start_watching(action, self): - if not self.grid.switch_start.get_active(): - self.grid.switch_start.set_active(True) +def start_watching(parent): + if not parent.grid.switch_start.get_active(): + parent.grid.switch_start.set_active(True) -def stop_watching(action, self): - if self.grid.switch_start.get_active(): - self.grid.switch_start.set_active(False) +def stop_watching(parent): + if parent.grid.switch_start.get_active(): + parent.grid.switch_start.set_active(False) diff --git a/interface/tools.py b/interface/tools.py index 5d4471a..99f67d6 100644 --- a/interface/tools.py +++ b/interface/tools.py @@ -19,9 +19,9 @@ def about(): class MainGrid(Gtk.Grid): """docstring for Grid""" - def __init__(self, root): + def __init__(self, parent): super(MainGrid, self).__init__() - self.root = root + self.parent = parent self.set_column_spacing(5) self.set_row_spacing(5) self.initialize_grid() @@ -30,7 +30,7 @@ def initialize_grid(self): self.text = Gtk.Label('En attente...') # Toolbar: button_show_saved = Gtk.Button.new_with_label('Fichiers sauvés') - button_show_saved.connect('clicked', self.root.show_saved) + button_show_saved.connect('clicked', self.parent.show_saved) button_check_now = Gtk.Button.new_with_label('Scanner maintenant') button_check_now.connect('clicked', self.on_check_now_clicked) # Watching: @@ -40,9 +40,9 @@ def initialize_grid(self): # Watched dirs: self.watched_list = Gtk.ComboBoxText.new_with_entry() button_add_watched = Gtk.Button.new_with_label('Ajouter') - button_add_watched.connect('clicked', self.root.add_watched_dir) + button_add_watched.connect('clicked', self.parent.add_watched_dir) button_del_watched = Gtk.Button.new_with_label('Supprimer') - button_del_watched.connect('clicked', self.root.del_watched_dir) + button_del_watched.connect('clicked', self.parent.del_watched_dir) self.spinner = Gtk.Spinner() # pack: @@ -60,9 +60,9 @@ def initialize_grid(self): def on_switch_activated(self, switch, active): if switch.get_active(): - self.root.start_watching(True) + self.parent.start_watching(True) else: - self.root.stop_watching() + self.parent.stop_watching() def on_check_now_clicked(self, button): - self.root.start_watching(False) + self.parent.start_watching(False) diff --git a/watcher/data.py b/watcher/data.py index c50fc46..b2f435f 100644 --- a/watcher/data.py +++ b/watcher/data.py @@ -3,7 +3,7 @@ CONF_FILE = 'SMW_conf_file.ini' DEFAULT_CONFIG = { - 'time_delta': 600, + 'time_delta': 10, 'archive_dir': 'safe_docs', 'watched_dirs': [], 'exclude_dirs': [], From b90f6a7be480eedb42361f38a4f2969f3c3bad19 Mon Sep 17 00:00:00 2001 From: Thykof Date: Sun, 3 Apr 2016 10:35:28 +0200 Subject: [PATCH 12/22] Fix exclude directory, improve create directories --- watcher/watcher.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/watcher/watcher.py b/watcher/watcher.py index 617b5c4..521eaf2 100644 --- a/watcher/watcher.py +++ b/watcher/watcher.py @@ -30,7 +30,7 @@ def watch(self): saved_files = self.list_files(path.join(self.config['archive_dir'], path.basename(watched_dir))) files_to_save = self.compare_files(unsaved_files, saved_files, watched_dir) if len(files_to_save) > 0: - self.create_safe_dirs(watched_dir) + self.create_safe_dirs(watched_dir, files_to_save) for filename in files_to_save: if not self.stop: archived_file = self.archive_file(filename, watched_dir) @@ -86,8 +86,13 @@ def filter_files(self, filename): # Filter files: file_ok = False if filename in self.config['exclude_files'] else True # Filter directories: - directory = path.split(filename)[0] - dir_ok = False if directory in self.config['exclude_dirs'] else True + dir_ok = True + directory = path.dirname(filename) + for exclude_dir in self.config['exclude_dirs']: + if exclude_dir in directory: + dir_ok = False + if directory is '': + dir_ok = True if ext_ok and file_ok and dir_ok: return True @@ -132,7 +137,7 @@ def compare_files(self, unsaved_files, saved_files, watched_dir): tell('Skipping: ' + filename) return files_to_save - def create_safe_dirs(self, watched_dir): + def create_safe_dirs(self, watched_dir, files_to_save): """Make all directories from *watched_dir* in archive directory. :param watched_dir: the directory watching @@ -140,9 +145,15 @@ def create_safe_dirs(self, watched_dir): """ dirs = self.list_dirs(watched_dir) for directory in dirs: - path_dir = path.join(self.config['archive_dir'], path.basename(watched_dir), directory) - if not path.exists(path_dir): - mkdir(path_dir) + # Don't create directory excluded: + exclude_dir = True + for exclude_dir in self.config['exclude_dirs']: + if exclude_dir in directory: + exclude_dir = False + if exclude_dir: + path_dir = path.join(self.config['archive_dir'], path.basename(watched_dir), directory) + if not path.exists(path_dir): + mkdir(path_dir) def archive_file(self, filename, watched_dir): """Copy the *filename* in the archive directory. From 384f82db7d8782f2b75987162a437030f63c5276 Mon Sep 17 00:00:00 2001 From: Thykof Date: Sun, 3 Apr 2016 10:39:39 +0200 Subject: [PATCH 13/22] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 76f9411..9cc2e6d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Current version is 1.0 #### Current state - feature/outline - watch different directories - - specify files and extensions to exclude + - specify directories, files and extensions to exclude - interface (gtk) Work in progress... From 3acec84f9deacbc9dfce7e6d46aaa8cceac6ee41 Mon Sep 17 00:00:00 2001 From: Thykof Date: Sun, 3 Apr 2016 18:20:43 +0200 Subject: [PATCH 14/22] Set transient in about dialog --- interface/interface.py | 2 +- interface/tools.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/interface.py b/interface/interface.py index 8279d83..c0abd10 100644 --- a/interface/interface.py +++ b/interface/interface.py @@ -131,4 +131,4 @@ def del_watched_dir(self, button): self.grid.text.set_text('Dossier supprimé') def about(self, action): - about() + about(self) diff --git a/interface/tools.py b/interface/tools.py index 99f67d6..af8f779 100644 --- a/interface/tools.py +++ b/interface/tools.py @@ -5,8 +5,8 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk -def about(): - dialog = Gtk.AboutDialog() +def about(parent): + dialog = Gtk.AboutDialog(transient_for=parent) dialog.set_program_name('SafeMyWork') dialog.set_version('1.0') dialog.set_website('https://github.com/Thykof/SafeMyWork') From ef53d0855774e761d6200ae63c198d116b2174ae Mon Sep 17 00:00:00 2001 From: Thykof Date: Mon, 4 Apr 2016 16:26:37 +0200 Subject: [PATCH 15/22] Gtk.Applicaton and ApplicationWindow --- interface/interface.py | 29 +++----------- interface/menubar.py | 90 +++++++++++++----------------------------- interface/menubar.ui | 48 ++++++++++++++++++++++ main.py | 42 ++++++++++++++++++-- 4 files changed, 119 insertions(+), 90 deletions(-) create mode 100644 interface/menubar.ui diff --git a/interface/interface.py b/interface/interface.py index c0abd10..62c8643 100644 --- a/interface/interface.py +++ b/interface/interface.py @@ -22,21 +22,17 @@ else: watcher.mod.tell('Import Error') -class Interface(Gtk.Window): - def __init__(self, config): - Gtk.Window.__init__(self, title='SafeMyWork 1.0') +class MyWindow(Gtk.ApplicationWindow): + def __init__(self, app, config): + Gtk.Window.__init__(self, title='SafeMyWork 1.0', application=app) self.set_position(Gtk.WindowPosition.CENTER) self.set_border_width(5) - self.connect('delete-event', self.quit_app) self.grid = MainGrid(self) self.add(self.grid) self.grid.switch_start.do_grab_focus(self.grid.switch_start) - menubar = create_menus(self) - box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - box.pack_start(menubar, False, False, 0) - self.grid.add(box) + create_menus(self) self.config = config self.watcher = Watcher(self.config) @@ -49,18 +45,6 @@ def initialize_config(self): for watched_dir in self.config['watched_dirs']: self.grid.watched_list.append_text(watched_dir) - def run(self): - self.show_all() - Gtk.main() - - def quit_app(self, *args): - self.grid.text.set_text('Fermeture') - self.save_config(self.config) - self.grid.switch_start.set_active(False) - self.stop_watching() - Gtk.main_quit() - #self.abort_watch() - def save_config(self, config): watcher.mod.tell('Save config') watcher.conf.save_config(config) @@ -105,7 +89,7 @@ def show_saved(self, *args): elif SYSTEM == 'Windows': startfile(self.config['archive_dir']) - def settings(self, action): + def settings(self, action, parameter): dialog_settings = Settings(self) dialog_settings.run() @@ -129,6 +113,3 @@ def del_watched_dir(self, button): self.config['watched_dirs'].remove(directory) self.grid.watched_list.remove(int(self.grid.watched_list.get_active())) self.grid.text.set_text('Dossier supprimé') - - def about(self, action): - about(self) diff --git a/interface/menubar.py b/interface/menubar.py index 2126490..0cba2ba 100644 --- a/interface/menubar.py +++ b/interface/menubar.py @@ -3,79 +3,45 @@ import gi gi.require_version('Gtk', '3.0') -from gi.repository import Gtk +from gi.repository import Gio -UI_INFO = """ - - - - - - - - - - - - - - - - - -""" +from .tools import about def create_menus(parent): - action_group = Gtk.ActionGroup(name='menu') + show_saved_action = Gio.SimpleAction.new('show_saved') + show_saved_action.connect('activate', parent.show_saved) + parent.add_action(show_saved_action) - action_FileMenu = Gtk.Action(name="FileMenu", label="Fichier") - action_group.add_action(action_FileMenu) + settings_action = Gio.SimpleAction.new('settings') + settings_action.connect('activate', parent.settings) + parent.add_action(settings_action) - action_Settings = Gtk.Action(name='Settings', label='Préférences') - action_Settings.connect('activate', parent.settings) - action_group.add_action(action_Settings) + start_watching_action = Gio.SimpleAction.new('start_watching') + start_watching_action.connect('activate', start_watching, parent) + parent.add_action(start_watching_action) - action_Quit = Gtk.Action(name='Quit', label='Quitter') - action_Quit.connect('activate', parent.quit_app) - action_group.add_action(action_Quit) + stop_watching_action = Gio.SimpleAction.new('stop_watching') + stop_watching_action.connect('activate', stop_watching, parent) + parent.add_action(stop_watching_action) - action_ActionMenu = Gtk.Action(name="ActionMenu", label="Action") - action_group.add_action(action_ActionMenu) + watch_now_action = Gio.SimpleAction.new('watch_now') + watch_now_action.connect('activate', wtach_now, parent) + parent.add_action(watch_now_action) - action_Start = Gtk.Action(name='Start', label='Démmarer le scan') - action_Start.connect('activate', lambda arg: start_watching(parent)) - action_group.add_action(action_Start) + about_action = Gio.SimpleAction.new('about') + about_action.connect('activate', show_about, parent) + parent.add_action(about_action) - action_Stop = Gtk.Action(name='Stop', label='Arrêter le scan') - action_Stop.connect('activate', lambda arg: stop_watching(parent)) - action_group.add_action(action_Stop) - - action_CheckNow = Gtk.Action(name='CheckNow', label='Scanner maintenant') - action_CheckNow.connect('activate', lambda arg: parent.start_watching(False)) - action_group.add_action(action_CheckNow) - - action_OpenSaved = Gtk.Action(name='OpenSaved', label='Afficher les fichiers sauvegardés') - action_OpenSaved.connect('activate', parent.show_saved) - action_group.add_action(action_OpenSaved) - - action_HelpMenu = Gtk.Action(name="HelpMenu", label="Aide") - action_group.add_action(action_HelpMenu) - - action_About = Gtk.Action(name='About', label='À propos') - action_About.connect('activate', parent.about) - action_group.add_action(action_About) - - uimanager = Gtk.UIManager() - uimanager.add_ui_from_string(UI_INFO) - uimanager.insert_action_group(action_group) - menubar = uimanager.get_widget("/MenuBar") - - return menubar - -def start_watching(parent): +def start_watching(action, parameter, parent): if not parent.grid.switch_start.get_active(): parent.grid.switch_start.set_active(True) -def stop_watching(parent): +def stop_watching(action, parameter, parent): if parent.grid.switch_start.get_active(): parent.grid.switch_start.set_active(False) + +def show_about(action, parameter, parent): + about(parent) + +def wtach_now(action, parameter, parent): + parent.start_watching(False) diff --git a/interface/menubar.ui b/interface/menubar.ui new file mode 100644 index 0000000..c7d977c --- /dev/null +++ b/interface/menubar.ui @@ -0,0 +1,48 @@ + + + + + Fichier +
+ + Afficher les fichiers sauvegardés + win.show_saved + + + Préférences + win.settings + + + Quitter + app.quit + +
+
+ + Action +
+ + Démmarer le scan + win.start_watching + + + Arrêter le scan + win.stop_watching + + + Scanner maintenant + win.watch_now + +
+
+ + Aide +
+ + À propos + win.about + +
+
+
+
diff --git a/main.py b/main.py index 3e3dd69..3ea723b 100644 --- a/main.py +++ b/main.py @@ -1,15 +1,49 @@ # -*- coding: utf-8 -*- #!/usr/bin/python3 +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk, Gio import sys from watcher import conf -from interface.interface import Interface +from interface.interface import MyWindow myfile = open('stderr.log', 'a') sys.stderr = myfile +class MyApplication(Gtk.Application): + def __init__(self): + Gtk.Application.__init__(self) + + def do_activate(self): + self.win = MyWindow(self, conf.get_config()) + self.win.show_all() + + def do_startup(self): + Gtk.Application.do_startup(self) + + quit_action = Gio.SimpleAction.new('quit', None) + quit_action.connect('activate', self.quit_callback) + self.add_action(quit_action) + + builder = Gtk.Builder() + try: + builder.add_from_file('interface/menubar.ui') + except: + from interface.menubar_ui import UI_INFO + builder.add_from_string(UI_INFO) + + self.set_menubar(builder.get_object('menubar')) + + def quit_callback(self, action, parameter): + self.win.grid.text.set_text('Fermeture') + conf.save_config(self.win.config) + self.win.grid.switch_start.set_active(False) + self.win.stop_watching() + sys.exit() + if __name__ == '__main__': - config = conf.get_config() - root = Interface(config) - root.run() + app = MyApplication() + exit_status = app.run(sys.argv) + sys.exit(exit_status) From 4936dee4f79f90c0b630cfe42830c780631cc7e3 Mon Sep 17 00:00:00 2001 From: Thykof Date: Mon, 4 Apr 2016 16:32:17 +0200 Subject: [PATCH 16/22] Improve about --- interface/dialog.py | 1 + interface/tools.py | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/interface/dialog.py b/interface/dialog.py index a690cea..86e6637 100644 --- a/interface/dialog.py +++ b/interface/dialog.py @@ -23,6 +23,7 @@ def __init__(self, parent): self.set_border_width(10) self.connect('delete-event', self.close) box = self.get_content_area() + box.set_spacing(6) box_time = self.create_box_time() box_ext = self.create_box_ext() diff --git a/interface/tools.py b/interface/tools.py index af8f779..4eb30c9 100644 --- a/interface/tools.py +++ b/interface/tools.py @@ -6,16 +6,20 @@ from gi.repository import Gtk def about(parent): - dialog = Gtk.AboutDialog(transient_for=parent) - dialog.set_program_name('SafeMyWork') - dialog.set_version('1.0') - dialog.set_website('https://github.com/Thykof/SafeMyWork') - dialog.set_authors(['Nathan Seva']) - dialog.set_comments('Utilitaire SafeMyWork') - dialog.set_license('SafeMyWork est sous la license GNU GPL(v3). \n\n https://github.com/Thykof/SafeMyWork/blob/master/LICENSE') + aboutdialog = Gtk.AboutDialog(transient_for=parent) + aboutdialog.set_program_name('SafeMyWork') + aboutdialog.set_version('1.0') + aboutdialog.set_website('https://github.com/Thykof/SafeMyWork') + aboutdialog.set_website_label("Github") + aboutdialog.set_authors(['Nathan Seva']) + aboutdialog.set_comments('Utilitaire SafeMyWork') + aboutdialog.set_license('SafeMyWork est sous la license GNU GPL(v3). \n\n https://github.com/Thykof/SafeMyWork/blob/master/LICENSE') - dialog.run() - dialog.destroy() + aboutdialog.connect("response", on_close_dialog) + aboutdialog.show() + +def on_close_dialog(action, parameter): + action.destroy() class MainGrid(Gtk.Grid): """docstring for Grid""" From 7858e7766170d952b7b50df8b5c03bbd9dfb6cc2 Mon Sep 17 00:00:00 2001 From: Thykof Date: Mon, 4 Apr 2016 16:41:54 +0200 Subject: [PATCH 17/22] Fix main.py ui import --- main.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/main.py b/main.py index 3ea723b..45b9d83 100644 --- a/main.py +++ b/main.py @@ -28,11 +28,7 @@ def do_startup(self): self.add_action(quit_action) builder = Gtk.Builder() - try: - builder.add_from_file('interface/menubar.ui') - except: - from interface.menubar_ui import UI_INFO - builder.add_from_string(UI_INFO) + builder.add_from_file('interface/menubar.ui') self.set_menubar(builder.get_object('menubar')) From 9a65d2a54ba4b4e9d0af8dda98b7d0f931769a05 Mon Sep 17 00:00:00 2001 From: Thykof Date: Sun, 19 Feb 2017 16:03:37 +0100 Subject: [PATCH 18/22] New way of save files --- watcher/safe.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 watcher/safe.py diff --git a/watcher/safe.py b/watcher/safe.py new file mode 100644 index 0000000..2e3e63c --- /dev/null +++ b/watcher/safe.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/python3 + +from shutil import copytree +from os import path, listdir, mkdir + +class Safer(object): + """Manage the creation of the duplicate directory of the folder placed under supervision.""" + def __init__(self, delicate_dirs, destination): + super(Safer, self).__init__() + self.delicate_dirs = delicate_dirs # List of different directories placed under supervision + self.destination = destination + if not path.exists(self.destination): + mkdir(self.destination) + + def start(self): + for directory in self.delicate_dirs: # Save files from all delicate directories + root_destination = path.join(self.destination, directory) + if not path.exists(root_destination): + mkdir(path.join(self.destination, directory)) + list_version = list() + for directory_version in listdir(root_destination): + list_version.append(int(directory_version.split('V--')[1])) + if list_version == []: + version = '1' + else: + version = str(max(list_version) + 1) + destination = path.join(self.destination, directory, directory + 'V--' + version) + copytree(directory, destination) \ No newline at end of file From a2f12d78d4e16f67d2ad694dfd935cbf131d9095 Mon Sep 17 00:00:00 2001 From: Thykof Date: Fri, 24 Feb 2017 18:02:08 +0100 Subject: [PATCH 19/22] Add a label in settings box --- interface/dialog.py | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/dialog.py b/interface/dialog.py index 86e6637..c7c6a5d 100644 --- a/interface/dialog.py +++ b/interface/dialog.py @@ -108,6 +108,7 @@ def create_box_dirs(self): def create_box_archive_dir(self): # Archive directory: box_archive_dir = Gtk.Box(spacing=6) + box_files.pack_start(Gtk.Label('Dossier archive : '), False, False, 0) self.archive_entry = Gtk.Entry() self.archive_entry.set_text(self.parent.config['archive_dir']) archive_button = Gtk.Button.new_with_label('Changer') From 56692d2dad1785e418e193cd190149354db371e1 Mon Sep 17 00:00:00 2001 From: Thykof Date: Fri, 24 Feb 2017 18:04:46 +0100 Subject: [PATCH 20/22] Change var name --- interface/tools.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/interface/tools.py b/interface/tools.py index 4eb30c9..b500e77 100644 --- a/interface/tools.py +++ b/interface/tools.py @@ -6,17 +6,17 @@ from gi.repository import Gtk def about(parent): - aboutdialog = Gtk.AboutDialog(transient_for=parent) - aboutdialog.set_program_name('SafeMyWork') - aboutdialog.set_version('1.0') - aboutdialog.set_website('https://github.com/Thykof/SafeMyWork') - aboutdialog.set_website_label("Github") - aboutdialog.set_authors(['Nathan Seva']) - aboutdialog.set_comments('Utilitaire SafeMyWork') - aboutdialog.set_license('SafeMyWork est sous la license GNU GPL(v3). \n\n https://github.com/Thykof/SafeMyWork/blob/master/LICENSE') + about_dialog = Gtk.about_dialog(transient_for=parent) + about_dialog.set_program_name('SafeMyWork') + about_dialog.set_version('1.0') + about_dialog.set_website('https://github.com/Thykof/SafeMyWork') + about_dialog.set_website_label("Github") + about_dialog.set_authors(['Nathan Seva']) + about_dialog.set_comments('Utilitaire SafeMyWork') + about_dialog.set_license('SafeMyWork est sous la license GNU GPL(v3). \n\n https://github.com/Thykof/SafeMyWork/blob/master/LICENSE') - aboutdialog.connect("response", on_close_dialog) - aboutdialog.show() + about_dialog.connect("response", on_close_dialog) + about_dialog.show() def on_close_dialog(action, parameter): action.destroy() From 662d6c0e0998275758418ded0397ab4cc1ab5a77 Mon Sep 17 00:00:00 2001 From: Thykof Date: Sat, 25 Feb 2017 08:51:12 +0100 Subject: [PATCH 21/22] Fix varname in setting --- interface/dialog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/dialog.py b/interface/dialog.py index c7c6a5d..3520171 100644 --- a/interface/dialog.py +++ b/interface/dialog.py @@ -108,7 +108,7 @@ def create_box_dirs(self): def create_box_archive_dir(self): # Archive directory: box_archive_dir = Gtk.Box(spacing=6) - box_files.pack_start(Gtk.Label('Dossier archive : '), False, False, 0) + box_archive_dir.pack_start(Gtk.Label('Dossier archive : '), False, False, 0) self.archive_entry = Gtk.Entry() self.archive_entry.set_text(self.parent.config['archive_dir']) archive_button = Gtk.Button.new_with_label('Changer') From c6451f28d690e385b759768905b1737b8c22b3bd Mon Sep 17 00:00:00 2001 From: Thykof Date: Sat, 25 Feb 2017 08:51:39 +0100 Subject: [PATCH 22/22] Fix about dialog --- interface/tools.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/interface/tools.py b/interface/tools.py index b500e77..ed936aa 100644 --- a/interface/tools.py +++ b/interface/tools.py @@ -6,7 +6,7 @@ from gi.repository import Gtk def about(parent): - about_dialog = Gtk.about_dialog(transient_for=parent) + about_dialog = Gtk.AboutDialog(transient_for=parent) about_dialog.set_program_name('SafeMyWork') about_dialog.set_version('1.0') about_dialog.set_website('https://github.com/Thykof/SafeMyWork') @@ -15,11 +15,8 @@ def about(parent): about_dialog.set_comments('Utilitaire SafeMyWork') about_dialog.set_license('SafeMyWork est sous la license GNU GPL(v3). \n\n https://github.com/Thykof/SafeMyWork/blob/master/LICENSE') - about_dialog.connect("response", on_close_dialog) - about_dialog.show() - -def on_close_dialog(action, parameter): - action.destroy() + about_dialog.run() + about_dialog.destroy() class MainGrid(Gtk.Grid): """docstring for Grid"""