2025.01.16 04:25:45

This commit is contained in:
Christian Moser 2025-01-16 04:25:46 +01:00
parent 39e9201539
commit 391b42f3bb
Failed to extract signature
5 changed files with 206 additions and 240 deletions

View File

@ -16,8 +16,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # # along with this program. If not, see <https://www.gnu.org/licenses/>. #
############################################################################### ###############################################################################
import gi from . import _import_gtk
gi.require_version('Gtk','4.0')
__version__ = "0.0.1" __version__ = "0.0.1"
from .settings import settings from .settings import settings

23
sgbackup/_import_gtk.py Normal file
View File

@ -0,0 +1,23 @@
###############################################################################
# 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/>. #
###############################################################################
_GTK_IMPORTED_ = False
if not _GTK_IMPORTED_:
import gi; gi.require_version("Gtk","4.0")
_GTK_IMPORTED_ = True

View File

@ -16,6 +16,8 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # # along with this program. If not, see <https://www.gnu.org/licenses/>. #
############################################################################### ###############################################################################
from . import _import_gtk
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
@ -281,19 +283,12 @@ class GameData(GObject):
self.__savegame_root = savegame_root self.__savegame_root = savegame_root
self.__savegame_dir = savegame_dir self.__savegame_dir = savegame_dir
self.__variables = {} self.__variables = {}
self.__filematchers = [] self.file_matchers = file_match
self.__ignorematchers = [] self.ignore_matchers = ignore_match
if variables is not None: if variables is not None:
variables.update(variables) variables.update(variables)
if file_match is not None:
for fm in file_match:
self.add_file_match(fm)
if ignore_match is not None:
for fm in ignore_match:
self.add_ignore_match(fm)
@Property @Property
def savegame_type(self)->SavegameType: def savegame_type(self)->SavegameType:
@ -346,9 +341,8 @@ class GameData(GObject):
@file_matchers.setter @file_matchers.setter
def file_matchers(self,fm:list[GameFileMatcher]|None): def file_matchers(self,fm:list[GameFileMatcher]|None):
if not fm:
self.__filematchers = [] self.__filematchers = []
else: if fm:
for matcher in fm: for matcher in fm:
if not isinstance(matcher,GameFileMatcher): if not isinstance(matcher,GameFileMatcher):
raise TypeError("\"file_match\" needs to be \"None\" or a list of \"GameFileMatcher\" instances!") raise TypeError("\"file_match\" needs to be \"None\" or a list of \"GameFileMatcher\" instances!")
@ -363,9 +357,8 @@ class GameData(GObject):
return self.__ignorematchers return self.__ignorematchers
@ignore_matchers.setter @ignore_matchers.setter
def ignore_matchers(self,im:list[GameFileMatcher]|None): def ignore_matchers(self,im:list[GameFileMatcher]|None):
if not im:
self.__ignorematchers = [] self.__ignorematchers = []
else: if im:
for matcher in im: for matcher in im:
if not isinstance(matcher,GameFileMatcher): if not isinstance(matcher,GameFileMatcher):
raise TypeError("\"ignore_match\" needs to be \"None\" or a list of \"GameFileMatcher\" instances!") raise TypeError("\"ignore_match\" needs to be \"None\" or a list of \"GameFileMatcher\" instances!")
@ -426,7 +419,7 @@ class GameData(GObject):
:return: The variables as a dict. :return: The variables as a dict.
:rtype: dict[str:str] :rtype: dict[str:str]
""" """
return self.variables return dict(self.variables)
def match_file(self,rel_filename:str)->bool: def match_file(self,rel_filename:str)->bool:
""" """
@ -791,6 +784,9 @@ class SteamGame(GameData):
vars["INSTALLDIR"] = self.installdir if self.installdir else "" vars["INSTALLDIR"] = self.installdir if self.installdir else ""
vars["STEAM_APPID"] = str(self.appid) vars["STEAM_APPID"] = str(self.appid)
vars["STEAM_LIBDIR"] = self.librarydir if self.librarydir else "" vars["STEAM_LIBDIR"] = self.librarydir if self.librarydir else ""
vars["STEAM_LIBRARY_DIR"] = self.librarydir if self.librarydir else ""
vars["STEAM_COMPATDATA"] = self.compatdata if self.compatdata else ""
return vars return vars
@Property(type=int) @Property(type=int)
@ -810,8 +806,9 @@ class SteamGame(GameData):
@Property @Property
def librarydir(self)->str|None: def librarydir(self)->str|None:
if not self.__librarydir and self.installdir: if not self.__librarydir and self.installdir:
return pathlib.Path(self.installdir).resolve().parent.parent.parent return str(pathlib.Path(self.installdir).resolve().parent.parent.parent)
return self.__librarydir return self.__librarydir
@librarydir.setter @librarydir.setter
def librarydir(self,directory): def librarydir(self,directory):
if not directory: if not directory:
@ -820,13 +817,20 @@ class SteamGame(GameData):
raise ValueError("Steam librarydir is not a valid directory!") raise ValueError("Steam librarydir is not a valid directory!")
self.__librarydir = directory self.__librarydir = directory
@Property
def compatdata(self)->str|None:
libdir = self.librarydir
if libdir:
return str(pathlib.Path(libdir).resolve() / 'steamapps' / 'compatdata')
return None
def serialize(self): def serialize(self):
ret = super().serialize() ret = super().serialize()
ret['appid'] = self.appid ret['appid'] = self.appid
if self.installdir: if self.installdir:
ret['installdir'] = self.installdir if self.installdir else "" ret['installdir'] = str(self.installdir) if self.installdir else ""
ret['librarydir'] = self.librarydir if self.librarydir else "" ret['librarydir'] = str(self.librarydir) if self.librarydir else ""
return ret return ret
@ -893,7 +897,7 @@ class Game(GObject):
@staticmethod @staticmethod
def new_from_dict(config:str): def new_from_dict(config:str):
logger = logger.getChild("Game.new_from_dict()") _logger = logger.getChild("Game.new_from_dict()")
def get_file_match(conf:dict): def get_file_match(conf:dict):
conf_fm = conf['file_match'] if 'file_match' in conf else None conf_fm = conf['file_match'] if 'file_match' in conf else None
@ -904,11 +908,11 @@ class Game(GObject):
for cfm in conf_fm: for cfm in conf_fm:
if ('type' in cfm and 'match' in cfm): if ('type' in cfm and 'match' in cfm):
try: try:
file_match.append(GameFileMatcher(GameFileType.from_string(cfm['type'],cfm['match']))) file_match.append(GameFileMatcher(GameFileType.from_string(cfm['type']),cfm['match']))
except Exception as ex: except Exception as ex:
logger.error("Adding GameFileMatcher to file_match failed! ({})!".format(ex)) _logger.error("Adding GameFileMatcher to file_match failed! ({})!".format(ex))
else: else:
logger.error("Illegal file_match settings! (\"type\" or \"match\" missing!)") _logger.error("Illegal file_match settings! (\"type\" or \"match\" missing!)")
else: else:
file_match = None file_match = None
@ -918,11 +922,11 @@ class Game(GObject):
for cim in conf_im: for cim in conf_im:
if ('type' in cim and 'match' in cim): if ('type' in cim and 'match' in cim):
try: try:
file_match.append(GameFileMatcher(GameFileType.from_string(cim['type'],cim['match']))) ignore_match.append(GameFileMatcher(GameFileType.from_string(cim['type']),cim['match']))
except Exception as ex: except Exception as ex:
logger.error("Adding GameFileMatcher to ignore_match failed! ({})!".format(ex)) _logger.error("Adding GameFileMatcher to ignore_match failed! ({})!".format(ex))
else: else:
logger.error("Illegal ignore_match settings! (\"type\" or \"match\" missing!)") _logger.error("Illegal ignore_match settings! (\"type\" or \"match\" missing!)")
else: else:
ignore_match = None ignore_match = None
@ -938,18 +942,22 @@ class Game(GObject):
if appid is not None and sgroot and sgdir: if appid is not None and sgroot and sgdir:
cls(appid,sgroot,sgdir,vars,installdir,file_match,ignore_match) cls(appid,sgroot,sgdir,vars,installdir,file_match,ignore_match)
return None return cls(appid,sgroot,sgdir,vars,installdir,file_match,ignore_match)
# new_steam_game() # new_steam_game()
if not 'id' in config or not 'name' in config: if not 'key' in config or not 'name' in config:
return None return None
id = config['id'] dbid = config['dbid'] if 'dbid' in config else None
key = config['key']
name = config['name'] name = config['name']
sgname = config['savegame_name'] if 'savegame_name' in config else id sgname = config['savegame_name'] if 'savegame_name' in config else key
sgtype = config['savegame_type'] if 'savegame_type' in config else SavegameType.UNSET sgtype = SavegameType.from_string(config['savegame_type']) if 'savegame_type' in config else SavegameType.UNSET
game = Game(key,name,sgname)
if dbid:
game.dbid = dbid
game = Game(id,name,sgname)
game.savegame_type = sgtype game.savegame_type = sgtype
game.is_active = config['is_active'] if 'is_active' in config else False game.is_active = config['is_active'] if 'is_active' in config else False
game.is_live = config['is_live'] if 'is_live' in config else True game.is_live = config['is_live'] if 'is_live' in config else True
@ -1007,7 +1015,12 @@ class Game(GObject):
if not os.path.isfile(filename): if not os.path.isfile(filename):
raise FileNotFoundError("Filename \"{filename}\" not found!".format(filename=filename)) raise FileNotFoundError("Filename \"{filename}\" not found!".format(filename=filename))
with open(filename,'rt',encoding="UTF-8") as ifile: with open(filename,'rt',encoding="UTF-8") as ifile:
return Game.new_from_dict(json.loads(ifile.read())) x=json.loads(ifile.read())
game = Game.new_from_dict(x)
if game is not None:
game.filename = filename
return game
def __init__(self,key:str,name:str,savegame_name:str): def __init__(self,key:str,name:str,savegame_name:str):
GObject.__init__(self) GObject.__init__(self)
@ -1098,7 +1111,7 @@ class Game(GObject):
self.__old_filename = self.__filename self.__old_filename = self.__filename
if not os.path.isabs(fn): if not os.path.isabs(fn):
self.__filename = GLib.build_filename(settings.gameconf_dir,fn) self.__filename = os.path.join(settings.gameconf_dir,fn)
else: else:
self.__filename = fn self.__filename = fn
@ -1246,13 +1259,15 @@ class Game(GObject):
def serialize(self)->dict: def serialize(self)->dict:
ret = { ret = {
'id': self.id, 'key': self.key,
'name': self.name, 'name': self.name,
'savegame_name': self.savegame_name, 'savegame_name': self.savegame_name,
'savegame_type': self.savegame_type.value, 'savegame_type': self.savegame_type.value,
'is_active': self.is_active, 'is_active': self.is_active,
'is_live': self.is_live, 'is_live': self.is_live,
} }
if self.dbid:
ret['dbid'] = self.dbid
if (self.windows): if (self.windows):
ret['windows'] = self.windows.serialize() ret['windows'] = self.windows.serialize()
@ -1357,6 +1372,7 @@ class Game(GObject):
class GameManager(GObject): class GameManager(GObject):
__global_gamemanager = None __global_gamemanager = None
logger = logger.getChild('GameManager')
@staticmethod @staticmethod
def get_global(): def get_global():
@ -1410,9 +1426,12 @@ class GameManager(GObject):
try: try:
game = Game.new_from_json_file(gcf) game = Game.new_from_json_file(gcf)
if not game: if not game:
self.logger.warn("Not loaded game \"{game}\"!".format(
game=(game.name if game is not None else "UNKNOWN GAME")))
print(game.serialize())
continue continue
except Exception as ex: except Exception as ex:
logger.error("Unable to load gameconf {gameconf}! ({what})".format( self.logger.error("Unable to load gameconf {gameconf}! ({what})".format(
gameconf = os.path.basename(gcf), gameconf = os.path.basename(gcf),
what = str(ex))) what = str(ex)))
continue continue

