mirror of
https://github.com/c9moser/sgbackup.git
synced 2026-01-19 19:40:13 +00:00
1772 lines
71 KiB
Python
1772 lines
71 KiB
Python
###############################################################################
|
|
# sgbackup - The SaveGame Backup tool #
|
|
# Copyright (C) 2024,2025 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 .. import _import_gtk
|
|
|
|
from gi.repository import Gio,GLib,Gtk,Pango
|
|
from gi.repository.GObject import Property,Signal,GObject,BindingFlags,SignalFlags
|
|
import rapidfuzz
|
|
from ..i18n import gettext as _, gettext_noop as N_
|
|
|
|
from ..game import (
|
|
Game,
|
|
GameData,
|
|
GameFileMatcher,
|
|
GameFileType,
|
|
SavegameType,
|
|
WindowsGame,
|
|
LinuxGame,
|
|
MacOSGame,
|
|
SteamGameData,
|
|
SteamLinuxData,
|
|
SteamMacOSData,
|
|
SteamWindowsData,
|
|
EpicGameData,
|
|
EpicWindowsData,
|
|
GameManager,
|
|
GameProvider,
|
|
GAME_PROVIDER_ICONS,
|
|
)
|
|
|
|
|
|
class GameVariableData(GObject):
|
|
"""
|
|
GameVariableData The Gio.ListStore data for Variables.
|
|
"""
|
|
|
|
def __init__(self,name:str,value:str):
|
|
"""
|
|
GameVariableData
|
|
|
|
:param name: The variable name
|
|
:type name: str
|
|
:param value: The variable value
|
|
:type value: str
|
|
|
|
Properties
|
|
__________
|
|
.. py:property:: name
|
|
:type: str
|
|
|
|
.. py:property:: value
|
|
:type: str
|
|
"""
|
|
GObject.__init__(self)
|
|
self.name = name
|
|
self.value = value
|
|
|
|
@Property(type=str)
|
|
def name(self)->str:
|
|
"""
|
|
name The variable name.
|
|
|
|
:type: str
|
|
"""
|
|
return self.__name
|
|
@name.setter
|
|
def name(self,name):
|
|
self.__name = name
|
|
|
|
@Property(type=str)
|
|
def value(self)->str:
|
|
"""
|
|
value The variable value
|
|
|
|
:type: str
|
|
"""
|
|
return self.__value
|
|
@value.setter
|
|
def value(self,value:str):
|
|
self.__value = value
|
|
|
|
class RegistryKeyData(GObject):
|
|
"""
|
|
RegistyKeyData The data for Windows registry keys.
|
|
"""
|
|
def __init__(self,regkey:str|None=None):
|
|
"""
|
|
RegistryKeyData
|
|
|
|
:param regkey: The registry key ot set, defaults to None
|
|
:type regkey: str | None, optional
|
|
"""
|
|
GObject.__init__(self)
|
|
if not regkey:
|
|
self.regkey = ""
|
|
else:
|
|
self.regkey = regkey
|
|
|
|
|
|
@Property(type=str)
|
|
def regkey(self)->str:
|
|
"""
|
|
regkey The registry key to set.
|
|
|
|
:type: str
|
|
"""
|
|
return self.__regkey
|
|
@regkey.setter
|
|
def regkey(self,key:str):
|
|
self.__regkey = key
|
|
|
|
def __bool__(self):
|
|
return bool(self.__regkey)
|
|
|
|
|
|
class GameFileTypeData(GObject):
|
|
""" GameFileTypeData The *Gio.Liststore* data for GameFileType *Gtk.DropDown* widgets."""
|
|
def __init__(self,match_type:GameFileType,name:str):
|
|
"""
|
|
GameFileTypeData
|
|
|
|
:param match_type: The matcher type
|
|
:type match_type: GameFileType
|
|
:param name: The name of the matcher type
|
|
:type name: str
|
|
"""
|
|
GObject.__init__(self)
|
|
if not isinstance(match_type,GameFileType):
|
|
raise TypeError("GameFileType")
|
|
self.__match_type = match_type
|
|
self.__name = name
|
|
|
|
@Property
|
|
def match_type(self)->GameFileType:
|
|
"""
|
|
match_type The match type
|
|
|
|
:type: GameFileType
|
|
"""
|
|
return self.__match_type
|
|
|
|
@Property(type=str)
|
|
def name(self)->str:
|
|
"""
|
|
name The name of the match type.
|
|
|
|
:type: str
|
|
"""
|
|
return self.__name
|
|
|
|
class SavegameTypeData(GObject):
|
|
"""
|
|
SavegameTypeData Holds the data for the SavegameType *Gtk.DropDown*.
|
|
"""
|
|
|
|
def __init__(self,type:SavegameType,name:str,icon_name:str):
|
|
"""
|
|
SavegameTypeData
|
|
|
|
:param type: The SavegameType to select.
|
|
:type type: SavegameType
|
|
:param name: The name of the SavegameType.
|
|
:type name: str
|
|
:param icon_name: The Icon name to display for the SavegameType
|
|
:type icon_name: str
|
|
"""
|
|
GObject.__init__(self)
|
|
self.__sgtype = type
|
|
self.__name = name
|
|
self.__icon_name = icon_name
|
|
|
|
@Property
|
|
def savegame_type(self)->SavegameType:
|
|
"""
|
|
savegame_type The savegane type to select.
|
|
|
|
|
|
:type: SavegameType
|
|
"""
|
|
return self.__sgtype
|
|
|
|
@Property
|
|
def name(self)->str:
|
|
"""
|
|
name The name of the SavegameType
|
|
|
|
:type: str
|
|
"""
|
|
return self.__name
|
|
|
|
@Property
|
|
def icon_name(self)->str:
|
|
"""
|
|
icon_name The icon name for the savegame type.
|
|
|
|
:type: str
|
|
"""
|
|
return self.__icon_name
|
|
|
|
|
|
class GameVariableDialog(Gtk.Dialog):
|
|
"""
|
|
GameVariableDialog The dialog for setting game variables.
|
|
|
|
It is bound to on the GameDialog variable columnviews. This dialog
|
|
will update the given columnview automatically if the response is
|
|
*Gtk.Response.APPLY* and destroy itself on any response.
|
|
|
|
If not variable is given, this dialog will create a new one
|
|
|
|
"""
|
|
def __init__(self,parent:Gtk.Window,columnview:Gtk.ColumnView,variable:GameVariableData|None=None):
|
|
"""
|
|
GameVariableDialog
|
|
|
|
:param parent: The parent window (should be a GameDialog instance).
|
|
:type parent: Gtk.Window
|
|
:param columnview: The Columnview to operate on.
|
|
:type columnview: Gtk.ColumnView
|
|
:param variable: The variable to edit, defaults to None
|
|
:type variable: GameVariableData | None, optional
|
|
"""
|
|
Gtk.Dialog.__init__(self)
|
|
self.set_transient_for(parent)
|
|
self.set_default_size(600,-1)
|
|
|
|
self.__columnview = columnview
|
|
|
|
if variable:
|
|
self.__variable = variable
|
|
else:
|
|
self.__variable = None
|
|
|
|
grid = Gtk.Grid()
|
|
label = Gtk.Label.new(_("Name:"))
|
|
label.set_xalign(0.0)
|
|
self.__name_entry = Gtk.Entry()
|
|
self.__name_entry.set_hexpand(True)
|
|
self.__name_entry.connect("changed",self._on_name_entry_changed)
|
|
grid.attach(label,0,0,1,1)
|
|
grid.attach(self.__name_entry,1,0,1,1)
|
|
|
|
label = Gtk.Label.new(_("Value:"))
|
|
label.set_xalign(0.0)
|
|
self.__value_entry = Gtk.Entry()
|
|
self.__value_entry.set_hexpand(True)
|
|
|
|
grid.attach(label,0,1,1,1)
|
|
grid.attach(self.__value_entry,1,1,1,1)
|
|
|
|
self.get_content_area().append(grid)
|
|
|
|
if self.__variable:
|
|
self.__name_entry.set_text(self.__variable.name)
|
|
self.__value_entry.set_text(self.__variable.value)
|
|
|
|
self.__apply_button = self.add_button("Apply",Gtk.ResponseType.APPLY)
|
|
self.__apply_button.set_sensitive(bool(self))
|
|
|
|
self.add_button("Cancel",Gtk.ResponseType.CANCEL)
|
|
|
|
def __bool__(self):
|
|
name = self.__name_entry.get_text()
|
|
if name:
|
|
if self.__variable and self.__variable.name == name:
|
|
return True
|
|
model = self.__columnview.get_model().get_model()
|
|
for i in range(model.get_n_items()):
|
|
if name == model.get_item(i).name:
|
|
return False
|
|
return True
|
|
return False
|
|
|
|
def _on_name_entry_changed(self,entry):
|
|
self.__apply_button.set_sensitive(bool(self))
|
|
|
|
def do_response(self,response):
|
|
if response == Gtk.ResponseType.APPLY:
|
|
if not bool(self):
|
|
return
|
|
if self.__variable:
|
|
self.__variable.name = self.__name_entry.get_text()
|
|
self.__variable.value = self.__value_entry.get_text()
|
|
else:
|
|
model = self.__columnview.get_model().get_model()
|
|
model.append(GameVariableData(self.__name_entry.get_text(),self.__value_entry.get_text()))
|
|
self.hide()
|
|
self.destroy()
|
|
|
|
|
|
|
|
class GameDialog(Gtk.Dialog):
|
|
def __init__(self,
|
|
parent:Gtk.Window|None=None,
|
|
game:Game|None=None):
|
|
"""
|
|
GameDialog This dialog is for setting game config.
|
|
|
|
The dialog automatically saves the game.
|
|
|
|
:param parent: The parent Window, defaults to None
|
|
:type parent: Gtk.Window | None, optional
|
|
:param game: The game to configure, defaults to None
|
|
:type game: Game | None, optional
|
|
"""
|
|
|
|
Gtk.Dialog.__init__(self)
|
|
if (parent):
|
|
self.set_transient_for(parent)
|
|
|
|
if isinstance(game,Game):
|
|
self.__game = game
|
|
else:
|
|
self.__game = None
|
|
|
|
self.set_default_size(800,600)
|
|
|
|
self.__filematch_dropdown_model = Gio.ListStore.new(GameFileTypeData)
|
|
self.__filematch_dropdown_model.append(GameFileTypeData(GameFileType.FILENAME,_("Filename")))
|
|
self.__filematch_dropdown_model.append(GameFileTypeData(GameFileType.GLOB,_("Glob")))
|
|
self.__filematch_dropdown_model.append(GameFileTypeData(GameFileType.REGEX,_("Regular expression")))
|
|
|
|
paned = Gtk.Paned(orientation=Gtk.Orientation.HORIZONTAL)
|
|
paned.set_position(200)
|
|
|
|
self.__stack = Gtk.Stack.new()
|
|
paned.set_end_child(self.__stack)
|
|
paned.set_hexpand(True)
|
|
paned.set_vexpand(True)
|
|
|
|
self.__stack_sidebar = Gtk.ListBox()
|
|
self.__stack_sidebar.set_activate_on_single_click(False)
|
|
self.__stack_sidebar.set_selection_mode(Gtk.SelectionMode.SINGLE)
|
|
self.__stack_sidebar.connect('selected_rows_changed',self._on_stack_sidebar_selected_rows_changed)
|
|
|
|
sidebar_scrolled = Gtk.ScrolledWindow()
|
|
sidebar_scrolled.set_child(self.__stack_sidebar)
|
|
paned.set_start_child(sidebar_scrolled)
|
|
|
|
self.__variable_name_factory = Gtk.SignalListItemFactory()
|
|
self.__variable_name_factory.connect('setup',self._on_variable_name_setup)
|
|
self.__variable_name_factory.connect('bind',self._on_variable_name_bind)
|
|
|
|
self.__variable_value_factory = Gtk.SignalListItemFactory()
|
|
self.__variable_value_factory.connect('setup',self._on_variable_value_setup)
|
|
self.__variable_value_factory.connect('bind',self._on_variable_value_bind)
|
|
|
|
self.__add_game_page()
|
|
self.__windows = self.__create_windows_page()
|
|
self.__linux = self.__create_linux_page()
|
|
self.__macos = self.__create_macos_page()
|
|
self.__steam = self.__create_steam_page()
|
|
self.__epic = self.__create_epic_page()
|
|
|
|
|
|
for stack_page in self.__stack.get_pages():
|
|
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL,4)
|
|
label = Gtk.Label.new(stack_page.props.title)
|
|
attrs = Pango.AttrList.new()
|
|
size_attr = Pango.AttrSize.new(14 * Pango.SCALE)
|
|
attrs.insert(size_attr)
|
|
label.set_attributes(attrs)
|
|
icon = Gtk.Image.new_from_icon_name(stack_page.props.icon_name)
|
|
icon.set_pixel_size(20)
|
|
hbox.append(icon)
|
|
hbox.append(label)
|
|
hbox.page_name = stack_page.props.name
|
|
|
|
self.__stack_sidebar.append(hbox)
|
|
|
|
|
|
self.__stack_sidebar.select_row(self.__stack_sidebar.get_row_at_index(0))
|
|
|
|
self.get_content_area().append(paned)
|
|
self.__apply_button = self.add_button("Apply",Gtk.ResponseType.APPLY)
|
|
self.__apply_button.set_sensitive(False)
|
|
|
|
self.add_button("Cancel",Gtk.ResponseType.CANCEL)
|
|
|
|
self.reset()
|
|
|
|
def __add_game_page(self):
|
|
page = Gtk.ScrolledWindow()
|
|
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL,2)
|
|
self.__set_widget_margin(vbox,5)
|
|
|
|
sgtype_data = (
|
|
(SavegameType.UNSET,"Not set","process-stop-symbolic"),
|
|
|
|
(SavegameType.WINDOWS,N_("Windows"),"windows-svgrepo-com-symbolic"),
|
|
(SavegameType.STEAM_WINDOWS,N_("Steam Windows"),"steam-svgrepo-com-symbolic"),
|
|
(SavegameType.EPIC_WINDOWS,N_("Epic Windows"),"epic-games-svgrepo-com-symbolic"),
|
|
#(SavegameType.GOG_WINDOWS,"GoG Windows","object-select-symbolic"),
|
|
|
|
(SavegameType.LINUX,N_("Linux native"),"linux-svgrepo-com-symbolic"),
|
|
(SavegameType.STEAM_LINUX,_("Steam Linux"),"steam-svgrepo-com-symbolic"),
|
|
#(SavegameType.EPIC_LINUX,_("Epic Linux"),"epic-games-svgrepo-com-symbolic"),
|
|
#(SavegameType.GOG_LINUX,"GoG Linux","object-select-symbolic"),
|
|
|
|
(SavegameType.MACOS,_("MacOS"),"apple-svgrepo-com-symbolic"),
|
|
(SavegameType.STEAM_MACOS,_("Steam MacOS"),"steam-svgrepo-com-symbolic"),
|
|
)
|
|
sgtype_model = Gio.ListStore.new(SavegameTypeData)
|
|
for data in sgtype_data:
|
|
sgtype_model.append(SavegameTypeData(*data))
|
|
|
|
grid = Gtk.Grid.new()
|
|
|
|
label = self.__create_label(_("Is active?"))
|
|
self.__active_switch = Gtk.Switch()
|
|
entry_hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL,5)
|
|
entry_hbox.append(self.__active_switch)
|
|
entry_hbox.append(label)
|
|
vbox.append(entry_hbox)
|
|
|
|
label = self.__create_label(_("Is live?"))
|
|
self.__live_switch = Gtk.Switch()
|
|
entry_hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL,5)
|
|
|
|
entry_hbox.append(self.__live_switch)
|
|
entry_hbox.append(label)
|
|
vbox.append(entry_hbox)
|
|
|
|
label = self.__create_label(_("ID:"))
|
|
self.__id_label = Gtk.Label()
|
|
self.__id_label.set_hexpand(True)
|
|
grid.attach(label,0,0,1,1)
|
|
grid.attach(self.__id_label,1,0,1,1)
|
|
|
|
label = self.__create_label(_("Key:"))
|
|
self.__key_entry = Gtk.Entry()
|
|
self.__key_entry.set_hexpand(True)
|
|
self.__key_entry.connect('changed',lambda w: self._on_savegame_type_changed())
|
|
|
|
grid.attach(label,0,1,1,1)
|
|
grid.attach(self.__key_entry,1,1,1,1)
|
|
|
|
sgtype_factory = Gtk.SignalListItemFactory()
|
|
sgtype_factory.connect('setup',self._on_savegame_type_setup)
|
|
sgtype_factory.connect('bind',self._on_savegame_type_bind)
|
|
self.__savegame_type_dropdown = Gtk.DropDown(model=sgtype_model,factory=sgtype_factory)
|
|
self.__savegame_type_dropdown.set_selected(0)
|
|
self.__savegame_type_dropdown.set_hexpand(True)
|
|
self.__savegame_type_dropdown.connect('notify::selected-item',lambda w,d: self._on_savegame_type_changed())
|
|
label = self.__create_label(_("Savegame Type:"))
|
|
grid.attach(label,0,2,1,1)
|
|
grid.attach(self.__savegame_type_dropdown,1,2,1,1)
|
|
|
|
label = self.__create_label(_("Game name:"))
|
|
self.__name_entry = Gtk.Entry()
|
|
self.__name_entry.set_hexpand(True)
|
|
self.__name_entry.connect('changed',lambda w: self._on_savegame_type_changed())
|
|
grid.attach(label,0,3,1,1)
|
|
grid.attach(self.__name_entry,1,3,1,1)
|
|
|
|
label = self.__create_label(_("Savegame name:"))
|
|
self.__sgname_entry = Gtk.Entry()
|
|
self.__sgname_entry.set_hexpand(True)
|
|
self.__sgname_entry.connect('changed',lambda w: self._on_savegame_type_changed())
|
|
grid.attach(label,0,4,1,1)
|
|
grid.attach(self.__sgname_entry,1,4,1,1)
|
|
vbox.append(grid)
|
|
|
|
self.__game_variables = self.__create_variables_widget()
|
|
|
|
vbox.append(self.__game_variables)
|
|
|
|
page.set_child(vbox)
|
|
self.__stack.add_titled(page,"main",_("Game"))
|
|
stack_page = self.__stack.get_page(page)
|
|
stack_page.set_icon_name('org.sgbackup.sgbackup-symbolic')
|
|
|
|
|
|
def __create_windows_page(self):
|
|
page = Gtk.ScrolledWindow()
|
|
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL,2)
|
|
self.__set_widget_margin(vbox,5)
|
|
|
|
grid = Gtk.Grid()
|
|
|
|
label = self.__create_label(_("Root directory:"))
|
|
page.sgroot_entry = Gtk.Entry()
|
|
page.sgroot_entry.set_hexpand(True)
|
|
page.sgroot_entry.connect('changed',lambda w: self._on_savegame_type_changed())
|
|
grid.attach(label,0,0,1,1)
|
|
grid.attach(page.sgroot_entry,1,0,1,1)
|
|
|
|
label = self.__create_label(_("Backup directory:"))
|
|
page.sgdir_entry = Gtk.Entry()
|
|
page.sgdir_entry.set_hexpand(True)
|
|
page.sgdir_entry.connect('changed',lambda w: self._on_savegame_type_changed())
|
|
grid.attach(label,0,1,1,1)
|
|
grid.attach(page.sgdir_entry,1,1,1,1)
|
|
|
|
label = self.__create_label(("Installation directory:"))
|
|
page.installdir_entry = Gtk.Entry()
|
|
page.installdir_entry.set_hexpand(True)
|
|
grid.attach(label,0,2,1,1)
|
|
grid.attach(page.installdir_entry,1,2,1,1)
|
|
vbox.append(grid)
|
|
|
|
page.filematch = self.__create_filematch_widget(_('Match Files'))
|
|
vbox.append(page.filematch)
|
|
|
|
page.ignorematch = self.__create_filematch_widget(_('Ignore Files'))
|
|
vbox.append(page.ignorematch)
|
|
|
|
page.lookup_regkeys = self.__create_registry_key_widget(_("Lookup Registry keys"))
|
|
vbox.append(page.lookup_regkeys)
|
|
|
|
page.installdir_regkeys = self.__create_registry_key_widget(_("Installations directory Registry keys"))
|
|
vbox.append(page.installdir_regkeys)
|
|
|
|
page.variables = self.__create_variables_widget()
|
|
vbox.append(page.variables)
|
|
|
|
page.set_child(vbox)
|
|
self.__stack.add_titled(page,"windows",_("Windows"))
|
|
stack_page = self.__stack.get_page(page)
|
|
stack_page.set_icon_name("windows-svgrepo-com-symbolic")
|
|
|
|
return page
|
|
|
|
|
|
def __create_linux_page(self):
|
|
page = Gtk.ScrolledWindow()
|
|
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL,2)
|
|
self.__set_widget_margin(vbox,5)
|
|
|
|
grid = Gtk.Grid()
|
|
label = self.__create_label(_("Root directory:"))
|
|
page.sgroot_entry = Gtk.Entry()
|
|
page.sgroot_entry.set_hexpand(True)
|
|
page.sgroot_entry.connect('changed',lambda w: self._on_savegame_type_changed())
|
|
grid.attach(label,0,0,1,1)
|
|
grid.attach(page.sgroot_entry,1,0,1,1)
|
|
|
|
label = self.__create_label(_("Backup directory:"))
|
|
page.sgdir_entry = Gtk.Entry()
|
|
page.sgdir_entry.set_hexpand(True)
|
|
page.sgdir_entry.connect('changed',lambda w: self._on_savegame_type_changed())
|
|
grid.attach(label,0,1,1,1)
|
|
grid.attach(page.sgdir_entry,1,1,1,1)
|
|
|
|
label = self.__create_label(_("Executable:"))
|
|
page.binary_entry = Gtk.Entry()
|
|
page.binary_entry.set_hexpand(True)
|
|
grid.attach(label,0,2,1,1)
|
|
grid.attach(page.binary_entry,1,2,1,1)
|
|
vbox.append(grid)
|
|
|
|
page.filematch = self.__create_filematch_widget('Match Files')
|
|
vbox.append(page.filematch)
|
|
|
|
page.ignorematch = self.__create_filematch_widget('Ignore Files')
|
|
vbox.append(page.ignorematch)
|
|
|
|
page.variables = self.__create_variables_widget()
|
|
vbox.append(page.variables)
|
|
|
|
page.set_child(vbox)
|
|
self.__stack.add_titled(page,"linux",_("Linux"))
|
|
stack_page = self.__stack.get_page(page)
|
|
stack_page.set_icon_name("linux-svgrepo-com-symbolic")
|
|
|
|
return page
|
|
|
|
def __create_macos_page(self):
|
|
page = Gtk.ScrolledWindow()
|
|
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL,2)
|
|
self.__set_widget_margin(vbox,5)
|
|
|
|
grid = Gtk.Grid()
|
|
label = self.__create_label(_("Root directory:"))
|
|
page.sgroot_entry = Gtk.Entry()
|
|
page.sgroot_entry.set_hexpand(True)
|
|
page.sgroot_entry.connect('changed',lambda w: self._on_savegame_type_changed())
|
|
grid.attach(label,0,0,1,1)
|
|
grid.attach(page.sgroot_entry,1,0,1,1)
|
|
|
|
label = self.__create_label(_("Backup directory:"))
|
|
page.sgdir_entry = Gtk.Entry()
|
|
page.sgdir_entry.set_hexpand(True)
|
|
page.sgdir_entry.connect('changed',lambda w: self._on_savegame_type_changed())
|
|
grid.attach(label,0,1,1,1)
|
|
grid.attach(page.sgdir_entry,1,1,1,1)
|
|
|
|
label = self.__create_label(_("Executable"))
|
|
page.binary_entry = Gtk.Entry()
|
|
page.binary_entry.set_hexpand(True)
|
|
grid.attach(label,0,2,1,1)
|
|
grid.attach(page.binary_entry,1,2,1,1)
|
|
vbox.append(grid)
|
|
|
|
page.filematch = self.__create_filematch_widget('Match Files')
|
|
vbox.append(page.filematch)
|
|
|
|
page.ignorematch = self.__create_filematch_widget('Ignore Files')
|
|
vbox.append(page.ignorematch)
|
|
|
|
page.variables = self.__create_variables_widget()
|
|
vbox.append(page.variables)
|
|
|
|
page.set_child(vbox)
|
|
self.__stack.add_titled(page,"macos",_("MacOS"))
|
|
stack_page = self.__stack.get_page(page)
|
|
stack_page.set_icon_name("apple-svgrepo-com-symbolic")
|
|
|
|
return page
|
|
|
|
def __create_steam_page(self):
|
|
def create_notebook_page(title,icon_name):
|
|
label_widget = Gtk.Box.new(Gtk.Orientation.HORIZONTAL,2)
|
|
label_icon = Gtk.Image.new_from_icon_name(icon_name)
|
|
label_icon.set_pixel_size(12)
|
|
label=Gtk.Label.new(title)
|
|
label_widget.append(label_icon)
|
|
label_widget.append(label)
|
|
|
|
nbpage = Gtk.ScrolledWindow()
|
|
nbvbox = Gtk.Box.new(Gtk.Orientation.VERTICAL,5)
|
|
nbgrid = Gtk.Grid()
|
|
self.__set_widget_margin(nbgrid,5)
|
|
|
|
label = self.__create_label(_("Root directory:"))
|
|
nbpage.sgroot_entry = Gtk.Entry()
|
|
nbpage.sgroot_entry.set_hexpand(True)
|
|
nbpage.sgroot_entry.connect('changed',lambda w: self._on_savegame_type_changed())
|
|
nbgrid.attach(label,0,0,1,1)
|
|
nbgrid.attach(nbpage.sgroot_entry,1,0,1,1)
|
|
|
|
label = self.__create_label(_("Backup directory:"))
|
|
nbpage.sgdir_entry = Gtk.Entry()
|
|
nbpage.sgdir_entry.set_hexpand(True)
|
|
nbpage.sgdir_entry.connect('changed',lambda w: self._on_savegame_type_changed())
|
|
nbgrid.attach(label,0,1,1,1)
|
|
nbgrid.attach(nbpage.sgdir_entry,1,1,1,1)
|
|
|
|
label = self.__create_label(_("Installation directory:"))
|
|
nbpage.installdir_entry = Gtk.Entry()
|
|
nbpage.installdir_entry.set_hexpand(True)
|
|
nbgrid.attach(label,0,3,1,1)
|
|
nbgrid.attach(nbpage.installdir_entry,1,3,1,1)
|
|
|
|
nbvbox.append(nbgrid)
|
|
|
|
nbpage.filematch = self.__create_filematch_widget('Match Files')
|
|
nbvbox.append(nbpage.filematch)
|
|
|
|
nbpage.ignorematch = self.__create_filematch_widget('Ignore Files')
|
|
nbvbox.append(nbpage.ignorematch)
|
|
|
|
nbpage.variables = self.__create_variables_widget()
|
|
nbvbox.append(nbpage.variables)
|
|
|
|
nbpage.set_child(nbvbox)
|
|
return nbpage,label_widget
|
|
# create_notebook_page()
|
|
|
|
page = Gtk.Box.new(Gtk.Orientation.VERTICAL,2)
|
|
|
|
grid = Gtk.Grid()
|
|
self.__set_widget_margin(grid,5)
|
|
|
|
label = Gtk.Label.new("App ID:")
|
|
page.appid_entry = Gtk.Entry()
|
|
page.appid_entry.set_hexpand(True)
|
|
grid.attach(label,0,0,1,1)
|
|
grid.attach(page.appid_entry,1,0,1,1)
|
|
page.append(grid)
|
|
|
|
page.notebook = Gtk.Notebook()
|
|
page.notebook.set_hexpand(True)
|
|
page.notebook.set_vexpand(True)
|
|
page.windows,nb_label = create_notebook_page(_('Windows'),'windows-svgrepo-com-symbolic')
|
|
page.notebook.append_page(page.windows,nb_label)
|
|
|
|
page.linux,nb_label = create_notebook_page(_("Linux"),'linux-svgrepo-com-symbolic')
|
|
page.notebook.append_page(page.linux,nb_label)
|
|
|
|
page.macos,nb_label = create_notebook_page(_("Mac OS"),'apple-svgrepo-com-symbolic')
|
|
page.notebook.append_page(page.macos,nb_label)
|
|
|
|
page.append(page.notebook)
|
|
self.__stack.add_titled(page,'steam','Steam')
|
|
stack_page = self.__stack.get_page(page)
|
|
stack_page.set_icon_name("steam-svgrepo-com-symbolic")
|
|
|
|
return page
|
|
|
|
def __create_epic_page(self):
|
|
def create_notebook_page(title,icon_name):
|
|
label_widget = Gtk.Box.new(Gtk.Orientation.HORIZONTAL,2)
|
|
label_icon = Gtk.Image.new_from_icon_name(icon_name)
|
|
label_icon.set_pixel_size(12)
|
|
label=Gtk.Label.new(title)
|
|
label_widget.append(label_icon)
|
|
label_widget.append(label)
|
|
|
|
nbpage = Gtk.ScrolledWindow()
|
|
nbvbox = Gtk.Box.new(Gtk.Orientation.VERTICAL,5)
|
|
nbgrid = Gtk.Grid()
|
|
self.__set_widget_margin(nbgrid,5)
|
|
|
|
label = self.__create_label(_("Root directory:"))
|
|
nbpage.sgroot_entry = Gtk.Entry()
|
|
nbpage.sgroot_entry.set_hexpand(True)
|
|
nbpage.sgroot_entry.connect('changed',lambda w: self._on_savegame_type_changed())
|
|
nbgrid.attach(label,0,0,1,1)
|
|
nbgrid.attach(nbpage.sgroot_entry,1,0,1,1)
|
|
|
|
label = self.__create_label(_("Backup directory:"))
|
|
nbpage.sgdir_entry = Gtk.Entry()
|
|
nbpage.sgdir_entry.set_hexpand(True)
|
|
nbpage.sgdir_entry.connect('changed',lambda w: self._on_savegame_type_changed())
|
|
nbgrid.attach(label,0,1,1,1)
|
|
nbgrid.attach(nbpage.sgdir_entry,1,1,1,1)
|
|
|
|
label = self.__create_label(_("Installation directory:"))
|
|
nbpage.installdir_entry = Gtk.Entry()
|
|
nbpage.installdir_entry.set_hexpand(True)
|
|
nbgrid.attach(label,0,3,1,1)
|
|
nbgrid.attach(nbpage.installdir_entry,1,3,1,1)
|
|
|
|
nbvbox.append(nbgrid)
|
|
|
|
nbpage.filematch = self.__create_filematch_widget('Match Files')
|
|
nbvbox.append(nbpage.filematch)
|
|
|
|
nbpage.ignorematch = self.__create_filematch_widget('Ignore Files')
|
|
nbvbox.append(nbpage.ignorematch)
|
|
|
|
nbpage.variables = self.__create_variables_widget()
|
|
nbvbox.append(nbpage.variables)
|
|
|
|
nbpage.set_child(nbvbox)
|
|
return nbpage,label_widget
|
|
# create_notebook_page()
|
|
|
|
page = Gtk.Box.new(Gtk.Orientation.VERTICAL,2)
|
|
grid = Gtk.Grid()
|
|
|
|
label = self.__create_label(_("AppName:"))
|
|
page.appname_entry = Gtk.Entry()
|
|
page.appname_entry.set_hexpand(True)
|
|
grid.attach(label,0,0,1,1)
|
|
grid.attach(page.appname_entry,1,0,1,1)
|
|
page.append(grid)
|
|
|
|
page.notebook = Gtk.Notebook()
|
|
page.notebook.set_hexpand(True)
|
|
page.notebook.set_vexpand(True)
|
|
|
|
page.windows,nb_label = create_notebook_page(_("Windows"),'windows-svgrepo-com-symbolic')
|
|
page.notebook.append_page(page.windows,nb_label)
|
|
|
|
page.append(page.notebook)
|
|
|
|
self.__stack.add_titled(page,'epic','Epic Games')
|
|
stack_page = self.__stack.get_page(page)
|
|
stack_page.set_icon_name("epic-games-svgrepo-com-symbolic")
|
|
|
|
return page
|
|
|
|
def __set_widget_margin(self,widget,margin):
|
|
widget.set_margin_start(margin)
|
|
widget.set_margin_end(margin)
|
|
widget.set_margin_top(margin)
|
|
widget.set_margin_bottom(margin)
|
|
|
|
def __create_variables_widget(self):
|
|
widget = Gtk.Frame.new("Variables")
|
|
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL,0)
|
|
|
|
model = Gio.ListStore.new(GameVariableData)
|
|
selection = Gtk.SingleSelection.new(model)
|
|
selection.set_autoselect(False)
|
|
selection.set_can_unselect(True)
|
|
|
|
widget.columnview = Gtk.ColumnView.new(selection)
|
|
widget.columnview.set_vexpand(True)
|
|
|
|
widget.actions = Gtk.ActionBar()
|
|
icon = Gtk.Image.new_from_icon_name("list-add-symbolic")
|
|
widget.add_button = Gtk.Button()
|
|
widget.add_button.set_child(icon)
|
|
widget.add_button.connect('clicked',
|
|
self._on_variables_add_button_clicked,
|
|
widget.columnview)
|
|
widget.actions.pack_start(widget.add_button)
|
|
|
|
icon = Gtk.Image.new_from_icon_name("document-edit-symbolic")
|
|
widget.edit_button = Gtk.Button()
|
|
widget.edit_button.set_child(icon)
|
|
widget.edit_button.set_sensitive(False)
|
|
widget.edit_button.connect('clicked',
|
|
self._on_variables_edit_buton_clicked,
|
|
widget.columnview)
|
|
widget.actions.pack_start(widget.edit_button)
|
|
|
|
icon = Gtk.Image.new_from_icon_name("list-remove-symbolic")
|
|
widget.remove_button = Gtk.Button()
|
|
widget.remove_button.set_child(icon)
|
|
widget.remove_button.set_sensitive(False)
|
|
widget.remove_button.connect('clicked',
|
|
self._on_variables_remove_button_clicked,
|
|
widget.columnview)
|
|
widget.actions.pack_start(widget.remove_button)
|
|
|
|
name_column = Gtk.ColumnViewColumn.new("Name",self.__variable_name_factory)
|
|
name_column.set_expand(True)
|
|
widget.columnview.append_column(name_column)
|
|
|
|
value_column = Gtk.ColumnViewColumn.new("Value",self.__variable_value_factory)
|
|
value_column.set_expand(True)
|
|
widget.columnview.append_column(value_column)
|
|
|
|
selection.connect('selection-changed',self._on_variable_selection_changed,widget)
|
|
|
|
vbox.append(widget.actions)
|
|
vbox.append(widget.columnview)
|
|
|
|
widget.set_child(vbox)
|
|
return widget
|
|
|
|
def __create_label(self,text:str):
|
|
label = Gtk.Label.new(text)
|
|
label.set_xalign(0.0)
|
|
return label
|
|
|
|
def __create_filematch_dropdown(self,item,widget):
|
|
factory = Gtk.SignalListItemFactory()
|
|
factory.connect('setup',self._on_filematch_type_dropdown_setup)
|
|
factory.connect('bind',self._on_filematch_type_dropdown_bind)
|
|
|
|
dropdown = Gtk.DropDown(model=self.__filematch_dropdown_model,factory=factory)
|
|
return dropdown
|
|
|
|
def __create_filematch_widget(self,title:str):
|
|
widget = Gtk.Frame.new(title)
|
|
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL,2)
|
|
|
|
widget.actions = Gtk.ActionBar()
|
|
|
|
widget.add_button = Gtk.Button()
|
|
icon = Gtk.Image.new_from_icon_name('list-add-symbolic')
|
|
widget.add_button.set_child(icon)
|
|
widget.add_button.connect('clicked',self._on_filematch_add_button_clicked,widget)
|
|
widget.actions.pack_start(widget.add_button)
|
|
|
|
model = Gio.ListStore.new(GameFileMatcher)
|
|
selection = Gtk.SingleSelection.new(model)
|
|
selection.set_autoselect(False)
|
|
selection.set_can_unselect(True)
|
|
|
|
type_factory = Gtk.SignalListItemFactory()
|
|
type_factory.connect('setup',self._on_filematch_type_setup,widget)
|
|
type_factory.connect('bind',self._on_filematch_type_bind,widget)
|
|
|
|
value_factory = Gtk.SignalListItemFactory()
|
|
value_factory.connect('setup',self._on_filematch_value_setup,widget)
|
|
value_factory.connect('bind',self._on_filematch_value_bind,widget)
|
|
|
|
widget.columnview = Gtk.ColumnView.new(selection)
|
|
type_column = Gtk.ColumnViewColumn.new("Matcher",type_factory)
|
|
value_column = Gtk.ColumnViewColumn.new("Match value",value_factory)
|
|
value_column.set_expand(True)
|
|
widget.columnview.append_column(type_column)
|
|
widget.columnview.append_column(value_column)
|
|
|
|
vbox.append(widget.actions)
|
|
vbox.append(widget.columnview)
|
|
widget.set_child(vbox)
|
|
|
|
return widget
|
|
|
|
def __create_registry_key_widget(self,title):
|
|
widget = Gtk.Frame.new(title)
|
|
vbox=Gtk.Box.new(Gtk.Orientation.VERTICAL,2)
|
|
|
|
widget.actions = Gtk.ActionBar()
|
|
icon = Gtk.Image.new_from_icon_name("list-add-symbolic")
|
|
button = Gtk.Button.new()
|
|
button.set_child(icon)
|
|
button.connect('clicked',self._on_windows_regkey_add_button_clicked,widget)
|
|
widget.actions.pack_start(button)
|
|
|
|
model = Gio.ListStore.new(RegistryKeyData)
|
|
selection = Gtk.SingleSelection.new(model)
|
|
selection.set_autoselect(False)
|
|
selection.set_can_unselect(True)
|
|
|
|
factory = Gtk.SignalListItemFactory()
|
|
factory.connect('setup',self._on_windows_regkey_setup)
|
|
factory.connect('bind',self._on_windows_regkey_bind,widget)
|
|
|
|
widget.listview = Gtk.ListView.new(selection,factory)
|
|
|
|
vbox.append(widget.actions)
|
|
vbox.append(widget.listview)
|
|
widget.set_child(vbox)
|
|
|
|
return widget
|
|
|
|
@Property(type=bool,default=False)
|
|
def has_game(self)->bool:
|
|
return (self.__game is not None)
|
|
|
|
def reset(self):
|
|
"""
|
|
reset Resets the dialog to the Game set on init or clears the dialog if no Game was set.
|
|
"""
|
|
def set_variables(var_widget,vars:dict[str:str]|None):
|
|
model = var_widget.columnview.get_model().get_model()
|
|
model.remove_all()
|
|
if vars:
|
|
for k,v in vars.items():
|
|
model.append(GameVariableData(str(k),str(v)))
|
|
|
|
def set_game_widget_data(widget,data:GameData|None):
|
|
def set_filematch(fm_widget,filematchers:list[GameFileMatcher]):
|
|
model = fm_widget.columnview.get_model().get_model()
|
|
model.remove_all()
|
|
if filematchers:
|
|
for fm in filematchers:
|
|
model.append(GameFileMatcher(fm.match_type,fm.match_file))
|
|
|
|
|
|
|
|
widget.sgroot_entry.set_text(data.savegame_root if data else "")
|
|
widget.sgdir_entry.set_text(data.savegame_dir if data else "")
|
|
set_variables(widget.variables,data.variables if data else None)
|
|
set_filematch(widget.filematch,data.file_matchers if data else None)
|
|
set_filematch(widget.ignorematch,data.ignore_matchers if data else None)
|
|
|
|
self.__active_switch.set_active(self.__game.is_active if self.has_game else True)
|
|
self.__live_switch.set_active(self.__game.is_live if self.has_game else True)
|
|
self.__name_entry.set_text(self.__game.name if self.has_game else "")
|
|
self.__key_entry.set_text(self.__game.key if self.has_game else "")
|
|
self.__sgname_entry.set_text(self.__game.savegame_name if self.has_game else "")
|
|
set_variables(self.__game_variables,self.__game.variables if self.has_game else None)
|
|
|
|
if self.has_game:
|
|
model = self.__savegame_type_dropdown.get_model()
|
|
sgtype = self.__game.savegame_type
|
|
for i in range(model.get_n_items()):
|
|
item = model.get_item(i)
|
|
if sgtype == item.savegame_type:
|
|
self.__savegame_type_dropdown.set_selected(i)
|
|
break
|
|
|
|
#windows
|
|
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()
|
|
self.__windows.installdir_regkeys.listview.get_model().get_model().remove_all()
|
|
if self.has_game and self.__game.windows:
|
|
grk_model = self.__windows.lookup_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:
|
|
grk_model.append(RegistryKeyData(rk))
|
|
|
|
#set installdir regkeys
|
|
for rk in self.__game.windows.installdir_registry_keys:
|
|
irk_model.append(RegistryKeyData(rk))
|
|
|
|
#linux
|
|
set_game_widget_data(self.__linux,self.__game.linux if self.has_game else None)
|
|
self.__linux.binary_entry.set_text(self.__game.linux.binary
|
|
if self.has_game and self.__game.linux and self.__game.linux.binary else "")
|
|
|
|
#macos
|
|
set_game_widget_data(self.__macos,self.__game.macos if self.__game else None)
|
|
self.__macos.binary_entry.set_text(self.__game.macos.binary
|
|
if (self.has_game and self.__game.macos and self.__game.macos.binary) else "")
|
|
|
|
#steam
|
|
set_game_widget_data(self.__steam.windows,self.__game.steam.windows if self.has_game and self.__game.steam else None)
|
|
set_game_widget_data(self.__steam.linux,self.__game.steam.linux if self.has_game and self.__game.steam else None)
|
|
set_game_widget_data(self.__steam.macos,self.__game.steam.macos if self.has_game and self.__game.steam else None)
|
|
|
|
self.__steam.appid_entry.set_text(str(self.__game.steam.appid)
|
|
if self.has_game and self.__game.steam else "")
|
|
self.__steam.windows.installdir_entry.set_text(self.__game.steam.windows.installdir
|
|
if self.has_game
|
|
and self.__game.steam
|
|
and self.__game.steam.windows
|
|
and self.__game.steam.windows.installdir
|
|
else "")
|
|
self.__steam.linux.installdir_entry.set_text(self.__game.steam.linux.installdir
|
|
if self.has_game
|
|
and self.__game.steam
|
|
and self.__game.steam.linux
|
|
and self.__game.steam.linux.installdir
|
|
else "")
|
|
self.__steam.macos.installdir_entry.set_text(self.__game.steam.macos.installdir
|
|
if self.has_game
|
|
and self.__game.steam
|
|
and self.__game.steam.macos
|
|
and self.__game.steam.macos.installdir
|
|
else "")
|
|
|
|
# Epic Games
|
|
set_game_widget_data(self.__epic.windows,self.__game.epic.windows if self.has_game and self.__game.epic else None)
|
|
|
|
self.__epic.appname_entry.set_text(self.__game.epic.appname if self.has_game and self.__game.epic else "")
|
|
self.__epic.windows.installdir_entry.set_text(self.__game.epic.windows.installdir
|
|
if self.has_game
|
|
and self.__game.epic
|
|
and self.__game.epic.windows
|
|
and self.__game.epic.windows.installdir
|
|
else "")
|
|
# reset()
|
|
|
|
def save(self):
|
|
"""
|
|
save Saves the game configuration to file.
|
|
"""
|
|
def get_game_data(widget):
|
|
fm_model = widget.filematch.columnview.get_model().get_model()
|
|
im_model = widget.ignorematch.columnview.get_model().get_model()
|
|
var_model = widget.variables.columnview.get_model().get_model()
|
|
|
|
filematch = []
|
|
ignorematch = []
|
|
variables = {}
|
|
|
|
for i in range(fm_model.get_n_items()):
|
|
fm_data = fm_model.get_item(i)
|
|
filematch.append(fm_data)
|
|
|
|
for i in range(im_model.get_n_items()):
|
|
im_data = im_model.get_item(i)
|
|
ignorematch.append(im_data)
|
|
|
|
for i in range(var_model.get_n_items()):
|
|
var = var_model.get_item(i)
|
|
variables[var.name] = var.value
|
|
|
|
return {
|
|
'sgroot': widget.sgroot_entry.get_text(),
|
|
'sgdir': widget.sgdir_entry.get_text(),
|
|
'filematch': filematch,
|
|
'ignorematch': ignorematch,
|
|
'variables': variables,
|
|
}
|
|
|
|
def get_steam_data(widget):
|
|
conf = get_game_data(widget)
|
|
conf.update({
|
|
'installdir': widget.installdir_entry.get_text(),
|
|
})
|
|
return conf
|
|
|
|
def get_epic_data(widget):
|
|
conf = get_game_data(widget)
|
|
conf.update({'installdir':widget.installdir_entry.get_text()})
|
|
if not self.get_is_valid():
|
|
return
|
|
|
|
variables = {}
|
|
var_model = self.__game_variables.columnview.get_model().get_model()
|
|
for i in range(var_model.get_n_items()):
|
|
var = var_model.get_item(i)
|
|
variables[var.name] = var.value
|
|
key = self.__key_entry.get_text()
|
|
name = self.__name_entry.get_text()
|
|
savegame_name = self.__sgname_entry.get_text()
|
|
savegame_type = self.__savegame_type_dropdown.get_selected_item().savegame_type
|
|
if self.has_game:
|
|
if self.__game.key != key:
|
|
GameManager.get_global().remove_game(self.__game)
|
|
|
|
self.__game.key = key
|
|
self.__game.name = name
|
|
self.__game.savegame_type = savegame_type
|
|
self.__game.savegame_name = savegame_name
|
|
self.__game.variables = variables
|
|
self.__game.filename = '.'.join((self.__game.key,'gameconf'))
|
|
else:
|
|
self.__game = Game(key,name,savegame_name)
|
|
self.__game.savegame_type = savegame_type
|
|
self.__game.variables = variables
|
|
|
|
if self.get_is_valid_savegame_type(SavegameType.WINDOWS):
|
|
data = get_game_data(self.__windows)
|
|
installdir = self.__windows.installdir_entry.get_text()
|
|
grk_model = self.__windows.lookup_regkeys.listview.get_model().get_model()
|
|
irk_model = self.__windows.installdir_regkeys.listview.get_model().get_model()
|
|
grk = []
|
|
irk = []
|
|
|
|
for i in range(grk_model.get_n_items()):
|
|
item = grk_model.get_item(i)
|
|
if item.regkey:
|
|
grk.append(item.regkey)
|
|
|
|
for i in range(irk_model.get_n_items()):
|
|
item = irk_model.get_item(i)
|
|
if item.regkey:
|
|
irk.append(item.regkey)
|
|
|
|
if self.__game.windows:
|
|
wg = self.__game.windows
|
|
wg.savegame_root = data['sgroot']
|
|
wg.savegame_dir = data['sgdir']
|
|
wg.variables = data['variables']
|
|
wg.file_matchers = data["filematch"]
|
|
wg.ignore_matchers = data['ignorematch']
|
|
wg.installdir = installdir
|
|
wg.game_registry_keys = grk
|
|
wg.installdir_registry_keys = irk
|
|
else:
|
|
self.__game.windows = WindowsGame(data['sgroot'],
|
|
data['sgdir'],
|
|
data['variables'],
|
|
installdir,
|
|
grk,
|
|
irk,
|
|
data['filematch'],
|
|
data['ignorematch'])
|
|
elif self.__game.windows:
|
|
self.__game.windows = None
|
|
|
|
if self.get_is_valid_savegame_type(SavegameType.LINUX):
|
|
data = get_game_data(self.__linux)
|
|
binary = self.__linux.binary_entry.get_text()
|
|
if self.__game.linux:
|
|
lg = self.__game.linux
|
|
lg.savegame_root = data['sgroot']
|
|
lg.savegame_dir = data['sgdir']
|
|
lg.variables = data['variables']
|
|
lg.file_matchers = data["filematch"]
|
|
lg.ignore_matchers = data['ignorematch']
|
|
lg.binary = binary
|
|
else:
|
|
self.__game.linux = LinuxGame(data["sgroot"],
|
|
data['sgdir'],
|
|
data["variables"],
|
|
binary,
|
|
data["filematch"],
|
|
data['ignorematch'])
|
|
elif self.__game.linux:
|
|
self.__game_linux = None
|
|
|
|
if self.get_is_valid_savegame_type(SavegameType.MACOS):
|
|
data = get_game_data(self.__macos)
|
|
binary = self.__macos.binary_entry.get_text()
|
|
if self.__game.macos:
|
|
mg = self.__game.macos
|
|
mg.savegame_root = data['sgroot']
|
|
mg.savegame_dir = data['sgdir']
|
|
mg.variables = data['variables']
|
|
mg.file_matchers = data["filematch"]
|
|
mg.ignore_matchers = data['ignorematch']
|
|
mg.binary = binary
|
|
else:
|
|
self.__game.macos = MacOSGame(data["sgroot"],
|
|
data['sgdir'],
|
|
data["variables"],
|
|
binary,
|
|
data["filematch"],
|
|
data['ignorematch'])
|
|
elif self.__game.macos:
|
|
self.__game.macos = None
|
|
|
|
if (self.get_is_valid_savegame_type(SavegameType.STEAM_WINDOWS)
|
|
or self.get_is_valid_savegame_type(SavegameType.STEAM_LINUX)
|
|
or self.get_is_valid_savegame_type(SavegameType.STEAM_MACOS)):
|
|
|
|
if self.__game.steam:
|
|
self.__game.steam.appid = int(self.__steam.appid_entry.get_text())
|
|
else:
|
|
self.__game.steam = SteamGameData(int(self.__steam.appid_entry.get_text()))
|
|
|
|
|
|
if self.get_is_valid_savegame_type(SavegameType.STEAM_WINDOWS):
|
|
data = get_steam_data(self.__steam.windows)
|
|
if self.__game.steam.windows:
|
|
g = self.__game.steam.windows
|
|
g.savegame_root = data['sgroot']
|
|
g.savegame_dir = data['sgdir']
|
|
g.variables = data['variables']
|
|
g.file_matchers = data["filematch"]
|
|
g.ignore_matchers = data['ignorematch']
|
|
g.installdir = data['installdir']
|
|
else:
|
|
self.__game.steam.windows = SteamWindowsData(savegame_root=data['sgroot'],
|
|
savegame_dir=data['sgdir'],
|
|
variables=data['variables'],
|
|
installdir=data['installdir'],
|
|
file_match=data['filematch'],
|
|
ignore_match=data['ignorematch'])
|
|
elif self.__game.steam.windows:
|
|
self.__game.steam.windows = None
|
|
|
|
if self.get_is_valid_savegame_type(SavegameType.STEAM_LINUX):
|
|
data = get_steam_data(self.__steam.linux)
|
|
if self.__game.steam.linux:
|
|
g = self.__game.steam.linux
|
|
g.savegame_root = data['sgroot']
|
|
g.savegame_dir = data['sgdir']
|
|
g.variables = data['variables']
|
|
g.file_matchers = data["filematch"]
|
|
g.ignore_matchers = data['ignorematch']
|
|
g.installdir = data['installdir']
|
|
else:
|
|
self.__game.steam.linux = SteamLinuxData(savegame_root=data['sgroot'],
|
|
savegame_dir=data['sgdir'],
|
|
variables=data['variables'],
|
|
installdir=data['installdir'],
|
|
file_match=data['filematch'],
|
|
ignore_match=data['ignorematch'])
|
|
elif self.__game.steam.linux:
|
|
self.__game.steam.linux = None
|
|
|
|
if self.get_is_valid_savegame_type(SavegameType.STEAM_MACOS):
|
|
data = get_steam_data(self.__steam.macos)
|
|
if self.__game.steam.macos:
|
|
g = self.__game.steam.macos
|
|
g.savegame_root = data['sgroot']
|
|
g.savegame_dir = data['sgdir']
|
|
g.variables = data['variables']
|
|
g.file_matchers = data["filematch"]
|
|
g.ignore_matchers = data['ignorematch']
|
|
g.installdir = data['installdir']
|
|
else:
|
|
self.__game.steam.macos = SteamMacOSData(savegame_root=data['sgroot'],
|
|
savegame_dir=data['sgdir'],
|
|
variables=data['variables'],
|
|
installdir=data['installdir'],
|
|
file_match=data['filematch'],
|
|
ignore_match=data['ignorematch'])
|
|
elif self.__game.steam.macos:
|
|
self.__game.steam.macos = None
|
|
# END: steam
|
|
|
|
# BEGIN: epic
|
|
if self.get_is_valid_savegame_type(SavegameType.EPIC_WINDOWS):
|
|
data = get_epic_data(self.__epic.windows)
|
|
|
|
if self.__game.epic:
|
|
self.__game.epic.appname = self.__epic.appname_entry.get_text()
|
|
else:
|
|
self.__game.epic = EpicGameData(appname=self.__epic.appname_entry.get_text())
|
|
|
|
if self.__game.epic.windows:
|
|
self.__game.epic.windows.savegame_root = data['sgroot']
|
|
self.__game.epic.windows.savegame_dir = data['sgdir']
|
|
self.__game.epic.windows.variables = data['variables']
|
|
self.__game.epic.windows.file_matchers = data['filematch']
|
|
self.__game.epic.windows.ignore_matchers = data['ignorematch']
|
|
self.__game.epic.windows.installdir = data['installdir']
|
|
else:
|
|
self.__game.epic.windows = EpicWindowsData(savegame_root=data['sgroot'],
|
|
savegame_dir=data['sgdir'],
|
|
variables=data['variables'],
|
|
file_match=data['filematch'],
|
|
ignore_match=data['ignorematch'],
|
|
installdir=data['installdir'])
|
|
# END: epic
|
|
|
|
self.__game.save()
|
|
GameManager.get_global().add_game(self.__game)
|
|
|
|
|
|
def get_is_valid(self)->bool:
|
|
"""
|
|
get_is_valid Check if the configuration is valid for saving.
|
|
|
|
:returns: `True` if the game data is valid.
|
|
:rtype: bool
|
|
"""
|
|
|
|
if (self.__key_entry.get_text() and self.__name_entry.get_text() and self.__sgname_entry.get_text()):
|
|
sgtype_data = self.__savegame_type_dropdown.get_selected_item()
|
|
return self.get_is_valid_savegame_type(sgtype_data.savegame_type)
|
|
return False
|
|
|
|
def get_is_valid_savegame_type(self,sgtype:SavegameType)->bool:
|
|
"""
|
|
get_is_valid_savegame_type Check if the data for a SavegameType savegame is valid.
|
|
|
|
:param sgtype: The type of the Savegame provider
|
|
:type: sgbackup.game.SavegameType
|
|
:returns: bool
|
|
"""
|
|
|
|
def check_is_valid(widget):
|
|
return (len(widget.sgroot_entry.get_text().strip()) > 0
|
|
and len(widget.sgdir_entry.get_text().strip()) > 0)
|
|
|
|
if sgtype == SavegameType.WINDOWS:
|
|
return check_is_valid(self.__windows)
|
|
elif sgtype == SavegameType.LINUX:
|
|
return check_is_valid(self.__linux)
|
|
elif sgtype == SavegameType.MACOS:
|
|
return check_is_valid(self.__macos)
|
|
elif sgtype == SavegameType.STEAM_WINDOWS:
|
|
return check_is_valid(self.__steam.windows)
|
|
elif sgtype == SavegameType.STEAM_LINUX:
|
|
return check_is_valid(self.__steam.linux)
|
|
elif sgtype == SavegameType.STEAM_MACOS:
|
|
return check_is_valid(self.__steam.macos)
|
|
elif sgtype == SavegameType.EPIC_WINDOWS:
|
|
return check_is_valid(self.__epic.windows)
|
|
#elif sgtype == SavegameType.EPIC_LINUX:
|
|
# return check_is_valid(self.__epic_linux)
|
|
#elif sgtype == SavegameType.GOG_WINDOWS:
|
|
# return check_is_valid(self.__gog_windows)
|
|
#elif sgtype == SavegameType.GOG_LINUX:
|
|
# return check_is_valid(self.__gog_linux)
|
|
return False
|
|
|
|
def _on_savegame_type_setup(self,factory,item):
|
|
vbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL,4)
|
|
vbox.icon = Gtk.Image()
|
|
vbox.label = Gtk.Label()
|
|
|
|
vbox.append(vbox.icon)
|
|
vbox.append(vbox.label)
|
|
item.set_child(vbox)
|
|
|
|
def _on_savegame_type_bind(self,factory,item):
|
|
vbox = item.get_child()
|
|
data = item.get_item()
|
|
vbox.icon.props.icon_name = data.icon_name
|
|
vbox.label.set_text(data.name)
|
|
|
|
def _on_savegame_type_changed(self):
|
|
self.__apply_button.set_sensitive(self.get_is_valid())
|
|
|
|
def _on_variable_name_setup(self,factory,item):
|
|
label = Gtk.Label()
|
|
item.set_child(label)
|
|
|
|
def _on_variable_name_bind(self,factory,item):
|
|
label = item.get_child()
|
|
data = item.get_item()
|
|
if not hasattr(label,'_property_data_to_label_binding'):
|
|
label._property_data_to_label_binding = data.bind_property('name',label,'label',BindingFlags.SYNC_CREATE)
|
|
|
|
def _on_variable_value_setup(self,factory,item):
|
|
label = Gtk.Label()
|
|
item.set_child(label)
|
|
|
|
def _on_variable_value_bind(self,factory,item):
|
|
label = item.get_child()
|
|
data = item.get_item()
|
|
if not hasattr(label,'_property_value_to_label_binding'):
|
|
label._property_value_to_label_binding = data.bind_property('value',label,'label',BindingFlags.SYNC_CREATE)
|
|
|
|
def _on_filematch_dropdown_selection_changed(self,dropdown,data,item):
|
|
data = item.get_item()
|
|
data.match_type = dropdown.get_selected_item().match_type
|
|
|
|
def _on_filematch_type_dropdown_setup(self,factory,item):
|
|
label = Gtk.Label()
|
|
item.set_child(label)
|
|
|
|
def _on_filematch_type_dropdown_bind(self,factory,item):
|
|
label = item.get_child()
|
|
data = item.get_item()
|
|
label.set_text(data.name)
|
|
|
|
def _on_filematch_type_setup(self,factory,item,widget):
|
|
item.set_child(self.__create_filematch_dropdown(item,widget))
|
|
|
|
def _on_filematch_type_bind(self,factory,item,widget):
|
|
dropdown = item.get_child()
|
|
data = item.get_item()
|
|
for i in range(self.__filematch_dropdown_model.get_n_items()):
|
|
if (data.match_type == self.__filematch_dropdown_model.get_item(i).match_type):
|
|
dropdown.set_selected(i)
|
|
break
|
|
if not hasattr(dropdown,'_signal_notify_selected_item_connector'):
|
|
dropdown._signal_notify_selected_item_connector = dropdown.connect('notify::selected-item',self._on_filematch_dropdown_selection_changed,item)
|
|
|
|
def _on_filematch_value_setup(self,factory,item,widget):
|
|
label = Gtk.EditableLabel()
|
|
item.set_child(label)
|
|
|
|
def _on_filematch_value_bind(self,factory,item,widget):
|
|
label = item.get_child()
|
|
data = item.get_item()
|
|
if (data.match_file):
|
|
label.set_text(data.match_file)
|
|
|
|
if not hasattr(label,'_property_text_to_matchfile_binding'):
|
|
label._property_text_to_matchfile_binding = label.bind_property('text',data,'match_file',BindingFlags.DEFAULT)
|
|
if not hasattr(label,'_signal_notify_editing_connector'):
|
|
label._signal_notify_editing_connector = label.connect('notify::editing',self._on_filematch_value_notify_editing,widget)
|
|
|
|
if not label.get_text():
|
|
label.grab_focus()
|
|
label.start_editing()
|
|
|
|
def _on_windows_regkey_setup(self,factory,item):
|
|
label = Gtk.EditableLabel()
|
|
item.set_child(label)
|
|
|
|
def _on_windows_regkey_bind(self,factory,item,widget):
|
|
label = item.get_child()
|
|
data = item.get_item()
|
|
label.set_text(data.regkey)
|
|
label.bind_property('text',data,'regkey',BindingFlags.DEFAULT)
|
|
label.connect('notify::editing',self._on_windows_regkey_label_notify_editing,widget)
|
|
if not label.get_text():
|
|
label.start_editing()
|
|
label.grab_focus()
|
|
|
|
def _on_stack_sidebar_selected_rows_changed(self,sidebar):
|
|
row = sidebar.get_selected_row()
|
|
self.__stack.set_visible_child_name(row.get_child().page_name)
|
|
|
|
def _on_variables_add_button_clicked(self,button,columnview):
|
|
dialog = GameVariableDialog(self,columnview)
|
|
dialog.present()
|
|
|
|
def _on_variables_remove_button_clicked(self,button,columnview):
|
|
selection = columnview.get_model()
|
|
model = selection.get_model()
|
|
selected = selection.get_selected()
|
|
if selected == Gtk.INVALID_LIST_POSITION:
|
|
return
|
|
model.remove(selected)
|
|
|
|
def _on_variables_edit_buton_clicked(self,button,columnview):
|
|
data = columnview.get_model().get_selected()
|
|
if data:
|
|
dialog = GameVariableDialog(self,columnview,data)
|
|
dialog.present()
|
|
|
|
def _on_variable_selection_changed(self,selection,position,n_items,var_widget):
|
|
if (selection.get_model().get_n_items() == 0) or (selection.get_selected() == Gtk.INVALID_LIST_POSITION):
|
|
var_widget.edit_button.set_sensitive(False)
|
|
var_widget.remove_button.set_sensitive(False)
|
|
else:
|
|
var_widget.edit_button.set_sensitive(True)
|
|
var_widget.remove_button.set_sensitive(True)
|
|
|
|
def _on_filematch_add_button_clicked(self,button,widget):
|
|
widget.columnview.get_model().get_model().append(GameFileMatcher(GameFileType.GLOB,""))
|
|
|
|
def _on_filematch_value_label_changed(self,label,widget):
|
|
if not label.get_text().strip():
|
|
model = widget.columnview.get_model().get_model()
|
|
i = 0
|
|
for i in reversed(range(model.get_n_items())):
|
|
item = model.get_item(i)
|
|
if not item.match_file.strip():
|
|
model.remove(i)
|
|
|
|
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
|
|
for i in reversed(range(model.get_n_items())):
|
|
item = model.get_item(i)
|
|
if not item.match_file.strip():
|
|
model.remove(i)
|
|
|
|
def _on_windows_regkey_add_button_clicked(self,button,widget):
|
|
widget.listview.get_model().get_model().append(RegistryKeyData())
|
|
|
|
def _on_windows_regkey_label_notify_editing(self,label,state,widget):
|
|
if not label.get_editing():
|
|
if not label.get_text():
|
|
model = widget.listview.get_model().get_model()
|
|
i = 0
|
|
for i in reversed(range(model.get_n_items())):
|
|
item = model.get_item(i)
|
|
if not item.regkey:
|
|
model.remove(i)
|
|
|
|
def do_response(self,response):
|
|
if (response == Gtk.ResponseType.APPLY):
|
|
self.save()
|
|
self.emit('apply')
|
|
|
|
self.hide()
|
|
self.destroy()
|
|
|
|
@Signal(name='apply',flags=SignalFlags.RUN_FIRST,return_type=None,arg_types=())
|
|
def do_apply(self):
|
|
pass
|
|
|
|
### GameSearchDialog ##########################################################
|
|
|
|
class GameSearchDialogData(GObject):
|
|
def __init__(self,game:Game,fuzzy_match:float=0.0):
|
|
GObject.__init__(self)
|
|
self.__game = game
|
|
self.__fuzzy_match = fuzzy_match
|
|
|
|
@Property
|
|
def game(self)->Game:
|
|
return self.__game
|
|
|
|
@Property(type=float)
|
|
def fuzzy_match(self)->float:
|
|
return self.__fuzzy_match
|
|
|
|
@fuzzy_match.setter
|
|
def fuzzy_match(self,match:float):
|
|
self.__fuzzy_match = match
|
|
|
|
|
|
class GameSearchDialogDataSorter(Gtk.Sorter):
|
|
def do_compare(self,item1:GameSearchDialogData,item2:GameSearchDialogData):
|
|
if (item1.fuzzy_match > item2.fuzzy_match):
|
|
return Gtk.Ordering.SMALLER
|
|
elif (item1.fuzzy_match < item2.fuzzy_match):
|
|
return Gtk.Ordering.LARGER
|
|
|
|
name1 = item1.game.name.lower()
|
|
name2 = item2.game.name.lower()
|
|
|
|
if (name1 > name2):
|
|
return Gtk.Ordering.LARGER
|
|
elif (name1 < name2):
|
|
return Gtk.Ordering.SMALLER
|
|
return Gtk.Ordering.EQUAL
|
|
|
|
class GameSearchDialogDataNameSorter(Gtk.Sorter):
|
|
def do_compare(self,item1:GameSearchDialogData,item2:GameSearchDialogData):
|
|
name1 = item1.game.name.lower()
|
|
name2 = item2.game.name.lower()
|
|
|
|
if (name1 > name2):
|
|
return Gtk.Ordering.LARGER
|
|
elif (name1 < name2):
|
|
return Gtk.Ordering.SMALLER
|
|
return Gtk.Ordering.EQUAL
|
|
|
|
|
|
class GameSearchDialogDataFilter(Gtk.Filter):
|
|
def do_match(self,item:GameSearchDialogData):
|
|
return (item.fuzzy_match > 0.0)
|
|
|
|
|
|
class GameSearchDialog(Gtk.Dialog):
|
|
def __init__(self,
|
|
parent:Gtk.Window|None=None,
|
|
search_name:str|None=None,
|
|
title:str|None=None):
|
|
Gtk.Dialog.__init__(self)
|
|
self.set_title("SGBackup: {title}".format(
|
|
title=title if title else _("Search for games")
|
|
))
|
|
|
|
if parent:
|
|
self.set_transient_for(parent)
|
|
|
|
self.search_name = search_name
|
|
|
|
self.__actionbar = Gtk.ActionBar()
|
|
new_game_button = Gtk.Button()
|
|
icon = Gtk.Image.new_from_icon_name('list-add-symbolic')
|
|
icon.set_pixel_size(16)
|
|
new_game_button.set_child(icon)
|
|
new_game_button.connect('clicked',self._on_new_game_button_clicked)
|
|
self.__actionbar.pack_start(new_game_button)
|
|
|
|
self.__action_hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL,2)
|
|
label = Gtk.Label.new(_("Enable Search?"))
|
|
self.__search_switch = Gtk.Switch()
|
|
self.__search_switch.set_active(bool(self.search_name))
|
|
self.__search_switch.set_sensitive(bool(self.search_name))
|
|
|
|
self.__action_hbox.append(label)
|
|
self.__action_hbox.append(self.__search_switch)
|
|
self.__actionbar.pack_end(self.__action_hbox)
|
|
|
|
self.get_content_area().append(self.__actionbar)
|
|
|
|
scrolled = Gtk.ScrolledWindow()
|
|
self.__liststore = Gio.ListStore()
|
|
for i in self.__get_search_games(search_name):
|
|
self.__liststore.append(GameSearchDialogData(**i))
|
|
self.__sort_model = Gtk.SortListModel(model=self.__liststore,sorter=GameSearchDialogDataSorter())
|
|
self.__filter_model = Gtk.FilterListModel(model=self.__sort_model,
|
|
filter=GameSearchDialogDataFilter() if search_name else None)
|
|
selection = Gtk.SingleSelection(model=self.__filter_model,autoselect=False,can_unselect=True)
|
|
|
|
factory = Gtk.SignalListItemFactory()
|
|
factory.connect('setup',self._on_listview_setup)
|
|
factory.connect('bind',self._on_listview_bind)
|
|
|
|
self.__listview = Gtk.ListView(model=selection,factory=factory)
|
|
scrolled.set_child(self.__listview)
|
|
|
|
self.get_content_area().append(scrolled)
|
|
|
|
self.add_button("Close",Gtk.ResponseType.OK)
|
|
|
|
def __get_search_games(self,search_name:str|None)->list:
|
|
games=[]
|
|
game_names=[]
|
|
|
|
gm = GameManager.get_global()
|
|
for g in gm.games.values():
|
|
games.append({'game':g,'fuzzy_match':0.0})
|
|
game_names.append(g.name)
|
|
|
|
if search_name:
|
|
result = rapidfuzz.process.extract(
|
|
query=search_name,
|
|
choices=game_names,
|
|
limit=20,
|
|
scorer=rapidfuzz.fuzz.WRatio)
|
|
|
|
for choice,score,index in result:
|
|
games[index]['fuzzy_match']=score
|
|
|
|
return games
|
|
|
|
def _on_listview_setup(self,factory,item):
|
|
child = Gtk.Grid()
|
|
child.set_column_spacing(4)
|
|
child.set_row_spacing(2)
|
|
|
|
child.name_label=Gtk.Label()
|
|
child.name_label.set_xalign(0.0)
|
|
child.name_label.set_hexpand(True)
|
|
child.attach(child.name_label,1,0,1,1)
|
|
|
|
label = Gtk.Label.new(_("Key:"))
|
|
label.set_xalign(0.0)
|
|
child.key_label = Gtk.Label()
|
|
child.key_label.set_xalign(0.0)
|
|
child.key_label.set_hexpand(True)
|
|
child.attach(label,0,1,1,1)
|
|
child.attach(child.key_label,1,1,1,1)
|
|
|
|
label = Gtk.Label.new(_("Platform:"))
|
|
label.set_xalign(0.0)
|
|
child.platform_hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL,4)
|
|
child.platform_hbox.set_hexpand(True)
|
|
child.platform_hbox._is_bound = False
|
|
child.attach(label,0,2,1,1)
|
|
child.attach(child.platform_hbox,1,2,1,1)
|
|
|
|
action_grid = Gtk.Grid()
|
|
icon = Gtk.Image.new_from_icon_name('document-edit-symbolic')
|
|
icon.set_pixel_size(16)
|
|
child.edit_button = Gtk.Button()
|
|
child.edit_button.set_child(icon)
|
|
action_grid.attach(child.edit_button,0,1,1,1)
|
|
child.attach(action_grid,2,0,1,3)
|
|
|
|
item.set_child(child)
|
|
|
|
def _on_listview_bind(self,factory,item):
|
|
def add_platform_icon(child,provider:GameProvider):
|
|
icon = Gtk.Image.new_from_icon_name(GAME_PROVIDER_ICONS[provider])
|
|
icon.set_pixel_size(16)
|
|
child.platform_hbox.append(icon)
|
|
|
|
child = item.get_child()
|
|
data = item.get_item()
|
|
|
|
child.name_label.set_markup("<span weight='bold' size='large'>{}</span>".format(
|
|
GLib.markup_escape_text(data.game.name)))
|
|
child.key_label.set_text(data.game.key)
|
|
|
|
if not child.platform_hbox._is_bound:
|
|
child.platform_hbox._is_bound = True
|
|
if data.game.windows:
|
|
add_platform_icon(child,GameProvider.WINDOWS)
|
|
if data.game.linux:
|
|
add_platform_icon(child,GameProvider.LINUX)
|
|
if data.game.macos:
|
|
add_platform_icon(child,GameProvider.MACOS)
|
|
if data.game.steam:
|
|
add_platform_icon(child,GameProvider.STEAM)
|
|
if data.game.epic:
|
|
add_platform_icon(child,GameProvider.EPIC_GAMES)
|
|
#if data.game.gog:
|
|
# add_platform_icon(child,GameProvider.GOG)
|
|
|
|
if hasattr(child.edit_button,'_signal_clicked_connector'):
|
|
child.edit_button.disconnect(child.edit_button._signal_clicked_connector)
|
|
child.edit_button._signal_clicked_connector = child.edit_button.connect('clicked',
|
|
self._on_edit_button_clicked,
|
|
data.game)
|
|
|
|
|
|
def do_prepare_game(self,game:Game|None):
|
|
if game is None:
|
|
return Game("",self.serch_name,"")
|
|
else:
|
|
return game
|
|
|
|
def _on_new_game_button_clicked(self,button):
|
|
def on_response(dialog,response,parent):
|
|
if response == Gtk.ResponseType.APPLY:
|
|
parent.refresh()
|
|
|
|
game = self.do_prepare_game(None)
|
|
parent = self.get_Transient_for()
|
|
dialog = GameDialog(parent=parent,game=game)
|
|
if hasattr(parent,"refresh"):
|
|
dialog.connect('response',on_response)
|
|
dialog.present()
|
|
self.response(Gtk.ResponseType.OK)
|
|
|
|
def _on_edit_button_clicked(self,button:Gtk.Button,game:Game):
|
|
def on_response(dialog,response,parent):
|
|
if response == Gtk.ResponseType.APPLY:
|
|
parent.refresh()
|
|
|
|
try:
|
|
game = self.do_prepare_game()
|
|
except Exception as ex:
|
|
dialog = Gtk.MessageDialog(
|
|
message=_("Unable to edit game <i>{}</i>!".format(GLib.markup_escape_text(game.name))),
|
|
use_markup=True,
|
|
secondary_message=str(ex),
|
|
secondary_use_markup=False,
|
|
transient_for=self.get_transient_for(),
|
|
parent=self.get_transient_for(),
|
|
buttons=Gtk.Buttons.OK
|
|
)
|
|
dialog.connect('response',lambda dialog,response: dialog.destroy())
|
|
dialog.present()
|
|
return
|
|
|
|
parent = self.get_transient_for()
|
|
dialog = GameDialog(parent=parent,game=game)
|
|
if hasattr(parent,"refresh"):
|
|
dialog.connect('response',on_response,parent)
|
|
dialog.present()
|
|
self.response(Gtk.ResponseType.OK)
|
|
|
|
def _on_search_switch_state_set(self,switch:Gtk.Switch,state:bool):
|
|
if state:
|
|
self.__sort_model.set_sorter(GameSearchDialogDataSorter())
|
|
self.__filter_model.set_filter(GameSearchDialogDataFilter())
|
|
else:
|
|
self.__sort_model.set_sorter(GameSearchDialogDataNameSorter())
|
|
self.__filter_model.set_filter(None)
|
|
|
|
@Property(type=str)
|
|
def search_name(self)->str:
|
|
return self.__search_name if self.__search_name else ""
|
|
|
|
@search_name.setter
|
|
def search_name(self,name:str):
|
|
if not name:
|
|
self.__search_name = None
|
|
else:
|
|
self.__search_name = name
|
|
|
|
def do_response(self,response):
|
|
self.hide()
|
|
self.destroy() |