Lumiera  0.pre.03
»edityourfreedom«
command.cpp
Go to the documentation of this file.
1 /*
2  Command - Key abstraction for proc/edit operations and UNDO management
3 
4  Copyright (C) Lumiera.org
5  2009, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
23 
42 #include "lib/util.hpp"
43 #include "lib/error.hpp"
44 #include "lib/symbol.hpp"
45 #include "lib/format-string.hpp"
46 #include "proc/control/command.hpp"
52 
53 #include <utility>
54 #include <sstream>
55 #include <string>
56 
57 using std::ostringstream;
58 using std::string;
59 using std::move;
60 using util::cStr;
61 using util::_Fmt;
62 
63 
64 namespace proc {
65 namespace control {
66  namespace error = lumiera::error;
67 
68  LUMIERA_ERROR_DEFINE (INVALID_COMMAND, "Unknown or insufficiently defined command");
69  LUMIERA_ERROR_DEFINE (DUPLICATE_COMMAND, "Attempt to redefine an already existing command definition");
70  LUMIERA_ERROR_DEFINE (INVALID_ARGUMENTS, "Arguments provided for binding doesn't match stored command function parameters");
71  LUMIERA_ERROR_DEFINE (UNBOUND_ARGUMENTS, "Command mutation functor not yet usable, because arguments aren't bound");
72  LUMIERA_ERROR_DEFINE (MISSING_MEMENTO, "Undo functor not yet usable, because no undo state has been captured");
73 
74 
75  namespace { // some common error checks...
76 
77  void
78  ___check_notBottom (const Command *handle, lib::Literal operation_descr)
79  {
80  REQUIRE (handle);
81  if (!handle->isValid())
82  throw error::Invalid (operation_descr+" an undefined command"
83  , LERR_(INVALID_COMMAND));
84  }
85 
86  void
87  ___check_isBound (const Command *handle)
88  {
89  REQUIRE (handle);
90  if (!handle->canExec())
91  throw error::State ("Lifecycle error: command arguments not bound"
92  , LERR_(UNBOUND_ARGUMENTS));
93  }
94 
95  void
96  ___check_canUndo (const Command *handle)
97  {
98  REQUIRE (handle);
99  if (!handle->canUndo())
100  throw error::State ("Lifecycle error: command has not yet captured UNDO information"
101  , LERR_(UNBOUND_ARGUMENTS));
102  }
103 
104  }
105 
106 
107 
108 
111 
112 
115 
116 
117 
118 
126  Command
128  {
129  Command cmd = CommandRegistry::instance().queryIndex (cmdID);
130  if (!cmd)
131  throw error::Invalid(_Fmt("Command \"%s\" not found") % cmdID
132  , LERR_(INVALID_COMMAND));
133 
134  ENSURE (cmdID == CommandRegistry::instance().findDefinition(cmd));
135  return cmd;
136  }
137 
138 
146  Command
148  {
149  Command cmd = CommandRegistry::instance().queryIndex (cmdID);
150  return cmd? cmd.newInstance()
151  : Command{};
152  }
153 
154 
156  Command
158  {
159  return CommandRegistry::instance().queryIndex (cmdID);
160  }
161 
162 
168  void
170  {
171  REQUIRE (implFrame);
172 
173  if (this->isValid())
174  duplicate_detected (cmdID);
175 
176  _Handle::activate (move (implFrame));
177  if (cmdID)
178  {
179  CommandRegistry::instance().track (cmdID, *this);
180  impl().cmdID = cmdID;
181  }
182 
183  TRACE (command, "%s defined OK", cStr(*this));
184  }
185 
186 
189  Command
190  Command::storeDef (Symbol newCmdID) const
191  {
193 
194  ___check_notBottom (this,"Cloning");
195  if (registry.queryIndex (newCmdID))
196  duplicate_detected (newCmdID);
197 
198  Command cloneDefinition;
199  cloneDefinition.activate (move (registry.createCloneImpl(this->impl())), newCmdID);
200  ENSURE (cloneDefinition);
201  return cloneDefinition;
202  }
203 
204 
206  Command
208  {
209  ___check_notBottom (this,"Cloning");
211  shared_ptr<CommandImpl> cloneImpl = registry.createCloneImpl(this->impl());
212 
213  Command clone;
214  clone.activate (move (cloneImpl));
215  ENSURE (clone);
216  return clone;
217  }
218 
219 
227  {
228  CommandImplCloneBuilder cloneBuilder(allocator_);
229  refObject.prepareClone(cloneBuilder);
230  return allocator_.create<CommandImpl> (refObject, cloneBuilder.clonedUndoMutation()
231  , cloneBuilder.clonedClosuere());
232  }
233 
234 
235 
236  void
238  {
239  throw error::Logic (_Fmt("Unable to store %s as new command. "
240  "ID \"%s\" is already in use")
241  % *this
242  % newCmdID
243  , LERR_(DUPLICATE_COMMAND));
244  }
245 
246 
247  bool
249  {
250  return CommandRegistry::instance().remove (cmdID);
251  }
252 
253 
257  void
259  {
260  ___check_notBottom (this, "Binding arguments of");
261  _Handle::impl().setArguments(args);
262  }
263 
264 
270  void
272  {
273  ___check_notBottom (this, "Binding arguments of");
274  _Handle::impl().setArguments(paramData);
275  }
276 
277 
285  Command&
287  {
288  ___check_notBottom (this, "Un-binding arguments of");
289  _Handle::impl().discardArguments();
290  return *this;
291  }
292 
293 
295  size_t
297  {
298  return CommandRegistry::instance().index_size();
299  }
300 
301 
302 
304  size_t
306  {
307  return CommandRegistry::instance().instance_count();
308  }
309 
310 
311 
312  namespace {
313  inline bool
314  was_activated (Command const& com)
315  {
316  return com.isValid();
317  }
318 
319  inline Command
320  registered_for (Symbol id)
321  {
322  return CommandRegistry::instance().queryIndex (id);
323  }
324  }
325 
326 
334  {
335  if (!was_activated (prototype_))
336  CommandRegistry::instance().remove (this->id_);
337  }
338 
339 
346  bool
348  {
349  return (was_activated (prototype_))
350  && (prototype_ == registered_for (this->id_))
351  ;
352  }
353 
354 
355 
356  bool
358  {
359  return isValid()
360  && impl().canExec();
361  }
362 
363 
364  bool
366  {
367  return isValid()
368  && impl().canUndo();
369  }
370 
371 
372  bool
373  Command::equivalentImpl (Command const& c1, Command const& c2)
374  {
375  return c1.impl() == c2.impl();
376  }
377 
378 
379  Symbol
380  Command::getID() const noexcept
381  {
382  return isValid()? impl().cmdID
383  : Symbol::FAILURE;
384  }
385 
386 
392  bool
394  {
395  return not CommandRegistry::instance().findDefinition (*this);
396  }
397 
398 
399 
400 
403  Command::operator string() const
404  {
405  ostringstream repr;
407  repr << "Command(\""<<getID()<<"\") ";
408  if (!isValid())
409  repr << "NIL";
410  else
411  if (canUndo())
412  repr << "{undo}";
413  else
414  if (canExec())
415  repr << "{exec}";
416  else
417  repr << "{def}";
418 
419  return repr.str();
420  }
421 
422 
423 
424 
425  ExecResult
426  Command::exec (HandlingPattern const& execPattern)
427  {
428  ___check_notBottom (this,"Invoking");
429  ___check_isBound (this);
430 
431  string cmdName{*this};
432  CommandImpl& thisCommand (_Handle::impl());
433  return execPattern.exec (thisCommand, cmdName);
434  }
435 
436 
437  ExecResult
438  Command::undo (HandlingPattern const& execPattern)
439  {
440  ___check_notBottom (this,"UNDOing");
441  ___check_canUndo (this);
442 
443  string cmdName{*this};
444  CommandImpl& thisCommand (_Handle::impl());
445  return execPattern.undo (thisCommand, cmdName);
446  }
447 
448 
449  ExecResult
451  {
452  return exec (HandlingPattern::get(pattID));
453  }
454 
455 
456  ExecResult
458  {
459  return undo (HandlingPattern::get(pattID));
460  }
461 
462 
463  ExecResult
465  {
467  }
468 
469 
472  {
473  ___check_notBottom (this,"Accessing");
474  return impl().getDefaultHandlingPattern();
475  }
476 
477 
480  {
481  ___check_notBottom (this, "Configuring");
482  return impl().setHandlingPattern(pattID);
483  }
484 
485 
486 
487 
488 
489 }} // namespace proc::control
ExecResult undo(CommandImpl &command, string) const
likewise invoke the configured UNDO operation
ChPredicate isValid(is_alnum() or is_any_of("-_.+$()@"))
characters to be retained
ExecResult exec()
Definition: command.hpp:240
static size_t definition_count()
Definition: command.cpp:296
LumieraError< LERR_(INVALID)> Invalid
Definition: error.hpp:216
void prepareClone(CommandImplCloneBuilder &visitor) const
assist with building a clone copy of this CommandImpl.
ExecResult exec(CommandImpl &command, string) const
main functionality: invoke a command, detect errors.
void setArguments(Arguments &)
Definition: command.cpp:258
PClo const & clonedClosuere()
after visitation: provide cloned StorageHolder, but already stripped down to the generic usage type ...
static Symbol FAILURE
Definition: symbol.hpp:123
Top level of the command implementation.
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:75
Front-end for printf-style string template interpolation.
Managing command definitions and the storage of individual command objects.
bool canExec() const
Definition: command.cpp:357
shared_ptr< CommandImpl > createCloneImpl(CommandImpl const &refObject)
create an allocation for holding a clone of the given CommandImpl data.
Definition: command.cpp:226
HandlingPattern::ID setHandlingPattern(HandlingPattern::ID)
define a handling pattern to be used by default
Definition: command.cpp:479
A front-end for using printf-style formatting.
Access point to singletons and other kinds of dependencies designated by type.
Definition: depend.hpp:289
HandlingPattern::ID getDefaultHandlingPattern() const
Definition: command.cpp:471
const char * cStr(string const &org)
convenience shortcut: conversion to c-String via string.
Definition: util.hpp:397
bool isAnonymous() const
Definition: command.cpp:393
Registry managing command implementation objects (Singleton).
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:196
~CommandDef()
when starting a CommandDef, we immediately place a yet empty Command object into the index...
Definition: command.cpp:333
Symbol getID() const noexcept
Definition: command.cpp:380
Token or Atom with distinct identity.
Definition: symbol.hpp:116
Proc-Layer Command implementation.
#define LERR_(_NAME_)
Definition: error.hpp:58
Marker types to indicate a literal string and a Symbol.
void activate(shared_ptr< CommandImpl > &&, Symbol cmdID=0)
Definition: command.cpp:169
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
bool isValid() const
Definition: handle.hpp:104
Proc-Layer command frontend.
UndoMutation const & clonedUndoMutation()
after visitation: use pre-built bits to provide a cloned UndoFunctor
Command newInstance() const
create independent (anonymous) clone copy of this command
Definition: command.cpp:207
static size_t instance_count()
Definition: command.cpp:305
Command & unbind()
discard any argument data previously bound.
Definition: command.cpp:286
Visitor to support creating a CommandImpl clone.
static Command get(Symbol cmdID)
Access existing command for use.
Definition: command.cpp:127
bool canUndo() const
Definition: command.cpp:365
LumieraError< LERR_(LOGIC)> Logic
Definition: error.hpp:212
Result (Status) of command execution.
bool isValid() const
is this a valid command definition? especially.
Definition: command.cpp:347
IMP & impl() const
Definition: handle.hpp:149
static bool equivalentImpl(Command const &, Command const &)
Definition: command.cpp:373
Pre-defined command execution skeletons.
Interface: Operation Skeleton how to invoke or undo a command.
Lumiera error handling (C++ interface).
TRACE(test, "inserted %d", data)
Helper for creating an implementation clone, based on the visitor pattern.
static Command fetchDef(Symbol cmdID)
Definition: command.cpp:157
static lib::Depend< CommandRegistry > instance
storage for the singleton factory used to access CommandRegistry
Handle object representing a single Command instance to be used by client code.
Definition: command.hpp:125
static bool remove(Symbol cmdID)
Definition: command.cpp:248
static Command maybeGetNewInstance(Symbol cmdID)
try to access an existing command definition and immediately create a new clone copy by calling newIn...
Definition: command.cpp:147
Proc-Layer implementation namespace root.
Definition: id-scheme.hpp:63
void duplicate_detected(Symbol) const
Definition: command.cpp:237
static HandlingPattern const & get(ID id)
retrieve the pre-configured pattern
Actually defining a command and binding it to execution parameters.
Command storeDef(Symbol newCmdID) const
create a clone definition
Definition: command.cpp:190
object-like record of data.
Definition: record.hpp:143
ENSURE(r==&pq)
LUMIERA_ERROR_DEFINE(INVALID_COMMAND, "Unknown or insufficiently defined command")
ExecResult undo()
Definition: command.hpp:246
Command queryIndex(Symbol cmdID)
query the command index by ID
ExecResult execSync()
invoke using a default "synchronous" execution pattern
Definition: command.cpp:464