View File

@ -17,7 +17,7 @@
############################################################################### ###############################################################################
from gi.repository import Gtk,Gio,Gdk from gi.repository import Gtk,Gio,Gdk
from gi.repository.GObject import GObject,Signal,Property,SignalFlags from gi.repository.GObject import GObject,Signal,Property,SignalFlags,BindingFlags
import logging; logger=logging.getLogger(__name__) import logging; logger=logging.getLogger(__name__)
@ -84,6 +84,7 @@ class GameView(Gtk.ScrolledWindow):
self.columnview.set_single_click_activate(True) self.columnview.set_single_click_activate(True)
self.set_child(self.columnview) self.set_child(self.columnview)
self.refresh()
@property @property
def _liststore(self)->Gio.ListStore: def _liststore(self)->Gio.ListStore:
@ -120,7 +121,7 @@ class GameView(Gtk.ScrolledWindow):
def _on_key_column_bind(self,factory,item): def _on_key_column_bind(self,factory,item):
label = item.get_child() label = item.get_child()
game = item.get_item() game = item.get_item()
label.bind_property(game,'key','label',GObject.BindingFlags.DEFAULT) game.bind_property('key',label,'label',BindingFlags.SYNC_CREATE)
def _on_name_column_setup(self,factory,item): def _on_name_column_setup(self,factory,item):
item.set_child(Gtk.Label()) item.set_child(Gtk.Label())
@ -128,14 +129,14 @@ class GameView(Gtk.ScrolledWindow):
def _on_name_column_bind(self,factory,item): def _on_name_column_bind(self,factory,item):
label = item.get_child() label = item.get_child()
game = item.get_item() game = item.get_item()
label.bind_proprety(game,'name','label',GObject.BindingFlags.DEFAULT) game.bind_property('name',label,'label',BindingFlags.SYNC_CREATE)
def _on_active_column_setup(self,factory,item): def _on_active_column_setup(self,factory,item):
item.set_child(Gtk.Switch()) item.set_child(Gtk.Switch())
def _on_active_column_bind(self,factory,item): def _on_active_column_bind(self,factory,item):
switch = item.get_child() switch = item.get_child()
game = item.get_data() game = item.get_item()
switch.set_active(game.is_active) switch.set_active(game.is_active)
item._signal_active_state_set = switch.connect('state-set',self._on_active_state_set,game) item._signal_active_state_set = switch.connect('state-set',self._on_active_state_set,game)
@ -153,8 +154,8 @@ class GameView(Gtk.ScrolledWindow):
def _on_live_column_bind(self,factory,item): def _on_live_column_bind(self,factory,item):
switch = item.get_child() switch = item.get_child()
game = item.get_data() game = item.get_item()
switch.set_active(game.is_active) switch.set_active(game.is_live)
item._signal_live_state_set = switch.connect('state-set',self._on_live_state_set,game) item._signal_live_state_set = switch.connect('state-set',self._on_live_state_set,game)
def _on_live_column_unbind(self,factory,item): def _on_live_column_unbind(self,factory,item):
@ -174,7 +175,7 @@ class GameView(Gtk.ScrolledWindow):
game.save() game.save()
if not state: if not state:
dialog = Gtk.MessageDialog() dialog = Gtk.MessageDialog()
dialog.set_transient_for(self.get_toplevel()) dialog.set_transient_for(self.get_root())
dialog.props.buttons = Gtk.ButtonsType.YES_NO dialog.props.buttons = Gtk.ButtonsType.YES_NO
dialog.props.text = "Do you want to create a new savegame for <i>{game}</i>?".format(game=game.name) dialog.props.text = "Do you want to create a new savegame for <i>{game}</i>?".format(game=game.name)
dialog.props.use_markup = True dialog.props.use_markup = True

