added contextmenu to gui.BackupView

This commit is contained in:
Christian Moser 2025-02-28 17:25:02 +01:00
parent 4801bcf7a1
commit 084808a408
Failed to extract signature
6 changed files with 280 additions and 37 deletions

View File

@ -4,7 +4,7 @@
SELF="$( realpath "$0" )"
PROJECT_DIR="$( dirname "$SELF")"
PACKAGES="gtk4 gobject-introspection python-gobject python-rapidfuzz"
PACKAGES="gtk4 gobject-introspection python-pip python-gobject python-rapidfuzz"
_install_pkg="base-devel"
for i in $PACKAGES; do
@ -15,7 +15,7 @@ pacman -Sy
pacman -S --noconfirm $_install_pkg
cd $PROJECT_DIR
pip install --user .
pip install --break-system-packages --verbose --user .
bindir=$( realpath ~/bin )
wbindir=$( cygpath -w "$bindir" )

View File

@ -22,7 +22,7 @@ import rapidfuzz
import logging; logger=logging.getLogger(__name__)
import os
import os,sys
from datetime import datetime as DateTime
from pathlib import Path
@ -641,7 +641,6 @@ class GameView(Gtk.Box):
dialog.set_modal(False)
dialog.connect('response',on_dialog_response,game)
dialog.present()
# GameView class
class BackupViewData(GObject):
@ -709,15 +708,28 @@ class BackupViewData(GObject):
def savegame_type_icon_name(self)->str:
return SAVEGAME_TYPE_ICONS[self.__sgtype]
@Property(type=str)
def savegame_os(self)->str:
return self.__sgos
@Property(type=bool,default=False)
def savegame_os_is_host_os(self):
platform = "unknown"
if (sys.platform.lower().startswith('win')):
platform = 'windows'
elif (sys.platform.lower() == 'macos'):
paltform = 'macos'
elif (sys.platform.lower() in ('linux','freebsd','netbsd','openbsd','dragonfly')):
platform = 'linux'
return (self.savegame_os == platform)
@Property(type=str)
def savegame_os_icon_name(self)->str:
if self.__sgos:
return SAVEGAME_TYPE_ICONS[self.__sgos]
return ""
@Property(type=str)
def ostype_icon_name(self):
pass
@Property(type=str)
def savegame_name(self)->str:
@ -786,6 +798,10 @@ class BackupView(Gtk.Box):
scrolled = Gtk.ScrolledWindow()
self.__gameview = gameview
self.__action_group = Gio.SimpleActionGroup.new()
self.__create_actions()
self.insert_action_group("backupview",self.action_group)
self.__liststore = Gio.ListStore()
selection = Gtk.SingleSelection.new(self.__liststore)
@ -836,6 +852,18 @@ class BackupView(Gtk.Box):
self.append(self._title_label)
self.append(scrolled)
gesture = Gtk.GestureClick.new()
gesture.set_button(3)
self.__columnview.add_controller(gesture)
gesture.connect('pressed',self._on_gesture_button3_press)
builder = Gtk.Builder()
builder.add_from_file(os.path.join(os.path.dirname(__file__),'appmenu.ui'))
self.__contextmenu_model = builder.get_object('backupview-contextmenu')
self.__contextmenu_popover = Gtk.PopoverMenu.new_from_model(self.__contextmenu_model)
self.__contextmenu_popover.set_parent(self.__columnview)
self.__contextmenu_popover.set_has_arrow(False)
@property
def gameview(self)->GameView:
"""
@ -845,6 +873,111 @@ class BackupView(Gtk.Box):
"""
return self.__gameview
@property
def action_group(self)->Gio.SimpleActionGroup:
return self.__action_group
def __create_actions(self):
self.__restore_action = Gio.SimpleAction.new("restore",None)
self.__restore_action.connect('activate',self._on_action_restore)
self.action_group.add_action(self.__restore_action)
self.__convert_to_windows_action = Gio.SimpleAction.new("convert-to-windows",None)
self.__convert_to_windows_action.connect('activate',self._on_action_convert_to_windows)
self.action_group.add_action(self.__convert_to_windows_action)
self.__convert_to_linux_action = Gio.SimpleAction.new("convert-to-linux",None)
self.__convert_to_linux_action.connect('activate',self._on_action_convert_to_linux)
self.action_group.add_action(self.__convert_to_linux_action)
self.__convert_to_macos_action = Gio.SimpleAction.new("convert-to-macos",None)
self.__convert_to_macos_action.connect('activate',self._on_action_convert_to_macos)
self.action_group.add_action(self.__convert_to_macos_action)
self.__convert_to_epic_linux_action = Gio.SimpleAction.new("convert-to-epic-linux",None)
self.__convert_to_epic_linux_action.connect('activate',self._on_action_convert_to_epic_linux)
self.action_group.add_action(self.__convert_to_epic_linux_action)
self.__convert_to_epic_windows_action = Gio.SimpleAction.new("convert-to-epic-windows",None)
self.__convert_to_epic_windows_action.connect('activate',self._on_action_convert_to_epic_windows)
self.action_group.add_action(self.__convert_to_epic_windows_action)
self.__convert_to_gog_linux_action = Gio.SimpleAction.new("convert-to-gog-linux",None)
self.__convert_to_gog_linux_action.connect('activate',self._on_action_convert_to_gog_linux)
self.action_group.add_action(self.__convert_to_gog_linux_action)
self.__convert_to_gog_windows_action = Gio.SimpleAction.new("convert-to-gog-windows",None)
self.__convert_to_gog_windows_action.connect('activate',self._on_action_convert_to_gog_windows)
self.action_group.add_action(self.__convert_to_gog_windows_action)
self.__convert_to_steam_linux_action = Gio.SimpleAction.new("convert-to-steam-linux",None)
self.__convert_to_steam_linux_action.connect('activate',self._on_action_convert_to_steam_linux)
self.action_group.add_action(self.__convert_to_steam_linux_action)
self.__convert_to_steam_macos_action = Gio.SimpleAction.new("convert-to-steam-macos",None)
self.__convert_to_steam_macos_action.connect('activate',self._on_action_convert_to_steam_macos)
self.action_group.add_action(self.__convert_to_steam_macos_action)
self.__convert_to_steam_windows_action = Gio.SimpleAction.new("convert-to-steam-windows",None)
self.__convert_to_steam_windows_action.connect('activate',self._on_action_convert_to_steam_windows)
self.action_group.add_action(self.__convert_to_steam_windows_action)
def _on_action_restore(self,action,param):
pass
def _on_action_convert_to_windows(self,action,param):
pass
def _on_action_convert_to_linux(self,action,param):
pass
def _on_action_convert_to_macos(self,action,param):
pass
def _on_action_convert_to_steam_windows(self,action,param):
pass
def _on_action_convert_to_steam_linux(self,action,param):
pass
def _on_action_convert_to_steam_macos(self,action,param):
pass
def _on_action_convert_to_epic_windows(self,action,param):
pass
def _on_action_convert_to_epic_linux(self,action,param):
pass
def _on_action_convert_to_gog_windows(self,action_param):
pass
def _on_action_convert_to_gog_linux(self,action,param):
pass
def _on_gesture_button3_press(self,gesture,n_press,x,y):
item = self.__columnview.get_model().get_selected_item()
self.__restore_action.set_enabled(item.savegame_os_is_host_os)
#######################################################################
#TODO: implement converter
self.__convert_to_linux_action.set_enabled(False)
self.__convert_to_macos_action.set_enabled(False)
self.__convert_to_windows_action.set_enabled(False)
self.__convert_to_epic_linux_action.set_enabled(False)
self.__convert_to_epic_windows_action.set_enabled(False)
self.__convert_to_gog_linux_action.set_enabled(False)
self.__convert_to_gog_windows_action.set_enabled(False)
self.__convert_to_steam_linux_action.set_enabled(False)
self.__convert_to_steam_macos_action.set_enabled(False)
self.__convert_to_steam_windows_action.set_enabled(False)
#######################################################################
self.__contextmenu_popover.popup()
def _on_sgtype_column_setup(self,factory,item):
icon = Gtk.Image()
icon.set_pixel_size(16)
@ -876,7 +1009,6 @@ class BackupView(Gtk.Box):
data = item.get_item()
checkbutton.set_active(data.is_live)
def _on_savegamename_column_setup(self,factory,item):
label = Gtk.Label()
item.set_child(label)

