renaming and deleting presets

first
sezanzeb 4 years ago
parent 4751aa6ff9
commit 5a499f6467

@ -32,7 +32,8 @@ from gi.repository import Gtk
from keymapper.data import get_data_path
from keymapper.X import create_setxkbmap_config, apply_preset, create_preset
from keymapper.presets import get_presets, find_newest_preset
from keymapper.presets import get_presets, find_newest_preset, \
delete_preset, rename_preset
from keymapper.logger import logger, update_verbosity, log_info
from keymapper.linux import get_devices
@ -98,12 +99,7 @@ class Window:
self.populate_devices()
# find and select the newest preset based on file modification dates
device, preset = find_newest_preset()
if device is not None:
self.get('device_selection').set_active_id(device)
if preset is not None:
self.get('device_selection').set_active_id(preset)
self.select_newest_preset()
def get(self, name):
"""Get a widget from the window"""
@ -113,6 +109,14 @@ class Window:
"""Safely close the application."""
Gtk.main_quit()
def select_newest_preset(self):
"""Find and select the newest preset."""
device, preset = find_newest_preset()
if device is not None:
self.get('device_selection').set_active_id(device)
if preset is not None:
self.get('device_selection').set_active_id(preset)
def populate_devices(self):
"""Make the devices selectable."""
devices = get_devices()
@ -124,8 +128,9 @@ class Window:
"""Show the available presets for the selected device."""
device = self.selected_device
presets = get_presets(device)
self.get('preset_name_input').set_text('')
if len(presets) == 0:
create_preset(device)
presets = [create_preset(device)]
else:
logger.debug('Presets for "%s": %s', device, ', '.join(presets))
preset_selection = self.get('preset_selection')
@ -140,7 +145,28 @@ class Window:
# and select the newest one (on the top)
preset_selection.set_active(0)
def update_mappings(self):
"""Construct the mapping from the inputs without saving or applying."""
self.mappings = [(10, 'c')]
def on_save_preset_clicked(self, button):
"""Save changes to a preset to the file system."""
new_name = self.get('preset_name_input').get_text()
if new_name != '' and new_name != self.selected_preset:
rename_preset(self.selected_device, self.selected_preset, new_name)
self.populate_presets()
self.update_mappings()
self.update_config()
def on_delete_preset_clicked(self, button):
"""Delete a preset from the file system."""
delete_preset(self.selected_device, self.selected_preset)
self.populate_presets()
def on_apply_preset_clicked(self, button):
"""Apply a preset without saving changes."""
self.update_mappings()
logger.debug(
'Applying preset "%s" for "%s"',
self.selected_preset,
@ -208,9 +234,6 @@ class Window:
----------
mapping : SingleKeyMapping
"""
# TODO modify self.mappings
self.update_config()
# shrink the window down as much as possible, otherwise it
# will increase with each added mapping but won't go back when they
# are removed.
@ -224,6 +247,7 @@ class Window:
self.on_add_key_clicked()
def update_config(self):
"""Write changes to disk"""
if self.selected_device is None or self.selected_preset is None:
return
@ -233,9 +257,6 @@ class Window:
self.selected_preset
)
# TODO use user defined mapping
self.mappings = [(10, 'c')]
create_setxkbmap_config(
self.selected_device,
self.selected_preset,

@ -5,7 +5,8 @@
<object class="GtkEntry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">a</property>
<property name="text" translatable="yes">asdf</property>
<property name="xalign">0.5</property>
</object>
<object class="GtkWindow" id="window">
<property name="width_request">450</property>
@ -101,13 +102,14 @@
</packing>
</child>
<child>
<object class="GtkButton" id="create_preset2">
<object class="GtkButton" id="save_preset">
<property name="label">gtk-save</property>
<property name="width_request">80</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_save_preset_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@ -144,13 +146,14 @@
</packing>
</child>
<child>
<object class="GtkButton" id="create_preset3">
<object class="GtkButton" id="delete_preset">
<property name="label">gtk-delete</property>
<property name="width_request">80</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_delete_preset_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@ -225,7 +228,7 @@
</packing>
</child>
<child>
<object class="GtkEntry">
<object class="GtkEntry" id="preset_name_input">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>

@ -51,7 +51,7 @@ def get_keycode(device, letter):
def create_preset(device, name=None):
"""Create an empty preset."""
"""Create an empty preset and return the name."""
existing_names = get_presets(device)
if name is None:
name = 'new preset'

@ -49,7 +49,7 @@ def get_presets(device):
]
# the highest timestamp to the front
presets.reverse()
return presets
return [preset.replace('_', ' ') for preset in presets]
def get_mappings(device, preset):
@ -65,21 +65,37 @@ def get_mappings(device, preset):
def get_any_preset():
"""Return the first found tuple of (device, preset)."""
any_device = list(get_devices().keys())[0]
devices = get_devices().keys()
if len(devices) == 0:
return None, None
any_device = list(devices)[0].replace('_', ' ')
any_preset = (get_presets(any_device) or [None])[0]
if any_preset is not None:
any_preset = any_preset.replace('_', ' ')
return any_device, any_preset
def find_newest_preset():
def find_newest_preset(device=None):
"""Get a tuple of (device, preset) that was most recently modified.
If no device has been configured yet, return arbitrarily.
If no device has been configured yet, return an arbitrary device.
Parameters
----------
device : string
If set, will return the newest preset for the device or None
"""
# sort the oldest files to the front in order to use pop to get the newest
paths = sorted(
glob.glob(os.path.join(CONFIG_PATH, '*/*')),
key=os.path.getmtime
)
if device is None:
paths = sorted(
glob.glob(os.path.join(CONFIG_PATH, '*/*')),
key=os.path.getmtime
)
else:
paths = sorted(
glob.glob(os.path.join(get_home_path(device), '*')),
key=os.path.getmtime
)
if len(paths) == 0:
logger.debug('No presets found.')
@ -111,3 +127,35 @@ def find_newest_preset():
logger.debug('The newest preset is "%s", "%s"', device, preset)
return device, preset
def delete_preset(device, preset):
"""Delete a preset from the file system."""
preset_path = get_home_path(device, preset)
if not os.path.exists(preset_path):
logger.debug('Cannot remove non existing path "%s"', preset_path)
return
logger.info('Removing "%s"', preset_path)
os.remove(preset_path)
device_path = get_home_path(device)
if len(os.listdir(device_path)) == 0:
logger.debug('Removing empty dir "%s"', device_path)
os.remove(device_path)
def rename_preset(device, old_preset_name, new_preset_name):
"""Rename a preset while avoiding name conflicts."""
new_preset_name = new_preset_name.strip()
# find a name that is not already taken
if os.path.exists(get_home_path(device, new_preset_name)):
i = 2
while os.path.exists(get_home_path(device, f'{new_preset_name} {i}')):
i += 1
new_preset_name = f'{new_preset_name} {i}'
logger.info('Moving "%s" to "%s"', old_preset_name, new_preset_name)
os.rename(
get_home_path(device, old_preset_name),
get_home_path(device, new_preset_name)
)

@ -24,7 +24,7 @@ import unittest
import shutil
import time
from keymapper.presets import find_newest_preset
from keymapper.presets import find_newest_preset, rename_preset
from keymapper.X import create_preset
@ -59,6 +59,16 @@ class TestCreatePreset(unittest.TestCase):
self.assertTrue(os.path.exists(f'{tmp}/.config/device_1/pre_set_2'))
class TestRenamePreset(unittest.TestCase):
def test_rename_preset(self):
create_preset('device 1', 'preset 1')
create_preset('device 1', 'foobar')
rename_preset('device 1', 'preset 1', 'foobar')
self.assertFalse(os.path.exists(f'{tmp}/.config/device_1/preset_1'))
self.assertTrue(os.path.exists(f'{tmp}/.config/device_1/foobar'))
self.assertTrue(os.path.exists(f'{tmp}/.config/device_1/foobar_2'))
class TestFindPresets(unittest.TestCase):
def setUp(self):
if os.path.exists(tmp):
@ -99,6 +109,20 @@ class TestFindPresets(unittest.TestCase):
# takes the first one that the test-fake returns
self.assertEqual(find_newest_preset(), ('device 1', None))
def test_find_newest_preset_7(self):
self.assertEqual(find_newest_preset('device 1'), ('device 1', None))
def test_find_newest_preset_8(self):
create_preset('device 1', 'preset 1')
time.sleep(0.01)
create_preset('device 1', 'preset 3')
time.sleep(0.01)
create_preset('device 2', 'preset 2')
self.assertEqual(
find_newest_preset('device 1'),
('device 1', 'preset 3')
)
if __name__ == "__main__":
unittest.main()

Loading…
Cancel
Save