TDME2  1.9.200
TextEditorTabController.cpp
Go to the documentation of this file.
2 
3 #include <array>
4 #include <memory>
5 #include <string>
6 #include <unordered_map>
7 
8 #include <tdme/tdme.h>
10 #include <tdme/engine/Texture.h>
11 #include <tdme/engine/Engine.h>
15 #include <tdme/gui/nodes/GUINode.h>
20 #include <tdme/gui/GUI.h>
21 #include <tdme/gui/GUIParser.h>
35 #include <tdme/utilities/Action.h>
36 #include <tdme/utilities/Console.h>
39 #include <tdme/utilities/Integer.h>
42 
43 #include <ext/tinyxml/tinyxml.h>
44 
46 
47 using std::array;
48 using std::make_unique;
49 using std::string;
50 using std::unique_ptr;
51 using std::unordered_map;
52 
63 using tdme::gui::GUI;
85 
89 
90 #define AVOID_NULLPTR_STRING(arg) (arg == nullptr?"":arg)
91 
92 TextEditorTabController::TextEditorTabController(TextEditorTabView* view)
93 {
94  this->view = view;
95  this->popUps = view->getPopUps();
96  this->view->getTabScreenNode()->addChangeListener(this);
97  this->view->getTabScreenNode()->addActionListener(this);
98  this->view->getTabScreenNode()->addFocusListener(this);
99 }
100 
102 }
103 
105 {
106  this->screenNode = screenNode;
107 }
108 
110 {
111  this->view->getTabScreenNode()->removeFocusListener(this);
112 }
113 
115 {
116  switch (command) {
117  case COMMAND_REDO:
118  view->redo();
119  break;
120  case COMMAND_UNDO:
121  view->undo();
122  break;
123  case COMMAND_CUT:
124  view->cut();
125  break;
126  case COMMAND_COPY:
127  view->copy();
128  break;
129  case COMMAND_PASTE:
130  view->paste();
131  break;
132  case COMMAND_DELETE:
133  view->delete_();
134  break;
135  case COMMAND_SELECTALL:
136  view->selectAll();
137  break;
138  case COMMAND_SAVE:
139  {
140  auto fileName = view->getFileName();
141  try {
142  if (fileName.empty() == true) throw ExceptionBase("Could not save file. No filename known");
143  view->saveFile(
144  Tools::getPathName(fileName),
145  Tools::getFileName(fileName)
146  );
147  } catch (Exception& exception) {
148  showInfoPopUp("Warning", string(exception.what()));
149  }
150  }
151  break;
152  case COMMAND_SAVEAS:
153  {
154  class OnTextSave: public virtual Action
155  {
156  public:
157  void performAction() override {
158  try {
159  textEditorTabController->view->saveFile(
160  textEditorTabController->popUps->getFileDialogScreenController()->getPathName(),
161  textEditorTabController->popUps->getFileDialogScreenController()->getFileName()
162  );
163  } catch (Exception& exception) {
164  textEditorTabController->showInfoPopUp("Warning", string(exception.what()));
165  }
166  textEditorTabController->popUps->getFileDialogScreenController()->close();
167  }
168 
169  /**
170  * Public constructor
171  * @param textEditorTabController text editor tab controller
172  */
173  OnTextSave(TextEditorTabController* textEditorTabController): textEditorTabController(textEditorTabController) {
174  }
175 
176  private:
177  TextEditorTabController* textEditorTabController;
178  };
179 
180  auto fileName = view->getFileName();
181  vector<string> extensions = {
182  view->getExtension()
183  };
185  Tools::getPathName(fileName),
186  "Save to: ",
187  extensions,
188  Tools::getFileName(fileName),
189  false,
190  new OnTextSave(this)
191  );
192  }
193  break;
194  case COMMAND_FINDREPLACE:
195  {
196  //
197  firstSearch = true;
199 
200  //
201  class FindAction: public virtual Action
202  {
203  public:
204  void performAction() override {
205  if (textEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText().empty() == true) {
206  textEditorTabController->showInfoPopUp("Find", "No find string given.");
207  } else {
208  if (textEditorTabController->view->find(
209  textEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText(),
210  textEditorTabController->popUps->getFindReplaceDialogScreenController()->isMatchCase(),
211  textEditorTabController->popUps->getFindReplaceDialogScreenController()->isWholeWordOnly(),
212  textEditorTabController->popUps->getFindReplaceDialogScreenController()->isInSelectionOnly(),
213  textEditorTabController->firstSearch,
214  textEditorTabController->searchIndex
215  ) == false) {
216  textEditorTabController->showInfoPopUp("Find", "Text not found.");
217  }
218  textEditorTabController->firstSearch = false;
219  }
220  }
221  FindAction(TextEditorTabController* textEditorTabController): textEditorTabController(textEditorTabController) {
222  }
223  private:
224  TextEditorTabController* textEditorTabController;
225  };
226  //
227  class CountAction: public virtual Action
228  {
229  public:
230  void performAction() override {
231  if (textEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText().empty() == true) {
232  textEditorTabController->showInfoPopUp("Count", "No find string given.");
233  } else {
234  auto count = textEditorTabController->view->count(
235  textEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText(),
236  textEditorTabController->popUps->getFindReplaceDialogScreenController()->isMatchCase(),
237  textEditorTabController->popUps->getFindReplaceDialogScreenController()->isWholeWordOnly(),
238  textEditorTabController->popUps->getFindReplaceDialogScreenController()->isInSelectionOnly()
239  );
240  textEditorTabController->showInfoPopUp("Count", "The text occurred " + to_string(count) + " times.");
241  }
242  }
243  CountAction(TextEditorTabController* textEditorTabController): textEditorTabController(textEditorTabController) {
244  }
245  private:
246  TextEditorTabController* textEditorTabController;
247  };
248  //
249  class ReplaceAction: public virtual Action
250  {
251  public:
252  void performAction() override {
253  if (textEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText().empty() == true) {
254  textEditorTabController->showInfoPopUp("Replace", "No find string given.");
255  } else {
256  if (textEditorTabController->view->replace(
257  textEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText(),
258  textEditorTabController->popUps->getFindReplaceDialogScreenController()->getReplaceText(),
259  textEditorTabController->popUps->getFindReplaceDialogScreenController()->isMatchCase(),
260  textEditorTabController->popUps->getFindReplaceDialogScreenController()->isWholeWordOnly(),
261  textEditorTabController->popUps->getFindReplaceDialogScreenController()->isInSelectionOnly(),
262  textEditorTabController->searchIndex
263  ) == false) {
264  textEditorTabController->showInfoPopUp("Replace", "Text not found.");
265  }
266  }
267  }
268  ReplaceAction(TextEditorTabController* textEditorTabController): textEditorTabController(textEditorTabController) {
269  }
270  private:
271  TextEditorTabController* textEditorTabController;
272  };
273  //
274  class ReplaceAllAction: public virtual Action
275  {
276  public:
277  void performAction() override {
278  if (textEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText().empty() == true) {
279  textEditorTabController->showInfoPopUp("Replace All", "No find string given.");
280  } else {
281  if (textEditorTabController->view->replaceAll(
282  textEditorTabController->popUps->getFindReplaceDialogScreenController()->getFindText(),
283  textEditorTabController->popUps->getFindReplaceDialogScreenController()->getReplaceText(),
284  textEditorTabController->popUps->getFindReplaceDialogScreenController()->isMatchCase(),
285  textEditorTabController->popUps->getFindReplaceDialogScreenController()->isWholeWordOnly(),
286  textEditorTabController->popUps->getFindReplaceDialogScreenController()->isInSelectionOnly()
287  ) == false) {
288  textEditorTabController->showInfoPopUp("Replace All", "Text not found.");
289  }
290  }
291  }
292  ReplaceAllAction(TextEditorTabController* textEditorTabController): textEditorTabController(textEditorTabController) {
293  }
294  private:
295  TextEditorTabController* textEditorTabController;
296  };
297  //
298  class CompleteAction: public virtual Action
299  {
300  public:
301  void performAction() override {
302  textEditorTabController->view->cancelFind();
303  textEditorTabController->popUps->getFindReplaceDialogScreenController()->close();
304  }
305  CompleteAction(TextEditorTabController* textEditorTabController): textEditorTabController(textEditorTabController) {
306  }
307  private:
308  TextEditorTabController* textEditorTabController;
309  };
310  //
312  new FindAction(this),
313  new CountAction(this),
314  new ReplaceAction(this),
315  new ReplaceAllAction(this),
316  new CompleteAction(this)
317  );
318  }
319  break;
320  default:
321  showInfoPopUp("Warning", "This command is not supported yet");
322  break;
323  }
324 }
325 
326 void TextEditorTabController::onDrop(const string& payload, int mouseX, int mouseY) {
327  showInfoPopUp("Warning", "You can not drop a file here");
328 }
329 
330 void TextEditorTabController::showInfoPopUp(const string& caption, const string& message)
331 {
332  popUps->getInfoDialogScreenController()->show(caption, message);
333 }
334 
336 {
337  if (node->getId() == "selectbox_outliner") {
338  auto outlinerNode = view->getEditorView()->getScreenController()->getOutlinerSelection();
339  if (StringTools::startsWith(outlinerNode, "miniscript.script.") == true) {
340  auto scriptIdx = Integer::parse(StringTools::substring(outlinerNode, string("miniscript.script.").size()));
341  if (view->isVisualEditor() == true) {
342  updateMiniScriptSyntaxTree(scriptIdx);
343  } else {
344  // TODO: jump to line
345  }
346  }
347  } else
348  if (node->getId() == view->getTabId() + "_tab_checkbox_visualcode" == true) {
349  auto visual = node->getController()->getValue().equals("1");
350  if (visual == true) {
353  } else {
354  view->setCodeEditor();
355  }
356  }
357 }
358 
360 {
361 }
362 
364  // if a node in this tab gets focussed, invalidate focus in main engine GUI
365  if (node->getScreenNode() == view->getTabScreenNode()) {
366  Engine::getInstance()->getGUI()->invalidateFocussedNode();
367  } else
368  // if a node in main engine GUI got focussed, invalidate tab focus
369  if (node->getScreenNode() == screenNode) {
371  } else {
372  Console::println("TextEditorTabController::onFocus(): Unknown screen node");
373  }
374 }
375 
377 }
378 
380  if (view->isVisualEditor() == false) return;
381  //
382  if (view->getEditorView()->getCurrentTabTooltipPosition(screenNode, mouseX, mouseY, contextMenuX, contextMenuY) == false) return;
383  //
384  auto nodeValue = node->getValue();
385  //
386  if (StringTools::startsWith(nodeValue, "node_") == true) {
388  contextMenuNodeId = StringTools::substring(nodeValue, string("node_").size());
389  } else
391  //
393  addNodeX = mouseX;
394  addNodeY = mouseY;
395 
396  }
397 }
398 
399 void TextEditorTabController::onTooltipShowRequest(GUINode* node, int mouseX, int mouseY) {
400  int tooltipLeft, tooltipTop;
401  if (view->getEditorView()->getCurrentTabTooltipPosition(screenNode, mouseX, mouseY, tooltipLeft, tooltipTop) == false) return;
402  //
403  popUps->getTooltipScreenController()->show(tooltipLeft, tooltipTop, node->getToolTip());
404 }
405 
408 }
409 
411  string xml;
412  xml+= "<selectbox-parent-option image=\"resources/engine/images/folder.png\" text=\"EngineMiniScript\" value=\"miniscript.script." + to_string(-1) + "\">\n";
413  auto scriptIdx = 0;
414  for (const auto& miniScriptSyntaxTree: miniScriptSyntaxTrees) {
415  xml+= "<selectbox-option text=\"" + GUIParser::escape(miniScriptSyntaxTree.name) + "\" value=\"miniscript.script." + to_string(scriptIdx) + "\" />\n";
416  scriptIdx++;
417  }
418  xml+= "</selectbox-parent-option>\n";
420 }
421 
424 }
425 
427  auto scriptFileName = view->getFileName();
428 
429  // we need to detect EngineMiniScript variant
430  vector<string> scriptAsStringArray;
431  try {
432  FileSystem::getInstance()->getContentAsStringArray(Tools::getPathName(scriptFileName), Tools::getFileName(scriptFileName), scriptAsStringArray);
433  } catch (Exception& exception) {
434  miniScriptSyntaxTrees.clear();
436  view->updateMiniScriptSyntaxTree(miniScriptScriptIdx);
437  //
438  showInfoPopUp("Warning", "Could not load script");
439  //
440  return;
441  }
442 
443  // load specific EngineMiniScript
444  scriptInstance = unique_ptr<EngineMiniScript>(EngineMiniScript::loadScript(Tools::getPathName(scriptFileName), Tools::getFileName(scriptFileName)));
445 
446  //
447  if (scriptInstance->isValid() == false) {
448  scriptInstance = nullptr;
449  miniScriptSyntaxTrees.clear();
451  view->updateMiniScriptSyntaxTree(miniScriptScriptIdx);
452  //
453  showInfoPopUp("Warning", "Could not load script. Script not valid!");
454  //
455  return;
456  }
457 
458  //
459  unordered_map<string, string> methodOperatorMap;
460  for (auto operatorMethod: scriptInstance->getOperatorMethods()) {
461  methodOperatorMap[operatorMethod->getMethodName()] = EngineMiniScript::getOperatorAsString(operatorMethod->getOperator());
462  }
463 
464  //
465  auto scriptIdx = 0;
466  miniScriptSyntaxTrees.clear();
467  for (auto script: scriptInstance->getScripts()) {
468  // determine name
469  string name;
470  string argumentsString;
471  switch(script.scriptType) {
472  case EngineMiniScript::Script::SCRIPTTYPE_FUNCTION: {
473  for (const auto& argument: script.arguments) {
474  if (argumentsString.empty() == false) argumentsString+= ", ";
475  if (argument.reference == true) argumentsString+= "=";
476  argumentsString+= argument.name;
477  }
478  argumentsString = "(" + argumentsString + ")";
479  name+= "function: "; break;
480  }
481  case EngineMiniScript::Script::SCRIPTTYPE_ON: name+= "on: "; break;
482  case EngineMiniScript::Script::SCRIPTTYPE_ONENABLED: name+= "on-enabled: "; break;
483  }
484  if (script.name.empty() == false) {
485  name+= script.name;
486  } else
487  if (script.condition.empty() == false)
488  name+= script.condition + (argumentsString.empty() == false?": " + argumentsString:"");
489  //
490  miniScriptSyntaxTrees.push_back(
491  {
492  .type = script.scriptType,
493  .condition = script.condition,
494  .name = name,
495  .conditionSyntaxTree = script.conditionSyntaxTree,
496  .syntaxTree = script.syntaxTree
497  }
498  );
499 
500  //
501  scriptIdx++;
502  }
503 
504  // pass it to view
505  view->setMiniScriptMethodOperatorMap(methodOperatorMap);
506  view->updateMiniScriptSyntaxTree(miniScriptScriptIdx);
507 
508  //
510 }
511 
514 }
Engine main class.
Definition: Engine.h:131
Texture entity.
Definition: Texture.h:24
GUI parser.
Definition: GUIParser.h:40
GUI module class.
Definition: GUI.h:64
void invalidateFocussedNode()
Invalidate focussed node.
Definition: GUI.cpp:197
GUI node controller base class.
virtual const MutableString & getValue()=0
GUI node base class.
Definition: GUINode.h:64
const string & getToolTip()
Definition: GUINode.h:346
GUINodeController * getController()
Definition: GUINode.h:661
GUIScreenNode * getScreenNode()
Definition: GUINode.h:325
const string & getId()
Definition: GUINode.h:339
GUI parent node base class thats supporting child nodes.
Definition: GUIParentNode.h:42
GUI screen node that represents a screen that can be rendered via GUI system.
Definition: GUIScreenNode.h:72
void addChangeListener(GUIChangeListener *listener)
Add change listener.
void removeFocusListener(GUIFocusListener *listener)
Remove focus listener.
void addActionListener(GUIActionListener *listener)
Add action listener.
void addFocusListener(GUIFocusListener *listener)
Add focus listener.
File system singleton class.
Definition: FileSystem.h:17
void show(const string &cwd, const string &captionText, const vector< string > &extensions, const string &fileName, bool enableFilter, Action *applyAction, Action *cancelAction=nullptr, const string &settingsFileName=".filedialog.properties", const string &settingsPathName=string())
Shows the file dialog pop up.
void show(Action *findAction, Action *countAction, Action *replaceAction, Action *replaceAllAction, Action *completeAction)
Shows the pop up.
void show(const string &caption, const string &message)
Shows the pop up.
void show(int mouseX, int mouseY, const string &tooltip)
Show tooltip.
Pop ups controller accessor class.
Definition: PopUps.h:29
FindReplaceDialogScreenController * getFindReplaceDialogScreenController()
Definition: PopUps.h:110
FileDialogScreenController * getFileDialogScreenController()
Definition: PopUps.h:61
TooltipScreenController * getTooltipScreenController()
Definition: PopUps.h:131
InfoDialogScreenController * getInfoDialogScreenController()
Definition: PopUps.h:75
void onContextMenuRequest(GUIElementNode *node, int mouseX, int mouseY) override
On context menu request.
void onDrop(const string &payload, int mouseX, int mouseY) override
On drop.
void setOutlinerAddDropDownContent()
Set outliner add drop down content.
void onCommand(TabControllerCommand command) override
On command.
void onUnfocus(GUIElementNode *node) override
On unfocus.
void updateMiniScriptSyntaxTree(int miniScriptScriptIdx)
Update EngineMiniScript syntax tree.
void showInfoPopUp(const string &caption, const string &message)
Show the information pop up / modal.
void onAction(GUIActionListenerType type, GUIElementNode *node) override
void onTooltipShowRequest(GUINode *node, int mouseX, int mouseY) override
On tooltip show request.
void saveFile(const string &pathName, const string &fileName)
Save file.
void setMiniScriptMethodOperatorMap(const unordered_map< string, string > &methodOperatorMap)
Set method -> operator map.
void updateMiniScriptSyntaxTree(int miniScriptScriptIdx)
Update miniscript syntax tree.
void setOutlinerAddDropDownContent(const string &xml)
Set outliner add drop down content.
Definition: EditorView.cpp:400
void setOutlinerContent(const string &xml)
Set outliner content.
Definition: EditorView.cpp:396
EditorScreenController * getScreenController()
Definition: EditorView.h:69
bool getCurrentTabTooltipPosition(GUIScreenNode *screenNode, int mouseX, int mouseY, int &tooltipLeft, int &tooltipTop)
Determine current tab tooltip position.
Definition: EditorView.cpp:439
Console class.
Definition: Console.h:29
Exception base class.
Definition: ExceptionBase.h:19
Integer class.
Definition: Integer.h:25
bool equals(const string &s2) const
Equals.
String tools class.
Definition: StringTools.h:22
An attribute is a name-value pair.
Definition: tinyxml.h:734
Always the top level node.
Definition: tinyxml.h:1317
The element is a container class.
Definition: tinyxml.h:886
std::exception Exception
Exception base class.
Definition: Exception.h:18
Tab controller, which connects UI with logic.
Definition: TabController.h:34
Action Interface.
Definition: Action.h:11