2 Maps Qt signals to Command objects.
4 The command factory connects to the global notifier and
5 creates commands objects as registered signals are
8 The factory itself is undoable in that it responds to
9 the undo and redo signals and manages the undo/redo stack.
13 from cola
import signals
18 """Return a static instance of the command factory."""
22 _factory
= CommandFactory()
26 def SLOT(signal
, *args
, **opts
):
28 Returns a callback that broadcasts a message over the notifier.
31 def broadcast(*local_args
, **opts
):
32 cola
.notifier().broadcast(signal
, *args
, **opts
)
36 class CommandFactory(object):
38 """Setup the undo/redo stacks and register for notifications."""
42 self
.signal_to_command
= {}
45 cola
.notifier().connect(signals
.undo
, self
.undo
)
46 cola
.notifier().connect(signals
.redo
, self
.redo
)
48 self
.model
= cola
.model()
49 self
.model
.add_observer(self
)
51 def add_command(self
, signal
, command
):
52 """Register a signal/command pair."""
53 self
.signal_to_command
[signal
] = command
54 cola
.notifier().connect(signal
, self
.cmdrunner(signal
))
56 def add_command_wrapper(self
, cmd_wrapper
):
57 self
.callbacks
.update(cmd_wrapper
.callbacks
)
59 def prompt_user(self
, name
, *args
, **opts
):
61 return self
.callbacks
[name
](*args
, **opts
)
63 raise NotImplementedError('No callback for "%s' % name
)
65 def notify(self
, *params
):
67 Observe model changes.
69 This captures model parameters and maps them to signals that
70 are observed by the UIs.
74 'diff_text': SLOT(signals
.diff_text
, self
.model
.diff_text
),
75 'commitmsg': SLOT(signals
.editor_text
, self
.model
.commitmsg
),
76 'mode': SLOT(signals
.mode
, self
.model
.mode
),
79 action
= actions
.get(param
, lambda: None)
83 """Clear the undo and redo stacks."""
87 def cmdrunner(self
, signal
):
88 """Return a function to create and run a signal's command."""
89 def run(*args
, **opts
):
90 return self
.do(signal
, *args
, **opts
)
93 def do(self
, signal
, *args
, **opts
):
94 """Given a signal and arguments, run its corresponding command."""
95 cmdclass
= self
.signal_to_command
[signal
]
96 cmdobj
= cmdclass(*args
, **opts
)
97 # TODO we disable undo/redo for now; views just need to
98 # inspect the stack and add menu entries when we enable it.
99 if self
.undoable
and cmdobj
.is_undoable():
100 self
.undostack
.append(cmdobj
)
104 """Undo the last command and add it to the redo stack."""
106 cmdobj
= self
.undostack
.pop()
108 self
.redostack
.append(cmdobj
)
110 print 'warning: undo stack is empty, doing nothing'
113 """Redo the last command and add it to the undo stack."""
115 cmdobj
= self
.redostack
.pop()
117 self
.undo
.append(cmd
)
119 print 'warning: redo stack is empty, doing nothing'
121 def is_undoable(self
):
122 """Does the undo stack contain any commands?"""
123 return bool(self
.undostack
)
125 def is_redoable(self
):
126 """Does the redo stack contain any commands?"""
127 return bool(self
.redostack
)