1 // Aseprite
2 // Copyright (C) 2001-2018 David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include "app/context.h"
12
13 #include "app/app.h"
14 #include "app/commands/command.h"
15 #include "app/commands/commands.h"
16 #include "app/console.h"
17 #include "app/doc.h"
18 #include "app/site.h"
19 #include "doc/layer.h"
20
21 #include <algorithm>
22 #include <stdexcept>
23
24 namespace app {
25
Context()26 Context::Context()
27 : m_docs(this)
28 , m_lastSelectedDoc(nullptr)
29 {
30 m_docs.add_observer(this);
31 }
32
~Context()33 Context::~Context()
34 {
35 m_docs.remove_observer(this);
36 }
37
sendDocumentToTop(Doc * document)38 void Context::sendDocumentToTop(Doc* document)
39 {
40 ASSERT(document != NULL);
41
42 documents().move(document, 0);
43 }
44
activeSite() const45 Site Context::activeSite() const
46 {
47 Site site;
48 onGetActiveSite(&site);
49 return site;
50 }
51
activeDocument() const52 Doc* Context::activeDocument() const
53 {
54 Site site;
55 onGetActiveSite(&site);
56 return site.document();
57 }
58
setActiveDocument(Doc * document)59 void Context::setActiveDocument(Doc* document)
60 {
61 onSetActiveDocument(document);
62 }
63
hasModifiedDocuments() const64 bool Context::hasModifiedDocuments() const
65 {
66 for (auto doc : documents())
67 if (doc->isModified())
68 return true;
69 return false;
70 }
71
notifyActiveSiteChanged()72 void Context::notifyActiveSiteChanged()
73 {
74 Site site = activeSite();
75 notify_observers<const Site&>(&ContextObserver::onActiveSiteChange, site);
76 }
77
executeCommand(const char * commandName)78 void Context::executeCommand(const char* commandName)
79 {
80 Command* cmd = Commands::instance()->byId(commandName);
81 if (cmd)
82 executeCommand(cmd);
83 else
84 throw std::runtime_error("Invalid command name");
85 }
86
executeCommand(Command * command,const Params & params)87 void Context::executeCommand(Command* command, const Params& params)
88 {
89 Console console;
90
91 ASSERT(command != NULL);
92 if (command == NULL)
93 return;
94
95 LOG(VERBOSE) << "CTXT: Executing command " << command->id() << "\n";
96 try {
97 m_flags.update(this);
98
99 ASSERT(!command->needsParams() || !params.empty());
100
101 command->loadParams(params);
102
103 CommandExecutionEvent ev(command);
104 BeforeCommandExecution(ev);
105
106 if (ev.isCanceled()) {
107 LOG(VERBOSE) << "CTXT: Command " << command->id() << " was canceled/simulated.\n";
108 }
109 else if (command->isEnabled(this)) {
110 command->execute(this);
111 LOG(VERBOSE) << "CTXT: Command " << command->id() << " executed successfully\n";
112 }
113 else {
114 LOG(VERBOSE) << "CTXT: Command " << command->id() << " is disabled\n";
115 }
116
117 AfterCommandExecution(ev);
118
119 // TODO move this code to another place (e.g. a Workplace/Tabs widget)
120 if (isUIAvailable())
121 app_rebuild_documents_tabs();
122 }
123 catch (base::Exception& e) {
124 LOG(ERROR) << "CTXT: Exception caught executing " << command->id() << " command\n"
125 << e.what() << "\n";
126
127 Console::showException(e);
128 }
129 catch (std::exception& e) {
130 LOG(ERROR) << "CTXT: std::exception caught executing " << command->id() << " command\n"
131 << e.what() << "\n";
132
133 console.printf("An error ocurred executing the command.\n\nDetails:\n%s", e.what());
134 }
135 #ifdef NDEBUG
136 catch (...) {
137 LOG(ERROR) << "CTXT: Unknown exception executing " << command->id() << " command\n";
138
139 console.printf("An unknown error ocurred executing the command.\n"
140 "Please save your work, close the program, try it\n"
141 "again, and report this bug.\n\n"
142 "Details: Unknown exception caught. This can be bad\n"
143 "memory access, divison by zero, etc.");
144 }
145 #endif
146 }
147
onCreateDocument(CreateDocArgs * args)148 void Context::onCreateDocument(CreateDocArgs* args)
149 {
150 args->setDocument(new Doc(nullptr));
151 }
152
onAddDocument(Doc * doc)153 void Context::onAddDocument(Doc* doc)
154 {
155 m_lastSelectedDoc = doc;
156 }
157
onRemoveDocument(Doc * doc)158 void Context::onRemoveDocument(Doc* doc)
159 {
160 if (doc == m_lastSelectedDoc)
161 m_lastSelectedDoc = nullptr;
162 }
163
onGetActiveSite(Site * site) const164 void Context::onGetActiveSite(Site* site) const
165 {
166 // Default/dummy site (maybe for batch/command line mode)
167 if (Doc* doc = m_lastSelectedDoc) {
168 site->document(doc);
169 site->sprite(doc->sprite());
170 site->layer(doc->sprite()->root()->firstLayer());
171 site->frame(0);
172 }
173 }
174
onSetActiveDocument(Doc * doc)175 void Context::onSetActiveDocument(Doc* doc)
176 {
177 m_lastSelectedDoc = doc;
178 }
179
180 } // namespace app
181