View File

@ -19,8 +19,10 @@
from gi.repository import Gtk,GLib,GObject,Gio
from ..game import GameManager,Game
from ..archiver import ArchiverManager
from ..settings import settings
from threading import Thread,ThreadError
import logging
logger = logging.getLogger(__name__)
@ -73,8 +75,8 @@ class BackupSingleDialog(Gtk.Dialog):
am.disconnect(self.__am_signal_progress)
del self.__am_signal_progress
#if settings.backup_dialog_close_when_finished:
# self.response(Gtk.ResponseType.OK)
if settings.gui_autoclose_backup_dialog:
self.response(Gtk.ResponseType.OK)
return False
@ -253,11 +255,13 @@ class BackupManyDialog(Gtk.Dialog):
GLib.idle_add(self._on_backup_finished)
if not self.games:
print("no games to backup!")
self.desotroy()
logger.warning("No games to backup!")
self.hide()
self.destroy()
self.response(Gtk.Response.OK)
return
self.__ok_button.set_sensitive(False)
am = ArchiverManager.get_global()
@ -274,13 +278,12 @@ class BackupManyDialog(Gtk.Dialog):
self.__signal_backup_game_finished = am.connect('backup-game-finished',
on_am_backup_game_finished)
print ("Starting thread")
print(self.games)
thread = Thread(target=thread_func,args=(am,list(self.__games)),daemon=True)
self.present()
thread.start()
def _on_column_name_setup(self,factory,item):
label = Gtk.Label()
label.set_xalign(0.0)
@ -361,6 +364,9 @@ class BackupManyDialog(Gtk.Dialog):
am.disconnect(self.__signal_backup_progress)
del self.__signal_backup_progress
if settings.gui_autoclose_backup_dialog:
self.response(Gtk.ResponseType.OK)
return False

View File

@ -128,6 +128,31 @@ class SettingsDialog(Gtk.Dialog):
self.add_button("Apply",Gtk.ResponseType.APPLY)
self.add_button("Cancel",Gtk.ResponseType.CANCEL)
def create_frame(self,label_text:str):
label = Gtk.Label()
label.set_markup("<span weight=\"bold\">{}</span>".format(GLib.markup_escape_text(label_text)))
frame = Gtk.Frame()
frame.set_label_widget(label)
frame.set_margin_start(5)
frame.set_margin_end(5)
frame.set_margin_top(5)
frame.set_margin_bottom(5)
return frame
def create_grid(self):
grid = Gtk.Grid()
grid.set_margin_start(5)
grid.set_margin_end(5)
grid.set_margin_top(5)
grid.set_margin_bottom(5)
grid.set_column_spacing(3)
return grid
def create_label(self,label_text:str):
label = Gtk.Label.new(label_text)
label.set_xalign(0.0)
return label
@property
def general_page(self):
return self.__general_page
@ -136,14 +161,18 @@ class SettingsDialog(Gtk.Dialog):
def archiver_page(self):
return self.__archiver_page
@property
def variables_page(self):
return self.__variables_page
def __add_general_settings_page(self):
page = Gtk.ScrolledWindow()
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL,8)
backup_frame = Gtk.Frame.new('Backup Settings')
backup_frame = self.create_frame('Backup Settings')
grid = Gtk.Grid()
grid = self.create_grid()
label = Gtk.Label.new('Backup directory:')
label = self.create_label('Backup directory:')
grid.attach(label,0,0,1,1)
page.backupdir_label = Gtk.Label.new(settings.backup_dir)
page.backupdir_label.set_hexpand(True)
@ -155,21 +184,21 @@ class SettingsDialog(Gtk.Dialog):
backupdir_button.connect('clicked',self._on_backupdir_button_clicked)
grid.attach(backupdir_button,2,0,1,1)
label = Gtk.Label.new('Backup versions:')
label = self.create_label('Backup versions:')
grid.attach(label,0,1,1,1)
page.backup_versions_spinbutton = Gtk.SpinButton.new_with_range(0,1000,1)
page.backup_versions_spinbutton.set_hexpand(True)
page.backup_versions_spinbutton.set_value(settings.backup_versions)
grid.attach(page.backup_versions_spinbutton,1,1,2,1)
label = Gtk.Label.new('Max. Backup Threads:')
label = self.create_label('Max. Backup Threads:')
page.backup_threads_spinbutton = Gtk.SpinButton.new_with_range(1,256,1)
page.backup_threads_spinbutton.set_hexpand(True)
page.backup_threads_spinbutton.set_value(settings.backup_threads)
grid.attach(label,0,2,1,1)
grid.attach(page.backup_threads_spinbutton,1,2,2,1)
label = Gtk.Label.new("Archiver:")
label = self.create_label("Archiver:")
archiver_model = Gio.ListStore.new(Archiver)
for archiver in ArchiverManager.get_global().archivers.values():
archiver_model.append(archiver)
@ -192,17 +221,18 @@ class SettingsDialog(Gtk.Dialog):
backup_frame.set_child(grid)
vbox.append(backup_frame)
search_frame = Gtk.Frame.new('Search Settings')
search_grid = Gtk.Grid()
### Search Settings
search_frame = self.create_frame('Search Settings')
search_grid = self.create_grid()
label = Gtk.Label.new("Minimum Characters:")
label = self.create_label("Minimum Characters:")
page.search_minchars_spinbutton = Gtk.SpinButton.new_with_range(1,32,1)
page.search_minchars_spinbutton.set_value(settings.search_min_chars)
page.search_minchars_spinbutton.set_hexpand(True)
search_grid.attach(label,0,0,1,1)
search_grid.attach(page.search_minchars_spinbutton,1,0,1,1)
label = Gtk.Label.new("Maximum Results:")
label = self.create_label("Maximum Results:")
page.search_maxresults_spinbutton = Gtk.SpinButton.new_with_range(1,100,1)
page.search_maxresults_spinbutton.set_value(settings.search_max_results)
page.search_maxresults_spinbutton.set_hexpand(True)
@ -212,6 +242,31 @@ class SettingsDialog(Gtk.Dialog):
search_frame.set_child(search_grid)
vbox.append(search_frame)
### GUI settings
gui_frame = self.create_frame('GUI')
gui_grid = self.create_grid()
label = self.create_label("Automatic close Backup Dialogs?")
page.gui_autoclose_backup_dialog_switch = Gtk.Switch()
page.gui_autoclose_backup_dialog_switch.set_active(settings.gui_autoclose_backup_dialog)
filler = Gtk.Label()
filler.set_hexpand(True)
gui_grid.attach(label,0,0,1,1)
gui_grid.attach(filler,1,0,1,1)
gui_grid.attach(page.gui_autoclose_backup_dialog_switch,2,0,1,1)
label = self.create_label("Automatic close Restore Dialogs?")
page.gui_autoclose_restore_dialog_switch = Gtk.Switch()
page.gui_autoclose_restore_dialog_switch.set_active(settings.gui_autoclose_restore_dialog)
filler = Gtk.Label()
filler.set_hexpand(True)
gui_grid.attach(label,0,1,1,1)
gui_grid.attach(filler,1,1,1,1)
gui_grid.attach(page.gui_autoclose_restore_dialog_switch,2,1,1,1)
gui_frame.set_child(gui_grid)
vbox.append(gui_frame)
page.set_child(vbox)
self.add_page(page,"general","Generic settings")
return page
@ -219,10 +274,8 @@ class SettingsDialog(Gtk.Dialog):
def __add_archiver_settings_page(self):
page = Gtk.ScrolledWindow()
page.vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL,4)
self._widget_set_margin(page.vbox,4)
grid = Gtk.Grid()
self._widget_set_margin(grid,4)
grid = self.create_grid()
zf_compressors = [
(zipfile.ZIP_STORED,"Stored",True),
@ -231,8 +284,8 @@ class SettingsDialog(Gtk.Dialog):
(zipfile.ZIP_LZMA,"LZMA",False),
]
zipfile_frame = Gtk.Frame.new("ZipFile Archiver")
label = Gtk.Label.new("Compressor:")
zipfile_frame = self.create_frame("ZipFile Archiver")
label = self.create_label("Compressor:")
zf_compressor_model = Gio.ListStore.new(ZipfileCompressorData)
for i in zf_compressors:
zf_compressor_model.append(ZipfileCompressorData(*i))
@ -250,7 +303,7 @@ class SettingsDialog(Gtk.Dialog):
grid.attach(label,0,0,1,1)
grid.attach(page.zf_compressor_dropdown,1,0,1,1)
label = Gtk.Label.new("Compression Level:")
label = self.create_label("Compression Level:")
page.zf_compresslevel_spinbutton = Gtk.SpinButton.new_with_range(0.0,9.0,1.0)
page.zf_compresslevel_spinbutton.set_value(settings.zipfile_compresslevel)
page.zf_compresslevel_spinbutton.set_hexpand(True)
@ -419,12 +472,13 @@ class SettingsDialog(Gtk.Dialog):
settings.backup_versions = self.general_page.backup_versions_spinbutton.get_value_as_int()
settings.backup_threads = self.general_page.backup_threads_spinbutton.get_value_as_int()
settings.archiver = self.general_page.archiver_dropdown.get_selected_item().key
settings.gui_autoclose_backup_dialog = self.general_page.gui_autoclose_backup_dialog_switch.get_active()
settings.gui_autoclose_restore_dialog = self.general_page.gui_autoclose_restore_dialog_switch.get_active()
settings.search_min_chars = self.general_page.search_minchars_spinbutton.get_value_as_int()
settings.search_max_results = self.general_page.search_maxresults_spinbutton.get_value_as_int()
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'):