View File

@ -16,10 +16,14 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # # along with this program. If not, see <https://www.gnu.org/licenses/>. #
############################################################################### ###############################################################################
from .. import _import_gtk
from gi.repository import Gio,GLib,Gtk,Pango from gi.repository import Gio,GLib,Gtk,Pango
from gi.repository.GObject import Property,Signal,GObject,BindingFlags from gi.repository.GObject import Property,Signal,GObject,BindingFlags
from ..game import ( from ..game import (
Game, Game,
GameData,
GameFileMatcher, GameFileMatcher,
GameFileType, GameFileType,
SavegameType, SavegameType,
@ -793,98 +797,57 @@ class GameDialog(Gtk.Dialog):
return widget return widget
@Property(type=bool,default=False)
def has_game(self)->bool:
return (self.__game is not None)
def reset(self): def reset(self):
""" """
reset Resets the dialog to the Game set on init or clears the dialog if no Game was set. reset Resets the dialog to the Game set on init or clears the dialog if no Game was set.
""" """
self.__active_switch.set_active(True) def set_variables(var_widget,vars:dict[str:str]|None):
self.__live_switch.set_active(True) model = var_widget.columnview.get_model().get_model()
self.__name_entry.set_text("") model.remove_all()
self.__sgname_entry.set_text("") if vars:
self.__game_variables.columnview.get_model().get_model().remove_all() for k,v in vars.items():
model.append(GameVariableData(str(k),str(v)))
#windows def set_game_widget_data(widget,data:GameData|None):
self.__windows.sgroot_entry.set_text("") def set_filematch(fm_widget,filematchers:list[GameFileMatcher]):
self.__windows.sgdir_entry.set_text("") model = fm_widget.columnview.get_model().get_model()
self.__windows.variables.columnview.get_model().get_model().remove_all() model.remove_all()
self.__windows.filematch.columnview.get_model().get_model().remove_all() if filematchers:
self.__windows.ignorematch.columnview.get_model().get_model().remove_all() for fm in filematchers:
self.__windows.lookup_regkeys.listview.get_model().get_model().remove_all() model.append(GameFileMatcher(fm.match_type,fm.match_file))
self.__windows.installdir_regkeys.listview.get_model().get_model().remove_all()
#linux
self.__linux.sgroot_entry.set_text("")
self.__linux.sgdir_entry.set_text("")
self.__linux.binary_entry.set_text("")
self.__linux.filematch.columnview.get_model().get_model().remove_all()
self.__linux.ignorematch.columnview.get_model().get_model().remove_all()
self.__linux.variables.columnview.get_model().get_model().remove_all()
#linux
self.__macos.sgroot_entry.set_text("")
self.__macos.sgdir_entry.set_text("")
self.__macos.binary_entry.set_text("")
self.__macos.filematch.columnview.get_model().get_model().remove_all()
self.__macos.ignorematch.columnview.get_model().get_model().remove_all()
self.__macos.variables.columnview.get_model().get_model().remove_all()
#steam windows widget.sgroot_entry.set_text(data.savegame_root if data else "")
self.__steam_windows.sgroot_entry.set_text("") widget.sgdir_entry.set_text(data.savegame_dir if data else "")
self.__steam_windows.sgdir_entry.set_text("") set_variables(widget.variables,data.variables if data else None)
self.__steam_windows.appid_entry.set_text("") set_filematch(widget.filematch,data.file_matchers if data else None)
self.__steam_windows.installdir_entry.set_text("") set_filematch(widget.ignorematch,data.ignore_matchers if data else None)
self.__steam_windows.filematch.columnview.get_model().get_model().remove_all()
self.__steam_windows.ignorematch.columnview.get_model().get_model().remove_all()
self.__steam_windows.variables.columnview.get_model().get_model().remove_all()
#steam linux self.__active_switch.set_active(self.__game.is_active if self.has_game else True)
self.__steam_linux.sgroot_entry.set_text("") self.__live_switch.set_active(self.__game.is_live if self.has_game else True)
self.__steam_linux.sgdir_entry.set_text("") self.__name_entry.set_text(self.__game.name if self.has_game else "")
self.__steam_linux.appid_entry.set_text("") self.__sgname_entry.set_text(self.__game.savegame_name if self.has_game else "")
self.__steam_linux.installdir_entry.set_text("") set_variables(self.__game_variables,self.__game.variables if self.has_game else None)
self.__steam_linux.filematch.columnview.get_model().get_model().remove_all()
self.__steam_linux.ignorematch.columnview.get_model().get_model().remove_all()
self.__steam_linux.variables.columnview.get_model().get_model().remove_all()
#steam macos if self.has_game:
self.__steam_macos.sgroot_entry.set_text("")
self.__steam_macos.sgdir_entry.set_text("")
self.__steam_macos.appid_entry.set_text("")
self.__steam_macos.installdir_entry.set_text("")
self.__steam_macos.filematch.columnview.get_model().get_model().remove_all()
self.__steam_macos.ignorematch.columnview.get_model().get_model().remove_all()
self.__steam_macos.variables.columnview.get_model().get_model().remove_all()
if self.__game is not None:
self.__active_switch.set_active(self.__game.is_active)
self.__live_switch.set_active(self.__game.is_live)
self.__name_entry.set_text(self.__game.name)
self.__sgname_entry.set_text(self.__game.savegame_name)
model = self.__savegame_type_dropdown.get_model() model = self.__savegame_type_dropdown.get_model()
sgtype = self.__game.savegame_type
for i in range(model.get_n_items()): for i in range(model.get_n_items()):
if model.get_item(i).savegame_type == self.__game.savegame_type: item = model.get_item(i)
if sgtype == item.savegame_type:
self.__savegame_type_dropdown.set_selected(i) self.__savegame_type_dropdown.set_selected(i)
break break
for name,value in self.__game.variables.items(): #windows
self.__game_variables.get_model().get_model().append(GameVariableData(name,value)) set_game_widget_data(self.__windows,self.__game.windows if self.has_game else None)
self.__windows.lookup_regkeys.listview.get_model().get_model().remove_all()
if self.__game.windows: self.__windows.installdir_regkeys.listview.get_model().get_model().remove_all()
self.__windows.sgroot_entry.set_text(self.__game.windows.savegame_root) if self.has_game and self.__game.windows:
self.__windows.sgdir_entry.set_text(self.__game.windows.savegame_dir)
self.__windows.installdir_entry.set_text(self.__game.windows.installdir)
#filematch
fm_model = self.__windows.filematch.columnview.get_model().get_model()
for fm in self.__game.windows.file_matchers:
fm_model.append(GameFileMatcher(im.match_type,im.match_file))
im_model = self.__windows.ignorematch.columnview.get_model().get_model()
for im in self.__game.windows.ignore_matchers:
im_model.append(GameFileMatcher(im.match_type,im.match_file))
# set lookup regkeys
var_model = self.__windows.variables.columnview.get_model().get_model()
grk_model = self.__windows.lookup_regkeys.listview.get_model().get_model() grk_model = self.__windows.lookup_regkeys.listview.get_model().get_model()
irk_model = self.__windows.installdir_regkeys.listview.get_model().get_model() irk_model = self.__windows.installdir_regkeys.listview.get_model().get_model()
for rk in self.__game.windows.game_registry_keys: for rk in self.__game.windows.game_registry_keys:
@ -894,100 +857,44 @@ class GameDialog(Gtk.Dialog):
for rk in self.__game.windows.installdir_registry_keys: for rk in self.__game.windows.installdir_registry_keys:
irk_model.append(RegistryKeyData(rk)) irk_model.append(RegistryKeyData(rk))
#set variables #linux
for name,value in self.__game.windows.variables.items(): set_game_widget_data(self.__linux,self.__game.linux if self.has_game else None)
var_model.append(GameVariableData(name,value)) self.__linux.binary_entry.set_text(self.__game.linux.binary if self.has_game and self.__game.linux else "")
if self.__game.linux: #macos
self.__linux.sgroot_entry.set_text(self.__game.linux.savegame_root) set_game_widget_data(self.__macos,self.__game.macos if self.__game else None)
self.__linux.sgdir_entry.set_text(self.__game.linux.savegame_dir) self.__macos.binary_entry.set_text(self.__game.macos.binary if self.has_game and self.__game.macos else "")
self.__linux.binary_entry.set_text(self.__game.linux.binary)
#filematch #steam windows
fm_model = self.__linux.filematch.columnview.get_model().get_model() set_game_widget_data(self.__steam_windows,self.__game.steam_windows if self.has_game else None)
for fm in self.__game.linux.file_matchers: self.__steam_windows.appid_entry.set_text(str(self.__game.steam_windows.appid)
fm_model.append(GameFileMatcher(fm.match_type,fm.match_file)) if self.has_game and self.__game.steam_windows else "")
self.__steam_windows.installdir_entry.set_text(self.__game.steam_windows.installdir
if self.has_game
and self.__game.steam_windows
and self.__game.steam_windows.installdir
else "")
im_model = self.__linux.ignorematch.columnview.get_model().get_model() #steam linux
for im in self.__game.linux.ignore_matchers: set_game_widget_data(self.__steam_linux,self.__game.steam_linux if self.has_game else None)
im_model.append(GameFileMatcher(im.match_type,im.match_file)) self.__steam_linux.appid_entry.set_text(str(self.__game.steam_linux.appid)
if self.has_game and self.__game.steam_linux else "")
self.__steam_linux.installdir_entry.set_text(self.__game.steam_linux.installdir
if self.has_game
and self.__game.steam_linux
and self.__game.steam_linux.installdir
else "")
var_model = self.__linux.variables.columnview.get_model().get_model() #steam macos
for name,value in self.__game.linux.variables.items(): set_game_widget_data(self.__steam_macos,self.__game.steam_macos if self.has_game else None)
var_model.append(GameVariableData(name,value)) self.__steam_macos.appid_entry.set_text(str(self.__game.steam_macos.appid)
if self.has_game and self.__game.steam_macos else "")
self.__steam_macos.installdir_entry.set_text(self.__game.steam_macos.installdir
if self.has_game
and self.__game.steam_macos
and self.__game.steam_macos.installdir
else "")
if self.__game.macos:
self.__macos.sgroot_entry.set_text(self.__game.macos.savegame_root)
self.__macos.sgdir_entry.set_text(self.__game.macos.savegame_dir)
self.__macos.binary_entry.set_text(self.__game.macos.binary)
#filematch
fm_model = self.__macos.filematch.columnview.get_model().get_model()
for fm in self.__game.macos.file_matchers:
fm_model.append(GameFileMatcher(fm.match_type,fm.match_file))
im_model = self.__macos.ignorematch.columnview.get_model().get_model()
for im in self.__game.macos.ignore_matchers:
im_model.append(GameFileMatcher(im.match_type,im.match_file))
var_model = self.__macos.variables.columnview.get_model().get_model()
for name,value in self.__game.linux.variables.items():
var_model.append(GameVariableData(name,value))
if self.__game.steam_windows:
self.__steam_windows.sgroot_entry.set_text(self.__game.steam_windows.savegame_root)
self.__steam_windows.sgdir_entry.set_text(self.__game.steam_windows.savegame_dir)
self.__steam_windows.appid_entry.set_text(str(self.__game.steam_windows.appid))
self.__steam_windows.installdir_entry.set_text(self.__game.steam_windows.installdir if self.__game.steam_windows.installdir else "")
#filematch
fm_model = self.__steam_windows.filematch.columnview.get_model().get_model()
for fm in self.__game.steam_windows.file_matchers:
fm_model.append(GameFileMatcher(fm.match_type,fm.match_file))
im_model = self.__steam_windows.ignorematch.columnview.get_model().get_model()
for im in self.__game.steam_windows.ignore_matchers:
im_model.append(GameFileMatcher(im.match_type,im.match_file))
var_model = self.__steam_windows.variables.columnview.get_model().get_model()
for name,value in self.__game.steam_windows.variables.items():
var_model.append(GameVariableData(name,value))
if self.__game.steam_linux:
self.__steam_linux.sgroot_entry.set_text(self.__game.steam_linux.savegame_root)
self.__steam_linux.sgdir_entry.set_text(self.__game.steam_linux.savegame_dir)
self.__steam_linux.appid_entry.set_text(str(self.__game.steam_linux.appid))
self.__steam_linux.installdir_entry.set_text(self.__game.steam_linux.installdir if self.__game.steam_linux.installdir else "")
fm_model = self.__steam_linux.filematch.columnview.get_model().get_model()
for fm in self.__game.steam_linux.file_matchers:
fm_model.append(GameFileMatcher(fm.match_type,fm.match_file))
im_model = self.__steam_linux.ignorematch.columnview.get_model().get_model()
for im in self.__game.steam_linux.ignore_matchers:
im_model.append(GameFileMatcher(im.match_type,im.match_file))
var_model = self.__steam_linux.variables.columnview.get_model().get_model()
for name,value in self.__game.steam_linux.variables.items():
var_model.append(GameVariableData(name,value))
if self.__game.steam_macos:
self.__steam_macos.sgroot_entry.set_text(self.__game.steam_macos.savegame_root)
self.__steam_macos.sgdir_entry.set_text(self.__game.steam_macos.savegame_dir)
self.__steam_macos.appid_entry.set_text(str(self.__game.steam_macos.appid))
self.__steam_macos.installdir_entry.set_text(self.__game.steam_macos.installdir if self.__game.steam_macos.installdir else "")
fm_model = self.__steam_macos.filematch.columnview.get_model().get_model()
for fm in self.__game.steam_macos.file_matchers:
fm_model.append(GameFileMatcher(fm.match_type,fm.match_file))
im_model = self.__steam_macos.ignorematch.columnview.get_model().get_model()
for im in self.__game.steam_macos.ignore_matchers:
im_model.append(GameFileMatcher(im.match_type,im.match_file))
var_model = self.__steam_macos.variables.columnview.get_model().get_model()
for name,value in self.__game.steam_macos.variables.items():
var_model.append(GameVariableData(name,value))
# reset() # reset()
def save(self): def save(self):
@ -1005,11 +912,11 @@ class GameDialog(Gtk.Dialog):
for i in range(fm_model.get_n_items()): for i in range(fm_model.get_n_items()):
fm_data = fm_model.get_item(i) fm_data = fm_model.get_item(i)
filematch.append(GameFileMatcher(fm_data.match_type,fm_data.match_value)) filematch.append(fm_data)
for i in range(im_model.get_n_items()): for i in range(im_model.get_n_items()):
im_data = im_model.get_item(i) im_data = im_model.get_item(i)
ignorematch.append(GameFileMatcher(im_data.match_type,im_data.match_value)) ignorematch.append(im_data)
for i in range(var_model.get_n_items()): for i in range(var_model.get_n_items()):
var = var_model.get_item(i) var = var_model.get_item(i)
@ -1043,13 +950,13 @@ class GameDialog(Gtk.Dialog):
name = self.__name_entry.get_text() name = self.__name_entry.get_text()
savegame_name = self.__sgname_entry.get_text() savegame_name = self.__sgname_entry.get_text()
savegame_type = self.__savegame_type_dropdown.get_selected_item().savegame_type savegame_type = self.__savegame_type_dropdown.get_selected_item().savegame_type
if self.__game: if self.has_game:
self.__game.key = key self.__game.key = key
self.__game.name = name self.__game.name = name
self.__game.savegame_type = savegame_type self.__game.savegame_type = savegame_type
self.__game.savegame_name = savegame_name self.__game.savegame_name = savegame_name
self.__game.variables = variables self.__game.variables = variables
self.__game.filename = '.'.join((self.__game.key(),'gameconf')) self.__game.filename = '.'.join((self.__game.key,'gameconf'))
else: else:
self.__game = Game(key,name,savegame_name) self.__game = Game(key,name,savegame_name)
self.__game.savegame_type = savegame_type self.__game.savegame_type = savegame_type
@ -1279,7 +1186,7 @@ class GameDialog(Gtk.Dialog):
def _on_variable_name_bind(self,factory,item): def _on_variable_name_bind(self,factory,item):
label = item.get_child() label = item.get_child()
data = item.get_item() data = item.get_item()
data.bind_property('name',label,'label',GObject.BindingFlags.SYNC_CREATE) data.bind_property('name',label,'label',BindingFlags.SYNC_CREATE)
def _on_variable_value_setup(self,factory,item): def _on_variable_value_setup(self,factory,item):
label = Gtk.Label() label = Gtk.Label()
@ -1288,7 +1195,7 @@ class GameDialog(Gtk.Dialog):
def _on_variable_value_bind(self,factory,item): def _on_variable_value_bind(self,factory,item):
label = item.get_child() label = item.get_child()
data = item.get_item() data = item.get_item()
data.bind_property('value',label,'label',GObject.BindingFlags.SYNC_CREATE) data.bind_property('value',label,'label',BindingFlags.SYNC_CREATE)
def _on_filematch_dropdown_selection_changed(self,dropdown,data,item): def _on_filematch_dropdown_selection_changed(self,dropdown,data,item):
data = item.get_item() data = item.get_item()
@ -1322,13 +1229,19 @@ class GameDialog(Gtk.Dialog):
def _on_filematch_value_bind(self,factory,item,widget): def _on_filematch_value_bind(self,factory,item,widget):
label = item.get_child() label = item.get_child()
data = item.get_item() data = item.get_item()
if (data.match_value): if (data.match_file):
label.set_text(data.match_value) label.set_text(data.match_file)
label.bind_property('text',data,'match_file',BindingFlags.DEFAULT)
#label.connect('changed',self._on_filematch_value_label_changed,widget)
label.connect('notify::editing',self._on_filematch_value_notify_editing,widget)
else: else:
label.start_editing() label.bind_property('text',data,'match_file',BindingFlags.DEFAULT)
#label.connect('changed',self._on_filematch_value_label_changed,widget)
label.connect('notify::editing',self._on_filematch_value_notify_editing,widget)
label.grab_focus() label.grab_focus()
label.bind_property('text',data,'match_value',BindingFlags.DEFAULT) label.start_editing()
label.connect('changed',self._on_filematch_value_label_changed,widget)
def _on_windows_regkey_setup(self,factory,item): def _on_windows_regkey_setup(self,factory,item):
label = Gtk.EditableLabel() label = Gtk.EditableLabel()
@ -1378,12 +1291,23 @@ class GameDialog(Gtk.Dialog):
widget.columnview.get_model().get_model().append(GameFileMatcher(GameFileType.GLOB,"")) widget.columnview.get_model().get_model().append(GameFileMatcher(GameFileType.GLOB,""))
def _on_filematch_value_label_changed(self,label,widget): def _on_filematch_value_label_changed(self,label,widget):
if not label.get_text(): if not label.get_text().strip():
model = widget.columnview.get_model().get_model() model = widget.columnview.get_model().get_model()
i = 0 i = 0
while i < model.get_n_items(): while i < model.get_n_items():
item = model.get_item(i) item = model.get_item(i)
if not item.match_value.strip(): if not item.match_file.strip():
model.remove(i)
continue
i += 1
def _on_filematch_value_notify_editing(self,label,param,widget):
if label.props.editing == False:
if not label.get_text().strip():
model = widget.columnview.get_model().get_model()
i = 0
while i < model.get_n_items():
item = model.get_item(i)
if not item.match_file.strip():
model.remove(i) model.remove(i)
continue continue
i += 1 i += 1