unsaved changes dialog

This commit is contained in:
sezanzeb 2020-11-15 00:27:45 +01:00
parent 20dbb4c8a8
commit 80bd7deacd
7 changed files with 48 additions and 41 deletions

View File

@ -238,7 +238,8 @@
</object>
</child>
<action-widgets>
<action-widget response="-7">go_back</action-widget>
<action-widget response="-3">go_back</action-widget>
<action-widget response="-6">go_ahead</action-widget>
</action-widgets>
<child type="titlebar">
<placeholder/>

View File

@ -203,8 +203,10 @@ def setxkbmap(device, layout):
logger.info('Applying layout "%s" on device %s', layout, device)
group = get_devices()[device]
keycodes = None if layout is None else 'key-mapper'
layout = layout or get_system_layout()
if layout is None:
cmd = ['setxkbmap', '-layout', get_system_layout()]
else:
cmd = ['setxkbmap', '-layout', layout, '-keycodes', 'key-mapper']
# apply it to every device that hangs on the same usb port, because I
# have no idea how to figure out which one of those 3 devices that are
@ -214,17 +216,9 @@ def setxkbmap(device, layout):
# only all virtual devices of the same hardware device
continue
cmd = [
'setxkbmap',
'-device', str(xinput_id)
]
if layout is not None:
cmd += ['-layout', layout]
if keycodes is not None:
cmd += ['-keycodes', keycodes]
logger.debug('Running `%s`', ' '.join(cmd))
subprocess.run(cmd)
device_cmd = cmd + ['-device', str(xinput_id)]
logger.debug('Running `%s`', ' '.join(device_cmd))
subprocess.run(device_cmd, capture_output=True)
def create_identity_mapping():

View File

@ -36,20 +36,18 @@ from keymapper.linux import keycode_reader
CTX_KEYCODE = 2
class Row:
class Row(Gtk.ListBoxRow):
"""A single, configurable key mapping."""
__gtype_name__ = 'ListBoxRow'
def __init__(self, delete_callback, window, keycode=None, character=None):
"""Construct a row widget."""
self.widget = None
super().__init__()
self.device = window.selected_device
self.window = window
self.delete_callback = delete_callback
self.put_together(keycode, character)
def get_widget(self):
"""Return the widget that wraps all the widgets of the row."""
return self.widget
def get_keycode(self):
keycode = self.keycode.get_label()
return int(keycode) if keycode else None
@ -111,7 +109,7 @@ class Row:
def highlight(self):
"""Mark this row as changed."""
self.widget.get_style_context().add_class('changed')
self.get_style_context().add_class('changed')
def on_character_input_change(self, entry):
keycode = self.get_keycode()
@ -169,11 +167,9 @@ class Row:
box.pack_start(delete_button, expand=True, fill=False, padding=0)
box.show_all()
row = Gtk.ListBoxRow()
row.add(box)
row.show_all()
self.add(box)
self.show_all()
self.widget = row
self.character_input = character_input
self.keycode = keycode_input

View File

@ -34,13 +34,16 @@ CONTINUE = True
GO_BACK = False
def unsavedChangesDialog():
def unsaved_changes_dialog():
"""Blocks until the user decided about an action."""
gladefile = get_data_path('key-mapper.glade')
builder = Gtk.Builder()
builder.add_from_file(gladefile)
dialog = builder.get_object('unsaved_changes')
dialog.show()
dialog.run()
response = dialog.run()
dialog.hide()
# TODO do something meaningful
return GO_BACK
if response == Gtk.ResponseType.ACCEPT:
return CONTINUE
else:
return GO_BACK

View File

@ -35,7 +35,7 @@ from keymapper.presets import get_presets, find_newest_preset, \
from keymapper.logger import logger
from keymapper.linux import get_devices, keycode_reader
from keymapper.gtk.row import Row
from keymapper.gtk.unsaved import unsavedChangesDialog, GO_BACK
from keymapper.gtk.unsaved import unsaved_changes_dialog, GO_BACK
def gtk_iteration():
@ -220,9 +220,12 @@ class Window:
def on_select_device(self, dropdown):
"""List all presets, create one if none exist yet."""
if custom_mapping.changed:
if unsavedChangesDialog() == GO_BACK:
return
if dropdown.get_active_id() == self.selected_device:
return
if custom_mapping.changed and unsaved_changes_dialog() == GO_BACK:
dropdown.set_active_id(self.selected_device)
return
device = dropdown.get_active_text()
@ -239,7 +242,7 @@ class Window:
def on_create_preset_clicked(self, button):
"""Create a new preset and select it."""
if custom_mapping.changed:
if unsavedChangesDialog() == GO_BACK:
if unsaved_changes_dialog() == GO_BACK:
return
new_preset = create_preset(self.selected_device)
@ -249,9 +252,12 @@ class Window:
def on_select_preset(self, dropdown):
"""Show the mappings of the preset."""
if custom_mapping.changed:
if unsavedChangesDialog() == GO_BACK:
return
if dropdown.get_active_id() == self.selected_preset:
return
if custom_mapping.changed and unsaved_changes_dialog() == GO_BACK:
dropdown.set_active_id(self.selected_preset)
return
self.clear_mapping_table()
@ -269,7 +275,7 @@ class Window:
keycode=keycode,
character=character
)
key_list.insert(single_key_mapping.get_widget(), -1)
key_list.insert(single_key_mapping, -1)
self.add_empty()
@ -279,7 +285,7 @@ class Window:
delete_callback=self.on_row_removed
)
key_list = self.get('key_list')
key_list.insert(empty.get_widget(), -1)
key_list.insert(empty, -1)
def on_row_removed(self, single_key_mapping):
"""Stuff to do when a row was removed
@ -290,7 +296,7 @@ class Window:
"""
key_list = self.get('key_list')
# https://stackoverflow.com/a/30329591/4417769
key_list.remove(single_key_mapping.get_widget())
key_list.remove(single_key_mapping)
def save_config(self):
"""Write changes to disk"""

View File

@ -55,6 +55,10 @@ linux._devices = {
}
linux.get_devices = lambda: linux._devices
# don't block tests
from keymapper.gtk import unsaved
unsaved.unsaved_changes_dialog = lambda: unsaved.CONTINUE
from keymapper.logger import update_verbosity
# some class function stubs.
@ -73,7 +77,7 @@ if __name__ == "__main__":
# in all of the available tests like unittest.main() does...,
# so provide both options.
if len(modules) > 0:
# for example `tests/test.py ConfigTest.testFirstLine`
# for example `tests/test.py integration.Integration.test_can_start`
testsuite = unittest.defaultTestLoader.loadTestsFromNames(
[f'testcases.{module}' for module in modules]
)

View File

@ -124,6 +124,9 @@ class Integration(unittest.TestCase):
def get_active_text(self):
return self.name
def get_active_id(self):
return self.name
# created on start because the first device is selected and some empty
# preset prepared.
self.assertTrue(os.path.exists(f'{USERS_SYMBOLS}/device_1/new_preset'))