View File

@ -58,4 +58,39 @@
</item>
</section>
</menu>
<menu id="backupview-contextmenu">
<section>
<item>
<attribute name='label' translatable="true">_Restore</attribute>
<attribute name='action'>backupview.restore</attribute>
</item>
</section>
<section>
<item>
<attribute name='label' translatable="true">Convert to _Windows</attribute>
<attribute name='action'>backupview.convert-to-windows</attribute>
</item>
<item>
<attribute name='label' translatable="true">Convert to _Linux</attribute>
<attribute name='action'>backupview.convert-to-linux</attribute>
</item>
<item>
<attribute name='label' translatable="true">Convert to _Mac OS</attribute>
<attribute name='action'>backupview.convert-to-macos</attribute>
</item>
<item>
<attribute name='label' translatable="true">Convert to _Steam Windows</attribute>
<attribute name='action'>backupview.convert-to-steam-windows</attribute>
</item>
<item>
<attribute name='label' translatable="true">Convert to Steam Linux</attribute>
<attribute name='action'>backupview.convert-to-steam-linux</attribute>
</item>
<item>
<attribute name="label" translatable="true">Convert to Steam Mac OS</attribute>
<attribute name="action">backupview.convert-to-steam-macos</attribute>
</item>
</section>
</menu>
</interface>

View File

@ -356,6 +356,22 @@ class Settings(GObject.GObject):
def search_min_chars(self,min_chars:int):
self.set_integer('search','minChars',min_chars)
@GObject.Property(type=bool,default=False)
def gui_autoclose_backup_dialog(self)->bool:
return self.get_boolean('gui','autocloseBackupDialog',False)
@gui_autoclose_backup_dialog.setter
def gui_autoclose_backup_dialog(self,autoclose:bool):
self.set_boolean('gui','autocloseBackupDialog',autoclose)
@GObject.Property(type=bool,default=False)
def gui_autoclose_restore_dialog(self)->bool:
return self.get_boolean('gui','autocloseRestoreDialog',False)
@gui_autoclose_restore_dialog.setter
def gui_autoclose_restore_dialog(self,autoclose:bool):
self.set_boolean('gui','autocloseRestoreDialog',autoclose)
@GObject.Property
def variables(self)->dict[str:str]:
ret = {}