Commit ef360c2f authored by Jacek Sowiński's avatar Jacek Sowiński

Execute commands on multiple items marked with 'm'

1. 'm' can be reconfigured to any other key (action: 'mark').
2. Using 'mark' on already marked todo item will unmark it.
3. 'esc' key will clear whole selection.
4. Command will be executed on **all** marked items in **all** columns.
parent d2ba87c3
......@@ -79,6 +79,7 @@ x = cmd do {}
pp = postpone
ps = postpone_s
pr = pri
m = mark
0 = first_column
$ = last_column
h = prev_column
......
......@@ -125,6 +125,7 @@ class _Config:
'e': 'cmd edit {}',
'u': 'cmd revert',
'x': 'cmd do {}',
'm': 'mark',
'pp': 'postpone',
'ps': 'postpone_s',
'pr': 'pri',
......
......@@ -96,6 +96,8 @@ class UIApplication(CLIApplicationBase):
self.todofile = TodoFile.TodoFile(config().todotxt())
self.todolist = TodoList.TodoList(self.todofile.read())
self.pending_todos = []
self.columns = urwid.Columns([], dividechars=0, min_width=COLUMN_WIDTH)
self.commandline = CommandLineWidget('topydo> ')
self.keystate_widget = KeystateWidget()
......@@ -169,6 +171,9 @@ class UIApplication(CLIApplicationBase):
"""
Executes a command, given as a string.
"""
if '{}' in p_command:
todos = ' '.join(self.pending_todos)
p_command = p_command.format(todos)
p_output = p_output or self._output
p_command = shlex.split(p_command)
(subcommand, args) = get_subcommand(p_command)
......@@ -187,6 +192,8 @@ class UIApplication(CLIApplicationBase):
if command.execute() != False:
self._post_execute()
self._clear_pending_todos()
except TypeError:
# TODO: show error message
pass
......@@ -277,6 +284,7 @@ class UIApplication(CLIApplicationBase):
def _handle_input(self, p_input):
dispatch = {
':': self._focus_commandline,
'esc': self._clear_pending_todos,
}
try:
......@@ -334,6 +342,9 @@ class UIApplication(CLIApplicationBase):
urwid.connect_signal(todolist, 'remove_pending_action', self._remove_alarm)
urwid.connect_signal(todolist, 'column_action', self._column_action_handler)
urwid.connect_signal(todolist, 'show_keystate', self._print_keystate)
urwid.connect_signal(todolist, 'append_pending_todos', self._pending_todos_handler)
urwid.connect_signal(todolist, 'check_pending_todos', self._is_pending)
urwid.connect_signal(todolist, 'clear_pending_todos', self._clear_pending_todos)
options = self.columns.options(
width_type='given',
......@@ -450,6 +461,25 @@ class UIApplication(CLIApplicationBase):
return sz
def _clear_pending_todos(self, p_refresh=True):
self.pending_todos = []
if p_refresh:
self._update_all_columns()
def _is_pending(self):
if len(self.pending_todos) > 0:
return True
else:
return False
def _pending_todos_handler(self, p_todo_id):
if p_todo_id not in self.pending_todos:
self.pending_todos.append(p_todo_id)
return True
else:
self.pending_todos.remove(p_todo_id)
return False
def run(self):
layout = columns()
if len(layout) > 0:
......
......@@ -16,7 +16,7 @@
import urwid
from topydo.ui.TodoWidget import TodoWidget
from topydo.ui.TodoWidget import TodoWidget, markup
from topydo.lib.Utils import translate_key_to_config
......@@ -62,6 +62,9 @@ class TodoListWidget(urwid.LineBox):
'remove_pending_action',
'column_action',
'show_keystate',
'append_pending_todos',
'check_pending_todos',
'clear_pending_todos',
])
@property
......@@ -199,6 +202,17 @@ class TodoListWidget(urwid.LineBox):
def selectable(self):
return True
def _append_pending_todos(self):
try:
todo = self.listbox.focus.todo
todo_id = str(self.view.todolist.number(todo))
result = urwid.emit_signal(self, 'append_pending_todos', todo_id)
attr_spec = {None: markup(todo, result)}
self.listbox.focus.widget.set_attr_map(attr_spec)
except AttributeError:
# No todo item selected
pass
def _execute_on_selected(self, p_cmd_str, p_execute_signal):
"""
Executes command specified by p_cmd_str on selected todo item.
......@@ -213,7 +227,13 @@ class TodoListWidget(urwid.LineBox):
todo = self.listbox.focus.todo
todo_id = str(self.view.todolist.number(todo))
urwid.emit_signal(self, p_execute_signal, p_cmd_str.format(todo_id))
result = urwid.emit_signal(self, 'check_pending_todos')
if result:
cmd = p_cmd_str
else:
cmd = p_cmd_str.format(todo_id)
urwid.emit_signal(self, p_execute_signal, cmd)
# force screen redraw after editing
if p_cmd_str.startswith('edit'):
......@@ -250,8 +270,8 @@ class TodoListWidget(urwid.LineBox):
Currently supported actions are: 'up', 'down', 'home', 'end',
'first_column', 'last_column', 'prev_column', 'next_column',
'append_column', 'insert_column', 'edit_column', 'delete_column',
'copy_column', swap_right', 'swap_left', 'postpone', 'postpone_s' and
'pri'.
'copy_column', swap_right', 'swap_left', 'postpone', 'postpone_s', 'pri'
and 'mark'.
"""
column_actions = ['first_column',
'last_column',
......@@ -278,6 +298,8 @@ class TodoListWidget(urwid.LineBox):
pass
elif p_action_str == 'pri':
pass
elif p_action_str == 'mark':
self._append_pending_todos()
def _add_pending_action(self, p_action, p_size):
"""
......
......@@ -35,7 +35,8 @@ def _to_urwid_color(p_color):
else:
return 'h{}'.format(p_color.color)
def _markup(p_todo, p_focus):
def markup(p_todo, p_focus):
"""
Returns an attribute spec for the colors that correspond to the given todo
item.
......@@ -83,8 +84,8 @@ class TodoWidget(urwid.WidgetWrap):
self.widget = urwid.AttrMap(
self.columns,
_markup(p_todo, False), # no focus
_markup(p_todo, True) # focus
markup(p_todo, False), # no focus
markup(p_todo, True) # focus
)
super().__init__(self.widget)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment