1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
|
#pragma once
#include "DataCell.hh"
#include "DocumentThread.hh"
#include <memory>
namespace cadabra {
class DocumentThread;
class GUIBase;
/// \ingroup clientserver
///
/// All actions derive from the ActionBase object, which defines
/// the interface they need to implement. These objects are used to
/// pass (user) action instructions around. They can be stored in
/// undo/redo stacks. All actions run on the GUI thread. The
/// update_gui members typically call members of the GUIBase class.
/// Action objects are allowed to modify the DTree document doc,
/// since they essentially contain code which is part of the
/// DocumentThread object.
///
/// All modifications to the document are done by calling 'perform' with an
/// action object. This enables us to implement an undo stack. This method
/// will take care of making the actual change to the DTree document, and
/// call back on the 'change' methods above to inform the derived class
/// that a change has been made.
class ActionBase {
public:
ActionBase(DataCell::id_t ref_id);
/// Perform the action. This should update both the document
/// tree data structure and the GUI. The latter is updated
/// by calling relevant methods on the GUIBase object passed
/// in.
virtual void execute(DocumentThread&, GUIBase&);
/// Revert the change to the DTree document and the GUI.
virtual void revert(DocumentThread&, GUIBase&)=0;
/// Can this action be undone?
virtual bool undoable() const;
DataCell::id_t ref_id;
protected:
DTree::iterator ref;
};
/// \ingroup clientserver
///
/// Add a cell to the notebook.
class ActionAddCell : public ActionBase {
public:
enum class Position { before, after, child };
ActionAddCell(DataCell, DataCell::id_t ref_, Position pos_);
virtual ~ActionAddCell() {};
virtual void execute(DocumentThread&, GUIBase&) override;
virtual void revert(DocumentThread&, GUIBase&) override;
private:
// Keep track of the location where this cell is inserted into
// the notebook.
DataCell newcell;
DTree::iterator newref;
Position pos;
int child_num;
};
/// \ingroup clientserver
///
/// Position the cursor relative to the indicated cell. If position is 'next' and
/// there is no input cell following the indicated one, create a new one.
class ActionPositionCursor : public ActionBase {
public:
enum class Position { in, next, previous };
ActionPositionCursor(DataCell::id_t ref_id_, Position pos_);
virtual ~ActionPositionCursor() {};
virtual void execute(DocumentThread&, GUIBase&) override;
virtual void revert(DocumentThread&, GUIBase&) override;
private:
bool needed_new_cell;
DTree::iterator newref;
Position pos;
};
/// \ingroup clientserver
///
/// Update the running status of the indicated cell.
class ActionSetRunStatus : public ActionBase {
public:
ActionSetRunStatus(DataCell::id_t ref_id_, bool running);
virtual ~ActionSetRunStatus() {};
virtual void execute(DocumentThread&, GUIBase&) override;
virtual void revert(DocumentThread&, GUIBase&) override;
virtual bool undoable() const override;
private:
DTree::iterator this_cell;
bool was_running_, new_running_;
};
/// \ingroup clientserver
///
/// Remove a cell and all its child cells from the document.
class ActionRemoveCell : public ActionBase {
public:
ActionRemoveCell(DataCell::id_t ref_id_);
virtual ~ActionRemoveCell();
virtual void execute(DocumentThread&, GUIBase&) override;
virtual void revert(DocumentThread&, GUIBase&) override;
private:
// Keep track of the location where this cell (and its child
// cells) was in the notebook. We keep a reference to the
// parent cell and the index of the current cell as child of
// that parent.
DTree removed_tree;
DTree::iterator reference_parent_cell;
size_t reference_child_index;
};
/// \ingroup clientserver
///
/// Split a cell into two separate cells, at the point of the cursor.
class ActionSplitCell : public ActionBase {
public:
ActionSplitCell(DataCell::id_t ref_id);
virtual ~ActionSplitCell();
virtual void execute(DocumentThread&, GUIBase&) override;
virtual void revert(DocumentThread&, GUIBase&) override;
private:
DTree::iterator newref; // the newly created cell
};
/// \ingroup clientserver
///
/// Add a text string (can be just a single character) at the point
/// of the cursor.
/// This action is assumed to be triggered from a user change to
/// the GUI cells, so will not update the GUI itself, only the
/// underlying DTree. However, the revert method will need to
/// update the GUI representation.
class ActionInsertText : public ActionBase {
public:
ActionInsertText(DataCell::id_t ref_id, int pos, const std::string&);
virtual ~ActionInsertText() {};
virtual void execute(DocumentThread&, GUIBase&) override;
virtual void revert(DocumentThread&, GUIBase&) override;
private:
DTree::iterator this_cell;
int insert_pos;
std::string text;
};
/// \ingroup clientserver
///
/// Complete text at a point in a GUI cell with one or more
/// alternative.
/// In contrast to ActionInsertText, this one is triggered from
/// the server-side, so will update the GUI both for execute
/// and revert.
class ActionCompleteText : public ActionBase {
public:
ActionCompleteText(DataCell::id_t ref_id, int pos, const std::string&, int alternative);
virtual ~ActionCompleteText() {};
virtual void execute(DocumentThread&, GUIBase&) override;
virtual void revert(DocumentThread&, GUIBase&) override;
int length() const;
int alternative() const;
private:
DTree::iterator this_cell;
int insert_pos;
std::string text;
int alternative_; // in case there is more than one completion alternative
};
/// \ingroup clientserver
///
/// Remove a text string starting at the indicated position, and
/// with the indicated length, from the indicated cell.
/// This action is assumed to be triggered from a user change to
/// the GUI cells, so will not update the GUI itself, only the
/// underlying DTree. However, the revert method will need to
/// update the GUI representation.
class ActionEraseText : public ActionBase {
public:
ActionEraseText(DataCell::id_t ref_id, int, int);
virtual ~ActionEraseText() {};
virtual void execute(DocumentThread&, GUIBase&) override;
virtual void revert(DocumentThread&, GUIBase&) override;
private:
DTree::iterator this_cell;
int from_pos, to_pos;
std::string removed_text;
};
}
//
// class ActionMergeCells
|