mirror of
https://github.com/c9moser/sgbackup.git
synced 2026-01-19 19:40:13 +00:00
2025.01.13 02:08:06
This commit is contained in:
parent
538f70c8b8
commit
a63453fd87
28
sgbackup/archiver/__init__.py
Normal file
28
sgbackup/archiver/__init__.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
###############################################################################
|
||||||
|
# sgbackup - The SaveGame Backup tool #
|
||||||
|
# Copyright (C) 2024 Christian Moser #
|
||||||
|
# #
|
||||||
|
# This program is free software: you can redistribute it and/or modify #
|
||||||
|
# it under the terms of the GNU General Public License as published by #
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, #
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||||
|
# GNU General Public License for more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License #
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
from ._archiver import Archiver,ArchiverManager
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
archiver = ArchiverManager()
|
||||||
|
|
||||||
|
__ALL__ = [
|
||||||
|
"Archiver",
|
||||||
|
"AchiverManager",
|
||||||
|
"archiver",
|
||||||
|
]
|
||||||
@ -24,7 +24,11 @@ from gi.repository.GObject import (
|
|||||||
signal_accumulator_true_handled,
|
signal_accumulator_true_handled,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .game import Game
|
import datetime
|
||||||
|
import os
|
||||||
|
|
||||||
|
from ..game import Game
|
||||||
|
from ..settings import settings
|
||||||
|
|
||||||
class Archiver:
|
class Archiver:
|
||||||
def __init__(self,key:str,name:str,extensions:list[str],decription:str|None=None):
|
def __init__(self,key:str,name:str,extensions:list[str],decription:str|None=None):
|
||||||
@ -35,6 +39,8 @@ class Archiver:
|
|||||||
else:
|
else:
|
||||||
self.__description = ""
|
self.__description = ""
|
||||||
|
|
||||||
|
self.__extensions = list(extensions)
|
||||||
|
|
||||||
@Property(type=str)
|
@Property(type=str)
|
||||||
def name(self)->str:
|
def name(self)->str:
|
||||||
return self.__name
|
return self.__name
|
||||||
@ -47,20 +53,68 @@ class Archiver:
|
|||||||
def description(self)->str:
|
def description(self)->str:
|
||||||
return self.__description
|
return self.__description
|
||||||
|
|
||||||
def backup(self,game)->bool:
|
@Property
|
||||||
pass
|
def extensions(self)->list[str]:
|
||||||
|
return self.__extensions
|
||||||
|
|
||||||
|
def backup(self,game:Game)->bool:
|
||||||
|
if not game.get_backup_files():
|
||||||
|
return
|
||||||
|
filename = self.generate_new_backup_filename()
|
||||||
|
dirname = os.path.dirname(filename)
|
||||||
|
if not os.path.isdir(dirname):
|
||||||
|
os.makedirs(dirname)
|
||||||
|
|
||||||
|
self.emit('backup',game,filename)
|
||||||
|
|
||||||
def restore(self,game,file)->bool:
|
def restore(self,game,file)->bool:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def generate_new_backup_filename(self,game:Game)->str:
|
||||||
|
dt = datetime.datetime.now()
|
||||||
|
basename = '.'.join(game.savegame_name,
|
||||||
|
game.savegame_subdir,
|
||||||
|
dt.strftime("%Y%m%d-%H%M%S"),
|
||||||
|
"sgbackup",
|
||||||
|
self.extensions[0])
|
||||||
|
return os.path.join(settings.backup_dir,game.savegame_name,game.subdir,basename)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Signal(name="backup",flags=SignalFlags.RUN_FIRST,
|
@Signal(name="backup",flags=SignalFlags.RUN_FIRST,
|
||||||
return_type=bool, arg_types=(GObject,str),
|
return_type=bool, arg_types=(GObject,str),
|
||||||
accumulator=signal_accumulator_true_handled)
|
accumulator=signal_accumulator_true_handled)
|
||||||
def do_backup(self,game:Game,filename:str):
|
def do_backup(self,game:Game,filename:str):
|
||||||
pass
|
raise NotImplementedError("{_class}.{function}() is not implemented!",_class=__class__,function="do_backup")
|
||||||
|
|
||||||
@Signal(name="restore",flags=SignalFlags.RUN_FIRST,
|
@Signal(name="restore",flags=SignalFlags.RUN_FIRST,
|
||||||
return_type=bool,arg_types=(GObject,str),
|
return_type=bool,arg_types=(str,),
|
||||||
accumulator=signal_accumulator_true_handled)
|
accumulator=signal_accumulator_true_handled)
|
||||||
def do_backup(self,game:Game,filanme:str):
|
def do_restore(self,filanme:str):
|
||||||
pass
|
raise NotImplementedError("{_class}.{function}() is not implemented!",_class=__class__,function="do_restore")
|
||||||
|
|
||||||
|
class ArchiverManager(GObject):
|
||||||
|
__global_archiver_manager = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
GObject.__init__(self)
|
||||||
|
self.__archivers = {}
|
||||||
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_global():
|
||||||
|
if ArchiverManager.__global_archiver_manager is None:
|
||||||
|
ArchiverManager.__global_archiver_manager = ArchiverManager()
|
||||||
|
|
||||||
|
return ArchiverManager.__global_archiver_manager
|
||||||
|
|
||||||
|
@property
|
||||||
|
def standard_archiver(self)->Archiver:
|
||||||
|
try:
|
||||||
|
return self.__archivers[settings.archiver]
|
||||||
|
except:
|
||||||
|
return self.__archivers["zipfile"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
71
sgbackup/archiver/zipfilearchiver.py
Normal file
71
sgbackup/archiver/zipfilearchiver.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
###############################################################################
|
||||||
|
# sgbackup - The SaveGame Backup tool #
|
||||||
|
# Copyright (C) 2024 Christian Moser #
|
||||||
|
# #
|
||||||
|
# This program is free software: you can redistribute it and/or modify #
|
||||||
|
# it under the terms of the GNU General Public License as published by #
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, #
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||||
|
# GNU General Public License for more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License #
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
from ._archiver import Archiver
|
||||||
|
import zipfile
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from ..game import Game,GameManager
|
||||||
|
from settings import settings
|
||||||
|
|
||||||
|
class ZipfileArchiver(Archiver):
|
||||||
|
def __init__(self):
|
||||||
|
Archiver.__init__(self,"zipfile","ZipFile",[".zip"],"Archiver for .zip files.")
|
||||||
|
|
||||||
|
def do_backup(self, game:Game, filename:str):
|
||||||
|
files = game.get_backup_files()
|
||||||
|
game_data = json.dumps(game.serialize(),ensure_ascii=False,indent=4)
|
||||||
|
with zipfile.ZipFile(filename,mode="w",
|
||||||
|
compression=settings.zipfile_compression,
|
||||||
|
compresslevel=settings.zipfile_compresslevel) as zf:
|
||||||
|
zf.writestr("game.conf",game_data)
|
||||||
|
for path,arcname in files.items():
|
||||||
|
zf.write(path,arcname)
|
||||||
|
|
||||||
|
def is_archive(self,filename:str)->bool:
|
||||||
|
if zipfile.is_zipfile(filename):
|
||||||
|
with zipfile.ZipFile(filename,"r") as zf:
|
||||||
|
if 'game.conf' in zf.filelist():
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def do_restore(self,filename:str):
|
||||||
|
# TODO: convert savegame dir if not the same SvaegameType!!!
|
||||||
|
|
||||||
|
if not zipfile.is_zipfile(filename):
|
||||||
|
raise RuntimeError("\"{filename}\" is not a valid sgbackup zipfile archive!")
|
||||||
|
|
||||||
|
with zipfile.ZipFile(filename,"r") as zf:
|
||||||
|
zip_game = Game.new_from_dict(json.loads(zf.read('game.conf').decode("utf-8")))
|
||||||
|
try:
|
||||||
|
game = GameManager.get_global().games[zip_game.key]
|
||||||
|
except:
|
||||||
|
game = zip_game
|
||||||
|
|
||||||
|
if not game.savegame_root:
|
||||||
|
os.makedirs(game.savegame_root)
|
||||||
|
|
||||||
|
extract_files = [i for i in zf.filelist if i.startswith(zip_game.savegame_dir + "/")]
|
||||||
|
for file in extract_files:
|
||||||
|
zf.extract(file,game.savegame_root)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
ARCHIVERS = [
|
||||||
|
ZipfileArchiver(),
|
||||||
|
]
|
||||||
@ -19,6 +19,7 @@
|
|||||||
from gi.repository.GObject import Property,GObject,Signal,SignalFlags
|
from gi.repository.GObject import Property,GObject,Signal,SignalFlags
|
||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
@ -28,6 +29,7 @@ from enum import StrEnum
|
|||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
import pathlib
|
import pathlib
|
||||||
|
import datetime
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -1303,6 +1305,19 @@ class Game(GObject):
|
|||||||
|
|
||||||
backup_files = get_backup_files_recursive(sgroot,sgdir)
|
backup_files = get_backup_files_recursive(sgroot,sgdir)
|
||||||
|
|
||||||
|
@Property(type=str)
|
||||||
|
def savegame_subdir(self)->str:
|
||||||
|
"""
|
||||||
|
savegame_subdir The subdir for the savegame backup.
|
||||||
|
|
||||||
|
If `is_live` results to `True`, *"live"* is returned. Else *"finished"* is returned.
|
||||||
|
|
||||||
|
:type: str
|
||||||
|
"""
|
||||||
|
if (self.is_live):
|
||||||
|
return "live"
|
||||||
|
return "finished"
|
||||||
|
|
||||||
|
|
||||||
class GameManager(GObject):
|
class GameManager(GObject):
|
||||||
__global_gamemanager = None
|
__global_gamemanager = None
|
||||||
@ -1379,3 +1394,4 @@ class GameManager(GObject):
|
|||||||
if (game.steam_windows):
|
if (game.steam_windows):
|
||||||
self.__steam_games[game.steam_windows.appid] = game
|
self.__steam_games[game.steam_windows.appid] = game
|
||||||
self.__steam_windows_games[game.steam_windows.appid] = game
|
self.__steam_windows_games[game.steam_windows.appid] = game
|
||||||
|
|
||||||
|
|||||||
@ -200,6 +200,10 @@ class GameView(Gtk.ScrolledWindow):
|
|||||||
# GameView class
|
# GameView class
|
||||||
|
|
||||||
class BackupViewData(GObject):
|
class BackupViewData(GObject):
|
||||||
|
"""
|
||||||
|
BackupViewData The data class for BackupView
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self,_game:Game,filename:str):
|
def __init__(self,_game:Game,filename:str):
|
||||||
GObject.GObject.__init__(self)
|
GObject.GObject.__init__(self)
|
||||||
self.__game = _game
|
self.__game = _game
|
||||||
@ -215,34 +219,75 @@ class BackupViewData(GObject):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def game(self)->Game:
|
def game(self)->Game:
|
||||||
|
"""
|
||||||
|
game The `Game` the data belong to
|
||||||
|
|
||||||
|
:type: Game
|
||||||
|
"""
|
||||||
return self.__game
|
return self.__game
|
||||||
|
|
||||||
@Property
|
@Property(type=str)
|
||||||
def savegame_name(self):
|
def savegame_name(self)->str:
|
||||||
|
"""
|
||||||
|
savegame_name The savegame_name of the file.
|
||||||
|
|
||||||
|
:type: str
|
||||||
|
"""
|
||||||
return self.__savegame_name
|
return self.__savegame_name
|
||||||
|
|
||||||
@Property(type=str)
|
@Property(type=str)
|
||||||
def filename(self)->str:
|
def filename(self)->str:
|
||||||
|
"""
|
||||||
|
filename The full filename of the savegame backup.
|
||||||
|
|
||||||
|
:type: str
|
||||||
|
"""
|
||||||
return self.__filename
|
return self.__filename
|
||||||
|
|
||||||
@Property(type=bool,default=False)
|
@Property(type=bool,default=False)
|
||||||
def is_live(self)->bool:
|
def is_live(self)->bool:
|
||||||
|
"""
|
||||||
|
is_live `True` if the savegame backup is from a live game.
|
||||||
|
|
||||||
|
:type: bool
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@Property
|
@Property(type=str)
|
||||||
def extension(self):
|
def extension(self)->str:
|
||||||
|
"""
|
||||||
|
extension The extension of the file.
|
||||||
|
|
||||||
|
:type: str
|
||||||
|
"""
|
||||||
return self.__extension
|
return self.__extension
|
||||||
|
|
||||||
@Property
|
@Property
|
||||||
def timestamp(self):
|
def timestamp(self)->DateTime:
|
||||||
|
"""
|
||||||
|
timestamp The timestamp of the file.
|
||||||
|
|
||||||
|
DateTime is the alias for `datetime.datetime`.
|
||||||
|
|
||||||
|
:type: DateTime
|
||||||
|
"""
|
||||||
return self.__timestamp
|
return self.__timestamp
|
||||||
|
|
||||||
def _on_selection_changed(self,selection):
|
def _on_selection_changed(self,selection):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class BackupView(Gtk.ScrolledWindow):
|
class BackupView(Gtk.ScrolledWindow):
|
||||||
|
"""
|
||||||
|
BackupView This view displays the backup for the selected `Game`.
|
||||||
|
"""
|
||||||
__gtype_name__ = "BackupView"
|
__gtype_name__ = "BackupView"
|
||||||
def __init__(self,gameview:GameView):
|
def __init__(self,gameview:GameView):
|
||||||
|
"""
|
||||||
|
BackupView
|
||||||
|
|
||||||
|
:param gameview: The `GameView` to connect this class to.
|
||||||
|
:type gameview: GameView
|
||||||
|
"""
|
||||||
Gtk.ScrolledWindow.__init__(self)
|
Gtk.ScrolledWindow.__init__(self)
|
||||||
self.__gameview = gameview
|
self.__gameview = gameview
|
||||||
|
|
||||||
@ -277,6 +322,11 @@ class BackupView(Gtk.ScrolledWindow):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def gameview(self)->GameView:
|
def gameview(self)->GameView:
|
||||||
|
"""
|
||||||
|
gameview The GameView this class is connected to.
|
||||||
|
|
||||||
|
:type: GameView
|
||||||
|
"""
|
||||||
return self.__gameview
|
return self.__gameview
|
||||||
|
|
||||||
def _on_live_column_setup(self,factory,item):
|
def _on_live_column_setup(self,factory,item):
|
||||||
@ -338,8 +388,17 @@ class BackupView(Gtk.ScrolledWindow):
|
|||||||
|
|
||||||
|
|
||||||
class AppWindow(Gtk.ApplicationWindow):
|
class AppWindow(Gtk.ApplicationWindow):
|
||||||
|
"""
|
||||||
|
AppWindow The applications main window.
|
||||||
|
"""
|
||||||
__gtype_name__ = "AppWindow"
|
__gtype_name__ = "AppWindow"
|
||||||
def __init__(self,application=None,**kwargs):
|
def __init__(self,application=None,**kwargs):
|
||||||
|
"""
|
||||||
|
AppWindow
|
||||||
|
|
||||||
|
:param application: The `Application` this window belongs to, defaults to `None`.
|
||||||
|
:type application: Application, optional
|
||||||
|
"""
|
||||||
kwargs['title'] = "SGBackup"
|
kwargs['title'] = "SGBackup"
|
||||||
|
|
||||||
if (application is not None):
|
if (application is not None):
|
||||||
@ -389,18 +448,39 @@ class AppWindow(Gtk.ApplicationWindow):
|
|||||||
self.set_child(vbox)
|
self.set_child(vbox)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def builder(self):
|
def builder(self)->Gtk.Builder:
|
||||||
|
"""
|
||||||
|
builder The Builder for this Window.
|
||||||
|
|
||||||
|
If application is set and it has an attriubte *builder*, The applications builder
|
||||||
|
is used else a new `Gtk.Builder` instance is created.
|
||||||
|
|
||||||
|
:type: Gtk.Builder
|
||||||
|
"""
|
||||||
return self.__builder
|
return self.__builder
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def backupview(self):
|
def backupview(self)->BackupView:
|
||||||
|
"""
|
||||||
|
backupview The `BackupView` of this window.
|
||||||
|
|
||||||
|
:type: BackupView
|
||||||
|
"""
|
||||||
return self.__backupview
|
return self.__backupview
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def gameview(self):
|
def gameview(self)->GameView:
|
||||||
|
"""
|
||||||
|
gameview The `GameView` for this window.
|
||||||
|
|
||||||
|
:type: GameView
|
||||||
|
"""
|
||||||
return self.__gameview
|
return self.__gameview
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
|
"""
|
||||||
|
refresh Refresh the views of this window.
|
||||||
|
"""
|
||||||
self.gameview.refresh()
|
self.gameview.refresh()
|
||||||
#self.backupview.refresh()
|
#self.backupview.refresh()
|
||||||
|
|
||||||
@ -411,7 +491,7 @@ class Application(Gtk.Application):
|
|||||||
Signals
|
Signals
|
||||||
_______
|
_______
|
||||||
|
|
||||||
+ `settings-dialog-init`
|
+ **settings-dialog-init** - Called when the application creates a new `SettingsDialog`.
|
||||||
"""
|
"""
|
||||||
__gtype_name__ = "Application"
|
__gtype_name__ = "Application"
|
||||||
|
|
||||||
@ -433,10 +513,18 @@ class Application(Gtk.Application):
|
|||||||
return self.__logger
|
return self.__logger
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def appwindow(self):
|
def appwindow(self)->AppWindow:
|
||||||
|
"""
|
||||||
|
appwindow The main `AppWindow` of this app.
|
||||||
|
|
||||||
|
:type: AppWindow
|
||||||
|
"""
|
||||||
return self.__appwindow
|
return self.__appwindow
|
||||||
|
|
||||||
def do_startup(self):
|
def do_startup(self):
|
||||||
|
"""
|
||||||
|
do_startup The startup method for this application.
|
||||||
|
"""
|
||||||
self._logger.debug('do_startup()')
|
self._logger.debug('do_startup()')
|
||||||
if not self.__builder:
|
if not self.__builder:
|
||||||
self.__builder = Gtk.Builder.new()
|
self.__builder = Gtk.Builder.new()
|
||||||
@ -451,29 +539,37 @@ class Application(Gtk.Application):
|
|||||||
theme.add_search_path(str(icons_path))
|
theme.add_search_path(str(icons_path))
|
||||||
|
|
||||||
action_about = Gio.SimpleAction.new('about',None)
|
action_about = Gio.SimpleAction.new('about',None)
|
||||||
action_about.connect('activate',self.on_action_about)
|
action_about.connect('activate',self._on_action_about)
|
||||||
self.add_action(action_about)
|
self.add_action(action_about)
|
||||||
|
|
||||||
action_new_game = Gio.SimpleAction.new('new-game',None)
|
action_new_game = Gio.SimpleAction.new('new-game',None)
|
||||||
action_new_game.connect('activate',self.on_action_new_game)
|
action_new_game.connect('activate',self._on_action_new_game)
|
||||||
self.add_action(action_new_game)
|
self.add_action(action_new_game)
|
||||||
|
|
||||||
action_quit = Gio.SimpleAction.new('quit',None)
|
action_quit = Gio.SimpleAction.new('quit',None)
|
||||||
action_quit.connect('activate',self.on_action_quit)
|
action_quit.connect('activate',self._on_action_quit)
|
||||||
self.add_action(action_quit)
|
self.add_action(action_quit)
|
||||||
|
|
||||||
action_settings = Gio.SimpleAction.new('settings',None)
|
action_settings = Gio.SimpleAction.new('settings',None)
|
||||||
action_settings.connect('activate',self.on_action_settings)
|
action_settings.connect('activate',self._on_action_settings)
|
||||||
self.add_action(action_settings)
|
self.add_action(action_settings)
|
||||||
|
|
||||||
# add accels
|
# add accels
|
||||||
self.set_accels_for_action('app.quit',["<Primary>q"])
|
self.set_accels_for_action('app.quit',["<Primary>q"])
|
||||||
|
|
||||||
@Property
|
@property
|
||||||
def builder(self):
|
def builder(self)->Gtk.Builder:
|
||||||
|
"""
|
||||||
|
builder Get the builder for the application.
|
||||||
|
|
||||||
|
:type: Gtk.Builder
|
||||||
|
"""
|
||||||
return self.__builder
|
return self.__builder
|
||||||
|
|
||||||
def do_activate(self):
|
def do_activate(self):
|
||||||
|
"""
|
||||||
|
do_activate This method is called, when the application is activated.
|
||||||
|
"""
|
||||||
self._logger.debug('do_activate()')
|
self._logger.debug('do_activate()')
|
||||||
if not (self.__appwindow):
|
if not (self.__appwindow):
|
||||||
self.__appwindow = AppWindow(application=self)
|
self.__appwindow = AppWindow(application=self)
|
||||||
@ -481,28 +577,34 @@ class Application(Gtk.Application):
|
|||||||
|
|
||||||
self.appwindow.present()
|
self.appwindow.present()
|
||||||
|
|
||||||
def on_action_about(self,action,param):
|
def _on_action_about(self,action,param):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_action_settings(self,action,param):
|
def _on_action_settings(self,action,param):
|
||||||
dialog = self.new_settings_dialog()
|
dialog = self.new_settings_dialog()
|
||||||
dialog.present()
|
dialog.present()
|
||||||
|
|
||||||
def on_action_quit(self,action,param):
|
def _on_action_quit(self,action,param):
|
||||||
self.quit()
|
self.quit()
|
||||||
|
|
||||||
def _on_dialog_response_refresh(self,dialog,response,check_response):
|
def _on_dialog_response_refresh(self,dialog,response,check_response):
|
||||||
if response == check_response:
|
if response == check_response:
|
||||||
self.appwindow.refresh()
|
self.appwindow.refresh()
|
||||||
|
|
||||||
def on_action_new_game(self,action,param):
|
def _on_action_new_game(self,action,param):
|
||||||
dialog = GameDialog(self.appwindow)
|
dialog = GameDialog(self.appwindow)
|
||||||
dialog.connect('response',
|
dialog.connect('response',
|
||||||
self._on_dialog_response_refresh,
|
self._on_dialog_response_refresh,
|
||||||
Gtk.ResponseType.APPLY)
|
Gtk.ResponseType.APPLY)
|
||||||
dialog.present()
|
dialog.present()
|
||||||
|
|
||||||
def new_settings_dialog(self):
|
def new_settings_dialog(self)->SettingsDialog:
|
||||||
|
"""
|
||||||
|
new_settings_dialog Create a new `SettingsDialog`.
|
||||||
|
|
||||||
|
:return: The new dialog.
|
||||||
|
:rtype: `SettingsDialog`
|
||||||
|
"""
|
||||||
dialog = SettingsDialog(self.appwindow)
|
dialog = SettingsDialog(self.appwindow)
|
||||||
self.emit('settings-dialog-init',dialog)
|
self.emit('settings-dialog-init',dialog)
|
||||||
return dialog
|
return dialog
|
||||||
@ -511,6 +613,14 @@ class Application(Gtk.Application):
|
|||||||
flags=SignalFlags.RUN_LAST,
|
flags=SignalFlags.RUN_LAST,
|
||||||
return_type=None,
|
return_type=None,
|
||||||
arg_types=(SettingsDialog,))
|
arg_types=(SettingsDialog,))
|
||||||
def do_settings_dialog_init(self,dialog):
|
def do_settings_dialog_init(self,dialog:SettingsDialog):
|
||||||
|
"""
|
||||||
|
do_settings_dialog_init The **settings-dialog-init** signal callback for initializing the `SettingsDialog`.
|
||||||
|
|
||||||
|
This signal is ment to add pages to the `SettingsDialog`.
|
||||||
|
|
||||||
|
:param dialog: The dialog to initialize.
|
||||||
|
:type dialog: SettingsDialog
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
from gi.repository import Gtk,GLib,Gio
|
from gi.repository import Gtk,GLib,Gio
|
||||||
from gi.repository.GObject import GObject,Signal,Property
|
from gi.repository.GObject import GObject,Signal,Property,SignalFlags
|
||||||
|
|
||||||
from ..settings import settings
|
from ..settings import settings
|
||||||
|
|
||||||
@ -81,7 +81,6 @@ class SettingsDialog(Gtk.Dialog):
|
|||||||
dialog.select_folder(self,None,self._on_backupdir_dialog_select_folder)
|
dialog.select_folder(self,None,self._on_backupdir_dialog_select_folder)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_page(self,page,name,title):
|
def add_page(self,page,name,title):
|
||||||
self.__stack.add_titled(page,name,title)
|
self.__stack.add_titled(page,name,title)
|
||||||
|
|
||||||
@ -91,7 +90,10 @@ class SettingsDialog(Gtk.Dialog):
|
|||||||
settings.save()
|
settings.save()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
@Signal(name='save')
|
@Signal(name='save',
|
||||||
|
flags=SignalFlags.RUN_FIRST,
|
||||||
|
return_type=None,
|
||||||
|
arg_types=())
|
||||||
def do_save(self):
|
def do_save(self):
|
||||||
settings.backup_dir = self.__backupdir_label.get_text()
|
settings.backup_dir = self.__backupdir_label.get_text()
|
||||||
|
|
||||||
@ -21,6 +21,27 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from gi.repository import GLib,GObject
|
from gi.repository import GLib,GObject
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
ZIPFILE_COMPRESSION_STR = {
|
||||||
|
zipfile.ZIP_STORED: "stored",
|
||||||
|
zipfile.ZIP_DEFLATED: "deflated",
|
||||||
|
zipfile.ZIP_BZIP2: "bzip2",
|
||||||
|
zipfile.ZIP_LZMA: "lzma",
|
||||||
|
}
|
||||||
|
|
||||||
|
ZIPFILE_COMPRESSLEVEL_MAX = {
|
||||||
|
zipfile.ZIP_STORED: 0,
|
||||||
|
zipfile.ZIP_DEFLATED: 9,
|
||||||
|
zipfile.ZIP_BZIP2: 9,
|
||||||
|
zipfile.ZIP_LZMA: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
ZIPFILE_STR_COMPRESSION = {}
|
||||||
|
for _zc,_zs in ZIPFILE_COMPRESSION_STR.items():
|
||||||
|
ZIPFILE_STR_COMPRESSION[_zs] = _zc
|
||||||
|
del _zc
|
||||||
|
del _zs
|
||||||
|
|
||||||
class Settings(GObject.GObject):
|
class Settings(GObject.GObject):
|
||||||
__gtype_name__ = "Settings"
|
__gtype_name__ = "Settings"
|
||||||
@ -84,6 +105,33 @@ class Settings(GObject.GObject):
|
|||||||
return self.parser.get('sgbackup','logLevel')
|
return self.parser.get('sgbackup','logLevel')
|
||||||
return "INFO"
|
return "INFO"
|
||||||
|
|
||||||
|
@GObject.Property(type=str)
|
||||||
|
def zipfile_compression(self)->str:
|
||||||
|
if self.parser.has_option('zipfile','compression'):
|
||||||
|
try:
|
||||||
|
ZIPFILE_STR_COMPRESSION[self.parser.get('zipfile','compression')]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return ZIPFILE_STR_COMPRESSION["deflated"]
|
||||||
|
|
||||||
|
@zipfile_compression.setter
|
||||||
|
def zipfile_compression(self,compression):
|
||||||
|
try:
|
||||||
|
self.parser.set('zipfile','compression',ZIPFILE_COMPRESSION_STR[compression])
|
||||||
|
except:
|
||||||
|
self.parser.set('zipfile','compression',ZIPFILE_STR_COMPRESSION[zipfile.ZIP_DEFLATED])
|
||||||
|
|
||||||
|
@GObject.Property(type=int)
|
||||||
|
def zipfile_compresslevel(self)->int:
|
||||||
|
if self.parser.has_option('zipfile','compressLevel'):
|
||||||
|
cl = self.parser.getint('zipfile','compressLevel')
|
||||||
|
return cl if cl <= ZIPFILE_COMPRESSLEVEL_MAX[self.zipfile_compression] else ZIPFILE_COMPRESSLEVEL_MAX[self.zipfile_compression]
|
||||||
|
return ZIPFILE_COMPRESSLEVEL_MAX[self.zipfile_compression]
|
||||||
|
|
||||||
|
@zipfile_compresslevel.setter
|
||||||
|
def zipfile_compresslevel(self,cl:int):
|
||||||
|
self.parser.set('zipfile','compressLevel',cl)
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
self.emit('save')
|
self.emit('save')
|
||||||
|
|
||||||
|
|||||||
@ -5,5 +5,4 @@ Applicaction
|
|||||||
.. autoclass:: sgbackup.gui.Application
|
.. autoclass:: sgbackup.gui.Application
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user