mirror of
https://github.com/c9moser/sgbackup.git
synced 2026-01-19 19:40:13 +00:00
2025.02.16 16:06:32 (desktop)
This commit is contained in:
parent
4aa56401e8
commit
f9f4adaf22
@ -224,7 +224,7 @@ class GameFileMatcher(GObject):
|
||||
raise TypeError("match_type is not a GameFileType instance!")
|
||||
self.__match_type = match_type
|
||||
|
||||
@Property
|
||||
@Property(type=str)
|
||||
def match_file(self)->str:
|
||||
"""
|
||||
match_file The matcher value.
|
||||
|
||||
@ -36,7 +36,67 @@ from ..archiver import ArchiverManager
|
||||
|
||||
__gtype_name__ = __name__
|
||||
|
||||
class GameView(Gtk.ScrolledWindow):
|
||||
class GameViewKeySorter(Gtk.Sorter):
|
||||
def __init__(self,sort_ascending:bool=True,*args,**kwargs):
|
||||
Gtk.Sorter.__init__(self)
|
||||
|
||||
self.sort_ascending = sort_ascending
|
||||
|
||||
@Property(type=bool,default=True)
|
||||
def sort_ascending(self)->bool:
|
||||
return self.__sort_ascending
|
||||
@sort_ascending.setter
|
||||
def sort_ascending(self,asc:bool):
|
||||
self.__sort_ascending = asc
|
||||
|
||||
def do_compare(self,game1,game2):
|
||||
if self.sort_ascending:
|
||||
if game1.key > game2.key:
|
||||
return Gtk.Ordering.LARGER
|
||||
elif game1.key < game2.key:
|
||||
return Gtk.Ordering.SMALLER
|
||||
else:
|
||||
return Gtk.Ordering.EQUAL
|
||||
else:
|
||||
if game1.key < game2.key:
|
||||
return Gtk.Ordering.LARGER
|
||||
elif game1.key > game2.key:
|
||||
return Gtk.Ordering.SMALLER
|
||||
else:
|
||||
return Gtk.Ordering.EQUAL
|
||||
|
||||
class GameViewNameSorter(Gtk.Sorter):
|
||||
def __init__(self,sort_ascending:bool=True,*args,**kwargs):
|
||||
Gtk.Sorter.__init__(self)
|
||||
|
||||
self.sort_ascending = sort_ascending
|
||||
|
||||
@Property(type=bool,default=True)
|
||||
def sort_ascending(self)->bool:
|
||||
return self.__sort_ascending
|
||||
@sort_ascending.setter
|
||||
def sort_ascending(self,asc:bool):
|
||||
self.__sort_ascending = asc
|
||||
|
||||
def do_compare(self,game1,game2):
|
||||
name1 = game1.name.lower()
|
||||
name2 = game2.name.lower()
|
||||
|
||||
if self.sort_ascending:
|
||||
if name1 > name2:
|
||||
return Gtk.Ordering.LARGER
|
||||
elif name1 < name2:
|
||||
return Gtk.Ordering.SMALLER
|
||||
else:
|
||||
return Gtk.Ordering.EQUAL
|
||||
else:
|
||||
if name1 < name2:
|
||||
return Gtk.Ordering.LARGER
|
||||
elif name1 > name2:
|
||||
return Gtk.Ordering.SMALLER
|
||||
else:
|
||||
return Gtk.Ordering.EQUAL
|
||||
class GameView(Gtk.Box):
|
||||
"""
|
||||
GameView The View for games.
|
||||
|
||||
@ -48,19 +108,70 @@ class GameView(Gtk.ScrolledWindow):
|
||||
"""
|
||||
GameView
|
||||
"""
|
||||
Gtk.ScrolledWindow.__init__(self)
|
||||
Gtk.Box.__init__(self,orientation=Gtk.Orientation.VERTICAL)
|
||||
self.__key_sorter = GameViewKeySorter(True)
|
||||
self.__name_sorter = GameViewNameSorter(True)
|
||||
|
||||
scrolled = Gtk.ScrolledWindow()
|
||||
scrolled.set_vexpand(True)
|
||||
scrolled.set_hexpand(True)
|
||||
|
||||
# set up the ActionBar for this widget
|
||||
self.__actionbar = Gtk.ActionBar()
|
||||
self.actionbar.set_hexpand(True)
|
||||
|
||||
icon = Gtk.Image.new_from_icon_name('list-add-symbolic')
|
||||
icon.set_pixel_size(16)
|
||||
add_game_button=Gtk.Button()
|
||||
add_game_button.set_child(icon)
|
||||
add_game_button.set_tooltip_text("Add a new game.")
|
||||
add_game_button.connect('clicked',self._on_add_game_button_clicked)
|
||||
self.actionbar.pack_start(add_game_button)
|
||||
|
||||
|
||||
icon = Gtk.Image.new_from_icon_name('steam-svgrepo-com-symbolic')
|
||||
icon.set_pixel_size(16)
|
||||
new_steam_games_button=Gtk.Button()
|
||||
new_steam_games_button.set_child(icon)
|
||||
new_steam_games_button.set_tooltip_text("Manage new Steam-Apps")
|
||||
new_steam_games_button.connect('clicked',self._on_new_steam_games_button_clicked)
|
||||
self.actionbar.pack_start(new_steam_games_button)
|
||||
|
||||
self.actionbar.pack_start(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL))
|
||||
|
||||
icon = Gtk.Image.new_from_icon_name('document-save-symbolic')
|
||||
icon.set_pixel_size(16)
|
||||
backup_active_live_button = Gtk.Button()
|
||||
backup_active_live_button.set_child(icon)
|
||||
backup_active_live_button.set_tooltip_markup("Backup all <i>active</i> and <i>live</i> Games.")
|
||||
backup_active_live_button.connect('clicked',self._on_backup_active_live_button_clicked)
|
||||
self.actionbar.pack_start(backup_active_live_button)
|
||||
|
||||
|
||||
|
||||
# Add a the search entry
|
||||
|
||||
self.__search_entry = Gtk.Entry()
|
||||
self.__search_entry.set_hexpand(True)
|
||||
self.actionbar.pack_end(self.__search_entry)
|
||||
self.actionbar.pack_end(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL))
|
||||
|
||||
self.append(self.actionbar)
|
||||
|
||||
|
||||
self.__liststore = Gio.ListStore.new(Game)
|
||||
for g in GameManager.get_global().games.values():
|
||||
pass
|
||||
self.__liststore.append(g)
|
||||
|
||||
self.__sort_model = Gtk.SortListModel.new(self._liststore,self.__name_sorter)
|
||||
self.__sort_model
|
||||
self.__action_dialog = None
|
||||
self.__backup_dialog = None
|
||||
|
||||
factory_icon = Gtk.SignalListItemFactory.new()
|
||||
factory_icon.connect('setup',self._on_icon_column_setup)
|
||||
factory_icon.connect('bind',self._on_icon_column_bind)
|
||||
factory_icon.connect('unbind',self._on_icon_column_unbind)
|
||||
column_icon = Gtk.ColumnViewColumn.new("",factory_icon)
|
||||
|
||||
factory_key = Gtk.SignalListItemFactory.new()
|
||||
@ -89,10 +200,13 @@ class GameView(Gtk.ScrolledWindow):
|
||||
factory_actions = Gtk.SignalListItemFactory.new()
|
||||
factory_actions.connect('setup',self._on_actions_column_setup)
|
||||
factory_actions.connect('bind',self._on_actions_column_bind)
|
||||
#factory_actions.connect('ubind',self._on_actions_column_unbind)
|
||||
column_actions = Gtk.ColumnViewColumn.new("",factory_actions)
|
||||
|
||||
selection = Gtk.SingleSelection.new(self._liststore)
|
||||
selection = Gtk.SingleSelection.new(self.__sort_model)
|
||||
self.__columnview = Gtk.ColumnView.new(selection)
|
||||
self.columnview.set_vexpand(True)
|
||||
self.columnview.set_hexpand(True)
|
||||
self.columnview.append_column(column_icon)
|
||||
self.columnview.append_column(column_key)
|
||||
self.columnview.append_column(column_name)
|
||||
@ -101,8 +215,9 @@ class GameView(Gtk.ScrolledWindow):
|
||||
self.columnview.append_column(column_actions)
|
||||
self.columnview.set_single_click_activate(True)
|
||||
|
||||
scrolled.set_child(self.columnview)
|
||||
|
||||
self.set_child(self.columnview)
|
||||
self.append(scrolled)
|
||||
self.refresh()
|
||||
|
||||
@property
|
||||
@ -124,18 +239,65 @@ class GameView(Gtk.ScrolledWindow):
|
||||
"""
|
||||
return self.__columnview
|
||||
|
||||
@property
|
||||
def actionbar(self)->Gtk.ActionBar:
|
||||
return self.__actionbar
|
||||
|
||||
def refresh(self):
|
||||
"""
|
||||
refresh Refresh the view.
|
||||
|
||||
This method reloads the installed Games.
|
||||
"""
|
||||
self.__liststore.remove_all()
|
||||
self.emit('refresh')
|
||||
|
||||
@Signal(name="refresh",return_type=None,arg_types=(),flags=SignalFlags.RUN_FIRST)
|
||||
def do_refresh(self):
|
||||
self._liststore.remove_all()
|
||||
for game in GameManager.get_global().games.values():
|
||||
self.__liststore.append(game)
|
||||
self._liststore.append(game)
|
||||
|
||||
def _on_game_dialog_response(self,dialog,response):
|
||||
if response == Gtk.ResponseType.APPLY:
|
||||
self.refresh()
|
||||
|
||||
@Signal(name='game-active-changed',return_type=None,arg_types=(Game,),flags=SignalFlags.RUN_FIRST)
|
||||
def do_game_active_changed(self,game:Game):
|
||||
pass
|
||||
|
||||
@Signal(name='game-live-changed',return_type=None,arg_types=(Game,),flags=SignalFlags.RUN_FIRST)
|
||||
def do_game_live_changed(self,game:Game):
|
||||
pass
|
||||
|
||||
def _on_new_steamapps_dialog_response(self,dialog,response):
|
||||
self.refresh()
|
||||
|
||||
def _on_add_game_button_clicked(self,button):
|
||||
dialog = GameDialog(parent=self.get_root())
|
||||
dialog.connect('response',self._on_game_dialog_response)
|
||||
dialog.present()
|
||||
|
||||
def _on_new_steam_games_button_clicked(self,button):
|
||||
dialog = NewSteamAppsDialog(parent=self.get_root())
|
||||
dialog.connect('response',self._on_new_steamapps_dialog_response)
|
||||
dialog.present()
|
||||
|
||||
def _on_backup_active_live_button_clicked(self,button):
|
||||
backup_games = []
|
||||
for i in range(self._liststore.get_n_items()):
|
||||
game = self._liststore.get_item(i)
|
||||
if game.is_live and game.is_active and os.path.exists(os.path.join(game.savegame_root,game.savegame_dir)):
|
||||
backup_games.append(game)
|
||||
|
||||
# TODO:
|
||||
#dialog = BackupManyDialog(parent=self.get_root(),games=backup_games)
|
||||
#dialog.set_modal(False)
|
||||
#dialog.present()
|
||||
|
||||
def _on_icon_column_setup(self,factory,item):
|
||||
item.set_child(Gtk.Image())
|
||||
image = Gtk.Image()
|
||||
image.set_pixel_size(24)
|
||||
item.set_child(image)
|
||||
|
||||
def _on_icon_column_bind(self,factory,item):
|
||||
def transform_to_icon_name(_bidning,sgtype):
|
||||
@ -145,11 +307,19 @@ class GameView(Gtk.ScrolledWindow):
|
||||
return ""
|
||||
icon = item.get_child()
|
||||
game = item.get_item()
|
||||
game.bind_property('savegame_type',icon,'icon_name',BindingFlags.SYNC_CREATE,transform_to_icon_name)
|
||||
if not hasattr(game,'_savegame_type_to_icon_name_binding'):
|
||||
game._savegame_type_to_icon_name_binding = game.bind_property('savegame_type',icon,'icon_name',BindingFlags.SYNC_CREATE,transform_to_icon_name)
|
||||
|
||||
def _on_icon_column_unbind(self,factory,item):
|
||||
game = item.get_item()
|
||||
if hasattr(game,'_savegame_type_to_icon_name_binding'):
|
||||
game._savegame_type_to_icon_name_binding.unbind()
|
||||
del game._savegame_type_to_icon_name_binding
|
||||
|
||||
def _on_key_column_setup(self,factory,item):
|
||||
item.set_child(Gtk.Label())
|
||||
label = Gtk.Label()
|
||||
label.set_xalign(0.0)
|
||||
item.set_child(label)
|
||||
|
||||
def _on_key_column_bind(self,factory,item):
|
||||
label = item.get_child()
|
||||
@ -157,12 +327,21 @@ class GameView(Gtk.ScrolledWindow):
|
||||
game.bind_property('key',label,'label',BindingFlags.SYNC_CREATE)
|
||||
|
||||
def _on_name_column_setup(self,factory,item):
|
||||
item.set_child(Gtk.Label())
|
||||
label = Gtk.Label()
|
||||
label.set_xalign(0.0)
|
||||
label.set_use_markup(True)
|
||||
item.set_child(label)
|
||||
|
||||
def _on_name_column_bind(self,factory,item):
|
||||
label = item.get_child()
|
||||
game = item.get_item()
|
||||
game.bind_property('name',label,'label',BindingFlags.SYNC_CREATE)
|
||||
if not hasattr(label,'_property_label_from_name_binding'):
|
||||
label._property_label_from_name_binding = game.bind_property('name',
|
||||
label,
|
||||
'label',
|
||||
BindingFlags.SYNC_CREATE,
|
||||
lambda _binding,s: "<span weight='bold' size='large'>{}</span>".format(
|
||||
GLib.markup_escape_text(s)))
|
||||
|
||||
def _on_active_column_setup(self,factory,item):
|
||||
item.set_child(Gtk.Switch())
|
||||
@ -179,8 +358,9 @@ class GameView(Gtk.ScrolledWindow):
|
||||
del item._signal_active_state_set
|
||||
|
||||
def _on_active_state_set(self,switch,state,game):
|
||||
game.is_active = state
|
||||
game.is_active = switch.get_active()
|
||||
game.save()
|
||||
self.emit('game-active-changed',game)
|
||||
|
||||
def _on_live_column_setup(self,factory,item):
|
||||
item.set_child(Gtk.Switch())
|
||||
@ -189,6 +369,7 @@ class GameView(Gtk.ScrolledWindow):
|
||||
switch = item.get_child()
|
||||
game = item.get_item()
|
||||
switch.set_active(game.is_live)
|
||||
if not hasattr(item,'_signal_live_state_set'):
|
||||
item._signal_live_state_set = switch.connect('state-set',self._on_live_state_set,game)
|
||||
|
||||
def _on_live_column_unbind(self,factory,item):
|
||||
@ -198,24 +379,25 @@ class GameView(Gtk.ScrolledWindow):
|
||||
|
||||
def _on_live_state_set(self,switch,state,game):
|
||||
def on_dialog_response(dialog,response):
|
||||
if response == Gtk.ResponseType.YES:
|
||||
pass
|
||||
#archiver.backup(game)
|
||||
dialog.hide()
|
||||
dialog.destroy()
|
||||
|
||||
if response == Gtk.ResponseType.YES:
|
||||
dialog = BackupSingleDialog(parent=self.get_root(),game=game)
|
||||
dialog.run()
|
||||
|
||||
game.is_live = switch.get_active()
|
||||
game.save()
|
||||
if not game.is_live:
|
||||
dialog = Gtk.MessageDialog()
|
||||
dialog = Gtk.MessageDialog(buttons=Gtk.ButtonsType.YES_NO)
|
||||
dialog.set_transient_for(self.get_root())
|
||||
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.use_markup = True
|
||||
dialog.props.secondary_text = "The new savegame is added to the finsihed savegames for the game."
|
||||
dialog.props.secondary_use_markup = False
|
||||
dialog.connect('response',on_dialog_response)
|
||||
dialog.present()
|
||||
self.emit('game-live-changed',game)
|
||||
|
||||
def _on_actions_column_setup(self,action,item):
|
||||
child = Gtk.Box.new(Gtk.Orientation.HORIZONTAL,2)
|
||||
@ -241,15 +423,39 @@ class GameView(Gtk.ScrolledWindow):
|
||||
child = item.get_child()
|
||||
game = item.get_item()
|
||||
archiver_manager = ArchiverManager.get_global()
|
||||
child.backup_button.connect('clicked',self._on_columnview_backup_button_clicked,item)
|
||||
child.edit_button.connect('clicked',self._on_columnview_edit_button_clicked,item)
|
||||
child.remove_button.connect('clicked',self._on_columnview_remove_button_clicked,item)
|
||||
archiver_manager.bind_property('backup-in-progress',child.backup_button,'sensitive',
|
||||
BindingFlags.SYNC_CREATE,lambda binding,x: False if x else True)
|
||||
archiver_manager.bind_property('backup-in-progress',child.edit_button,'sensitive',
|
||||
BindingFlags.SYNC_CREATE,lambda binding,x: False if x else True)
|
||||
archiver_manager.bind_property('backup-in-progress',child.remove_button,'sensitive',
|
||||
BindingFlags.SYNC_CREATE,lambda binding,x: False if x else True)
|
||||
|
||||
if not hasattr(child.backup_button,'_signal_clicked_connection'):
|
||||
child.backup_button._signal_clicked_connection = child.backup_button.connect('clicked',self._on_columnview_backup_button_clicked,item)
|
||||
if not hasattr(child.backup_button,'_property_backup_in_progress_binding'):
|
||||
child.backup_button._property_backup_in_progress_binding = archiver_manager.bind_property('backup-in-progress',
|
||||
child.backup_button,
|
||||
'sensitive',
|
||||
BindingFlags.SYNC_CREATE,
|
||||
lambda binding,x: False if x else True)
|
||||
|
||||
if not hasattr(child.edit_button,'_signal_clicked_connection'):
|
||||
child.edit_button._signal_clicked_connection = child.edit_button.connect('clicked',self._on_columnview_edit_button_clicked,item)
|
||||
|
||||
if not hasattr(child.edit_button,'_property_backup_in_progress_binding'):
|
||||
child.edit_button._property_backup_in_progress_binding = archiver_manager.bind_property('backup-in-progress',
|
||||
child.edit_button,
|
||||
'sensitive',
|
||||
BindingFlags.SYNC_CREATE,
|
||||
lambda binding,x: False if x else True)
|
||||
|
||||
if not hasattr(child.remove_button,'_signal_clicked_connection'):
|
||||
child.remove_button._signal_clicked_connection = child.remove_button.connect('clicked',self._on_columnview_remove_button_clicked,item)
|
||||
if not hasattr(child.remove_button,'_property_backup_in_progress_binding'):
|
||||
child.remove_button._property_backup_in_progress_binding = archiver_manager.bind_property('backup-in-progress',
|
||||
child.remove_button,'sensitive',
|
||||
BindingFlags.SYNC_CREATE,
|
||||
lambda binding,x: False if x else True)
|
||||
|
||||
|
||||
if os.path.exists(os.path.join(game.savegame_root,game.savegame_dir)):
|
||||
child.backup_button.set_sensitive(True)
|
||||
else:
|
||||
child.backup_button.set_sensitive(False)
|
||||
|
||||
def _on_columnview_backup_button_clicked(self,button,item):
|
||||
def on_dialog_response(dialog,response):
|
||||
@ -361,7 +567,7 @@ class BackupViewData(GObject):
|
||||
|
||||
:type: bool
|
||||
"""
|
||||
pass
|
||||
return self.__is_live
|
||||
|
||||
@Property(type=str)
|
||||
def extension(self)->str:
|
||||
@ -571,11 +777,34 @@ class AppWindow(Gtk.ApplicationWindow):
|
||||
|
||||
vbox.append(self.__vpaned)
|
||||
|
||||
statusbar = Gtk.Statusbar()
|
||||
statusbar.set_hexpand(True)
|
||||
statusbar.set_vexpand(False)
|
||||
statusbar.push(0,'Running ...')
|
||||
vbox.append(statusbar)
|
||||
self.__statusbar = Gtk.Statusbar()
|
||||
self.statusbar.set_hexpand(True)
|
||||
self.statusbar.set_vexpand(False)
|
||||
self.gameview.connect('refresh',self._on_gameview_refresh)
|
||||
self.gameview.connect('game-active-changed',lambda gv,*data: self._on_gameview_refresh(gv))
|
||||
self.gameview.connect('game-live-changed',lambda gv,*data: self._on_gameview_refresh(gv))
|
||||
|
||||
n_games = self.gameview._liststore.get_n_items()
|
||||
n_live = 0
|
||||
n_active = 0
|
||||
n_finished = 0
|
||||
for i in range(n_games):
|
||||
game = self.gameview._liststore.get_item(i)
|
||||
if game.is_live:
|
||||
n_live += 1
|
||||
else:
|
||||
n_finished += 1
|
||||
|
||||
if game.is_active:
|
||||
n_active += 1
|
||||
|
||||
self.statusbar.push(0,'{games} Games -- {active} Games active -- {live} Games live -- {finished} Games finished'.format(
|
||||
games=n_games,
|
||||
active=n_active,
|
||||
live=n_live,
|
||||
finished=n_finished))
|
||||
|
||||
vbox.append(self.statusbar)
|
||||
|
||||
self.set_child(vbox)
|
||||
|
||||
@ -609,6 +838,10 @@ class AppWindow(Gtk.ApplicationWindow):
|
||||
"""
|
||||
return self.__gameview
|
||||
|
||||
@property
|
||||
def statusbar(self):
|
||||
return self.__statusbar
|
||||
|
||||
def refresh(self):
|
||||
"""
|
||||
refresh Refresh the views of this window.
|
||||
@ -617,6 +850,29 @@ class AppWindow(Gtk.ApplicationWindow):
|
||||
self.gameview.refresh()
|
||||
#self.backupview.refresh()
|
||||
|
||||
def _on_gameview_refresh(self,gameview):
|
||||
self.statusbar.pop(0)
|
||||
n_games = gameview._liststore.get_n_items()
|
||||
n_active = 0
|
||||
n_live = 0
|
||||
n_finished = 0
|
||||
for i in range(n_games):
|
||||
game = gameview._liststore.get_item(i)
|
||||
if game.is_live:
|
||||
n_live += 1
|
||||
else:
|
||||
n_finished += 1
|
||||
|
||||
if game.is_active:
|
||||
n_active += 1
|
||||
|
||||
self.statusbar.push(0,'{games} Games -- {active} Games active -- {live} Games live -- {finished} Games finished'.format(
|
||||
games=n_games,
|
||||
active=n_active,
|
||||
live=n_live,
|
||||
finished=n_finished))
|
||||
|
||||
|
||||
class Application(Gtk.Application):
|
||||
"""
|
||||
Application The `Gtk.Application` for this app.
|
||||
|
||||
@ -1025,9 +1025,9 @@ class GameDialog(Gtk.Dialog):
|
||||
self.__game_linux = None
|
||||
|
||||
if self.get_is_valid_savegame_type(SavegameType.MACOS):
|
||||
data = get_game_data(self.__linux)
|
||||
binary = self.__linux.binary_entry.get_text()
|
||||
if self.__game.linux:
|
||||
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']
|
||||
@ -1187,7 +1187,8 @@ class GameDialog(Gtk.Dialog):
|
||||
def _on_variable_name_bind(self,factory,item):
|
||||
label = item.get_child()
|
||||
data = item.get_item()
|
||||
data.bind_property('name',label,'label',BindingFlags.SYNC_CREATE)
|
||||
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()
|
||||
@ -1196,7 +1197,8 @@ class GameDialog(Gtk.Dialog):
|
||||
def _on_variable_value_bind(self,factory,item):
|
||||
label = item.get_child()
|
||||
data = item.get_item()
|
||||
data.bind_property('value',label,'label',BindingFlags.SYNC_CREATE)
|
||||
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()
|
||||
@ -1221,7 +1223,8 @@ class GameDialog(Gtk.Dialog):
|
||||
if (data.match_type == self.__filematch_dropdown_model.get_item(i).match_type):
|
||||
dropdown.set_selected(i)
|
||||
break
|
||||
dropdown.connect('notify::selected-item',self._on_filematch_dropdown_selection_changed,item)
|
||||
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()
|
||||
@ -1232,11 +1235,13 @@ class GameDialog(Gtk.Dialog):
|
||||
data = item.get_item()
|
||||
if (data.match_file):
|
||||
label.set_text(data.match_file)
|
||||
label.bind_property('text',data,'match_file',BindingFlags.DEFAULT)
|
||||
label.connect('notify::editing',self._on_filematch_value_notify_editing,widget)
|
||||
else:
|
||||
label.bind_property('text',data,'match_file',BindingFlags.DEFAULT)
|
||||
label.connect('notify::editing',self._on_filematch_value_notify_editing,widget)
|
||||
|
||||
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()
|
||||
|
||||
@ -1293,23 +1298,20 @@ class GameDialog(Gtk.Dialog):
|
||||
if not label.get_text().strip():
|
||||
model = widget.columnview.get_model().get_model()
|
||||
i = 0
|
||||
while i < model.get_n_items():
|
||||
for i in reversed(range(model.get_n_items())):
|
||||
item = model.get_item(i)
|
||||
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():
|
||||
for i in reversed(range(model.get_n_items())):
|
||||
item = model.get_item(i)
|
||||
if not item.match_file.strip():
|
||||
model.remove(i)
|
||||
continue
|
||||
i += 1
|
||||
|
||||
def _on_windows_regkey_add_button_clicked(self,button,widget):
|
||||
widget.listview.get_model().get_model().append(RegistryKeyData())
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
###############################################################################
|
||||
|
||||
from gi.repository import Gtk,GLib,Gio
|
||||
from gi.repository.GObject import GObject,Signal,Property,SignalFlags
|
||||
from gi.repository.GObject import GObject,Signal,Property,SignalFlags,BindingFlags
|
||||
|
||||
from ..settings import settings
|
||||
from ..archiver import ArchiverManager,Archiver
|
||||
@ -65,6 +65,38 @@ class ZipfileCompressorDataSorter(Gtk.Sorter):
|
||||
return Gtk.Ordering.EQUAL
|
||||
|
||||
|
||||
class VariableData(GObject):
|
||||
def __init__(self,name:str,value:str):
|
||||
GObject.__init__(self)
|
||||
self.__name = name
|
||||
self.__value = value
|
||||
|
||||
@Property(type=str)
|
||||
def name(self)->str:
|
||||
return self.__name
|
||||
|
||||
@name.setter
|
||||
def name(self,name:str):
|
||||
self.__name = name
|
||||
|
||||
@Property(type=str)
|
||||
def value(self)->str:
|
||||
return self.__value
|
||||
|
||||
@value.setter
|
||||
def value(self,value:str):
|
||||
self.__value = value
|
||||
|
||||
class VariableDataSorter(Gtk.Sorter):
|
||||
def do_compare(self,item1,item2):
|
||||
if (item1.name < item2.name):
|
||||
return Gtk.Ordering.SMALLER
|
||||
elif (item1.name > item2.name):
|
||||
return Gtk.Ordering.LARGER
|
||||
else:
|
||||
return Gtk.Ordering.EQUAL
|
||||
|
||||
|
||||
class SettingsDialog(Gtk.Dialog):
|
||||
def __init__(self,parent=None):
|
||||
Gtk.Dialog.__init__(self)
|
||||
@ -80,6 +112,7 @@ class SettingsDialog(Gtk.Dialog):
|
||||
self.__stack_sidebar = Gtk.StackSidebar.new()
|
||||
self.__general_page = self.__add_general_settings_page()
|
||||
self.__archiver_page = self.__add_archiver_settings_page()
|
||||
self.__variables_page = self.__add_variables_settings_page()
|
||||
|
||||
sidebar_scrolled=Gtk.ScrolledWindow()
|
||||
sidebar_scrolled.set_child(self.__stack_sidebar)
|
||||
@ -90,7 +123,6 @@ class SettingsDialog(Gtk.Dialog):
|
||||
paned.set_vexpand(True)
|
||||
self.__stack_sidebar.set_stack(self.__stack)
|
||||
|
||||
|
||||
vbox.append(paned)
|
||||
|
||||
self.add_button("Apply",Gtk.ResponseType.APPLY)
|
||||
@ -157,7 +189,6 @@ class SettingsDialog(Gtk.Dialog):
|
||||
grid.attach(page.archiver_dropdown,1,3,2,1)
|
||||
|
||||
|
||||
|
||||
vbox.append(grid)
|
||||
page.set_child(vbox)
|
||||
|
||||
@ -212,6 +243,99 @@ class SettingsDialog(Gtk.Dialog):
|
||||
self.add_page(page,"zipfile","Archiver Settings")
|
||||
return page
|
||||
|
||||
def _on_variable_add_button_clicked(self,button):
|
||||
variable_model = self.__variables_page.variable_columnview.get_model()
|
||||
while hasattr(variable_model,'get_model'):
|
||||
variable_model = variable_model.get_model()
|
||||
variable_model.append(VariableData("",""))
|
||||
|
||||
def __add_variables_settings_page(self):
|
||||
page = Gtk.Box.new(Gtk.Orientation.VERTICAL,0)
|
||||
|
||||
actions = Gtk.ActionBar()
|
||||
icon=Gtk.Image.new_from_icon_name('list-add-symbolic')
|
||||
button = Gtk.Button()
|
||||
button.set_child(icon)
|
||||
button.connect('clicked',self._on_variable_add_button_clicked)
|
||||
actions.pack_end(button)
|
||||
page.append(actions)
|
||||
|
||||
scrolled = Gtk.ScrolledWindow()
|
||||
|
||||
model = Gio.ListStore.new(VariableData)
|
||||
for vname,vvalue in settings.variables.items():
|
||||
model.append(VariableData(vname,vvalue))
|
||||
|
||||
sorted_model = Gtk.SortListModel.new(model,VariableDataSorter())
|
||||
|
||||
vname_factory = Gtk.SignalListItemFactory()
|
||||
vname_factory.connect('setup',self._on_variable_name_factory_setup)
|
||||
vname_factory.connect('bind',self._on_variable_name_factory_bind)
|
||||
|
||||
vvalue_factory = Gtk.SignalListItemFactory()
|
||||
vvalue_factory.connect('setup',self._on_variable_value_factory_setup)
|
||||
vvalue_factory.connect('bind',self._on_variable_value_factory_bind)
|
||||
|
||||
selection = Gtk.SingleSelection(model=sorted_model)
|
||||
page.variable_columnview = Gtk.ColumnView.new(selection)
|
||||
|
||||
vname_column = Gtk.ColumnViewColumn.new("Name",vname_factory)
|
||||
vname_column.set_expand(True)
|
||||
page.variable_columnview.append_column(vname_column)
|
||||
|
||||
vvalue_column = Gtk.ColumnViewColumn.new("Value",vvalue_factory)
|
||||
page.variable_columnview.append_column(vvalue_column)
|
||||
|
||||
page.variable_columnview.set_vexpand(True)
|
||||
scrolled.set_child(page.variable_columnview)
|
||||
scrolled.set_hexpand(True)
|
||||
page.append(scrolled)
|
||||
|
||||
self.add_page(page,"variables","Variables")
|
||||
|
||||
return page
|
||||
|
||||
|
||||
def _on_variable_name_notify_editing(self,label,param,*data):
|
||||
if label.props.editing == False:
|
||||
if not label.get_text():
|
||||
model = self.__variables_page.variable_columnview.get_model()
|
||||
while hasattr(model,'get_model'):
|
||||
model = model.get_model()
|
||||
|
||||
for i in reversed(range(model.get_n_items())):
|
||||
if not model.get_item(i).name:
|
||||
model.remove(i)
|
||||
|
||||
|
||||
def _on_variable_name_factory_setup(self,factory,item):
|
||||
label = Gtk.EditableLabel()
|
||||
item.set_child(label)
|
||||
|
||||
def _on_variable_name_factory_bind(self,factory,item):
|
||||
data = item.get_item()
|
||||
label = item.get_child()
|
||||
label.set_text(data.name)
|
||||
if not hasattr(label,'_property_text_to_name_binding'):
|
||||
label._property_text_to_name_binding = label.bind_property('text',data,'name',BindingFlags.DEFAULT)
|
||||
if not hasattr(label,'_signal_notify_editing_connection'):
|
||||
label._signal_notify_editing_connection = label.connect('notify::editing',self._on_variable_name_notify_editing)
|
||||
|
||||
if not data.name:
|
||||
label.grab_focus()
|
||||
label.start_editing()
|
||||
|
||||
def _on_variable_value_factory_setup(self,factory,item):
|
||||
label = Gtk.EditableLabel()
|
||||
item.set_child(label)
|
||||
|
||||
def _on_variable_value_factory_bind(self,factory,item):
|
||||
label = item.get_child()
|
||||
data = item.get_item()
|
||||
label.set_text(data.value)
|
||||
if not hasattr(label,'_property_text_to_value_binding'):
|
||||
label._property_text_to_value_binding = label.bind_property('text',data,'name',BindingFlags.DEFAULT)
|
||||
|
||||
def _on_archiver_factory_setup(self,factory,item):
|
||||
label = Gtk.Label()
|
||||
item.set_child(label)
|
||||
@ -277,4 +401,13 @@ class SettingsDialog(Gtk.Dialog):
|
||||
settings.zipfile_compression = self.archiver_page.zf_compressor_dropdown.get_selected_item().compressor
|
||||
settings.zipfile_compresslevel = self.archiver_page.zf_compresslevel_spinbutton.get_value_as_int()
|
||||
|
||||
variables = {}
|
||||
variable_model = self.__variables_page.variable_columnview.get_model()
|
||||
while hasattr(variable_model,'get_model'):
|
||||
variable_model = variable_model.get_model()
|
||||
for i in range(variable_model.get_n_items()):
|
||||
vdata = variable_model.get_item(i)
|
||||
if vdata.name:
|
||||
variables[vdata.name] = vdata.value
|
||||
settings.variables = variables
|
||||
|
||||
@ -223,6 +223,7 @@ class NewSteamAppsDialog(Gtk.Dialog):
|
||||
self.__listview = Gtk.ListView.new(selection,factory)
|
||||
self.__listview.set_vexpand(True)
|
||||
self.__listview.set_show_separators(True)
|
||||
self.__listview.set_single_click_activate(True)
|
||||
|
||||
scrolled = Gtk.ScrolledWindow()
|
||||
scrolled.set_child(self.__listview)
|
||||
@ -286,8 +287,10 @@ class NewSteamAppsDialog(Gtk.Dialog):
|
||||
child.name_label.set_markup("<span weight='bold' size='large'>{}</span>".format(GLib.markup_escape_text(data.name)))
|
||||
child.appid_label.set_text(str(data.appid))
|
||||
child.installdir_label.set_text(data.installdir)
|
||||
child.add_app_button.connect('clicked',self._on_add_steamapp_button_clicked,data)
|
||||
child.ignore_app_button.connect('clicked',self._on_ignore_steamapp_button_clicked,data)
|
||||
if not hasattr(child.add_app_button,'_signal_clicked_connector'):
|
||||
child.add_app_button._signal_clicked_connector = child.add_app_button.connect('clicked',self._on_add_steamapp_button_clicked,data)
|
||||
if not hasattr(child.ignore_app_button,'_signal_clicked_connector'):
|
||||
child.ignore_app_button._signal_clicked_connector = child.ignore_app_button.connect('clicked',self._on_ignore_steamapp_button_clicked,data)
|
||||
|
||||
def _on_add_steamapp_button_clicked(self,button,data:SteamApp,*args):
|
||||
def on_dialog_response(dialog,response):
|
||||
|
||||
@ -14,12 +14,12 @@
|
||||
<attribute name='label' translatable='true'>_Steam</attribute>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name='label' translatable='true'>Manage libraries</attribute>
|
||||
<attribute name='action'>app.steam-manage-libraries</attribute>
|
||||
<attribute name='label' translatable='true'>New Steam Apps</attribute>
|
||||
<attribute name='action'>app.steam-new-apps</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name='label' translatable='true'>Manage new apps</attribute>
|
||||
<attribute name='action'>app.steam-new-apps</attribute>
|
||||
<attribute name='label' translatable='true'>Manage Steam Libraries</attribute>
|
||||
<attribute name='action'>app.steam-manage-libraries</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</submenu>
|
||||
|
||||
@ -396,6 +396,9 @@ class Settings(GObject.GObject):
|
||||
return self.get_string('variables',name,"")
|
||||
|
||||
def get_variables(self)->dict[str:str]:
|
||||
if PLATFORM_WINDOWS:
|
||||
ret = dict(((name.upper(),value) for name,value in os.environ.items()))
|
||||
else:
|
||||
ret = dict(os.environ)
|
||||
ret.update({
|
||||
"DOCUMENTS": GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOCUMENTS),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user