OSDN Git Service

583bb25cad46c4c8618cc6decc2726bbfa98e88c
[qt-creator-jp/qt-creator-jp.git] / src / plugins / macros / macromanager.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2010 Nicolas Arnaud-Cormos.
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "macromanager.h"
35
36 #include "macrosconstants.h"
37 #include "macroevent.h"
38 #include "macro.h"
39 #include "imacrohandler.h"
40 #include "savedialog.h"
41 #include "actionmacrohandler.h"
42 #include "texteditormacrohandler.h"
43 #include "findmacrohandler.h"
44
45 #include <texteditor/texteditorconstants.h>
46
47 #include <coreplugin/coreconstants.h>
48 #include <coreplugin/actionmanager/actionmanager.h>
49 #include <coreplugin/actionmanager/actioncontainer.h>
50 #include <coreplugin/actionmanager/command.h>
51 #include <coreplugin/icore.h>
52 #include <coreplugin/uniqueidmanager.h>
53 #include <coreplugin/icontext.h>
54 #include <coreplugin/editormanager/editormanager.h>
55 #include <coreplugin/editormanager/ieditor.h>
56
57 #include <QtCore/QDir>
58 #include <QtCore/QFile>
59 #include <QtCore/QFileInfo>
60 #include <QtCore/QSettings>
61 #include <QtCore/QSignalMapper>
62 #include <QtCore/QList>
63
64 #include <QtGui/QShortcut>
65 #include <QtGui/QMainWindow>
66 #include <QtGui/QAction>
67 #include <QtGui/QFileDialog>
68 #include <QtGui/QMessageBox>
69
70 using namespace Macros;
71 using namespace Macros::Internal;
72
73 /*!
74     \namespace Macros
75     \brief The Macros namespace contains support for macros in Qt Creator.
76 */
77
78 /*!
79
80     \class Macro::MacroManager
81     \brief Manager for macros.
82
83     The MacroManager manage all macros, it loads them on startup, keep track of the
84     current macro and create new macros.
85
86     There are two important methods in this class that can be used outside the Macros plugin:
87     \list
88     \o registerEventHandler: add a new event handler
89     \o registerAction: add a macro event when this action is triggered
90     \endlist
91
92     This class is a singleton and can be accessed using the instance method.
93 */
94
95 /*!
96     \fn void registerAction(QAction *action, const QString &id)
97
98     Append this action to the list of actions registered in a macro. The id is
99     the action id passed to the ActionManager.
100 */
101
102 class Macros::MacroManager::MacroManagerPrivate
103 {
104 public:
105     MacroManagerPrivate(MacroManager *qq);
106
107     MacroManager *q;
108     QMap<QString, Macro *> macros;
109     Macro *currentMacro;
110     bool isRecording;
111
112     QList<IMacroHandler*> handlers;
113
114     QSignalMapper *mapper;
115
116     ActionMacroHandler *actionHandler;
117     TextEditorMacroHandler *textEditorHandler;
118     FindMacroHandler *findHandler;
119
120     void initialize();
121     void addMacro(Macro *macro);
122     void removeMacro(const QString &name);
123     void changeMacroDescription(Macro *macro, const QString &description);
124
125     bool executeMacro(Macro *macro);
126     void showSaveDialog();
127 };
128
129 MacroManager::MacroManagerPrivate::MacroManagerPrivate(MacroManager *qq):
130     q(qq),
131     currentMacro(0),
132     isRecording(false),
133     mapper(new QSignalMapper(qq))
134 {
135     connect(mapper, SIGNAL(mapped(QString)), q, SLOT(executeMacro(QString)));
136
137     // Load existing macros
138     initialize();
139
140     actionHandler = new ActionMacroHandler;
141     textEditorHandler = new TextEditorMacroHandler;
142     findHandler = new FindMacroHandler;
143 }
144
145 void MacroManager::MacroManagerPrivate::initialize()
146 {
147     macros.clear();
148     QDir dir(q->macrosDirectory());
149     QStringList filter;
150     filter << QString("*.")+Constants::M_EXTENSION;
151     QStringList files = dir.entryList(filter, QDir::Files);
152
153     foreach (const QString &name, files) {
154         QString fileName = dir.absolutePath() + '/' + name;
155         Macro *macro = new Macro;
156         macro->loadHeader(fileName);
157         addMacro(macro);
158     }
159 }
160
161 void MacroManager::MacroManagerPrivate::addMacro(Macro *macro)
162 {
163     // Add sortcut
164     Core::Context context(TextEditor::Constants::C_TEXTEDITOR);
165     Core::ICore *core = Core::ICore::instance();
166     Core::ActionManager *am = core->actionManager();
167     QShortcut *shortcut = new QShortcut(core->mainWindow());
168     shortcut->setWhatsThis(macro->description());
169     const QString macroId = QLatin1String(Constants::PREFIX_MACRO) + macro->displayName();
170     am->registerShortcut(shortcut, macroId, context);
171     connect(shortcut, SIGNAL(activated()), mapper, SLOT(map()));
172     mapper->setMapping(shortcut, macro->displayName());
173
174     // Add macro to the map
175     macros[macro->displayName()] = macro;
176 }
177
178 void MacroManager::MacroManagerPrivate::removeMacro(const QString &name)
179 {
180     if (!macros.contains(name))
181         return;
182     // Remove shortcut
183     Core::ICore *core = Core::ICore::instance();
184     Core::ActionManager *am = core->actionManager();
185     am->unregisterShortcut(Core::Id(Constants::PREFIX_MACRO+name));
186
187     // Remove macro from the map
188     Macro *macro = macros.take(name);
189     delete macro;
190 }
191
192 void MacroManager::MacroManagerPrivate::changeMacroDescription(Macro *macro, const QString &description)
193 {
194     macro->load();
195     macro->setDescription(description);
196     macro->save(macro->fileName());
197
198     // Change shortcut what's this
199     Core::ICore *core = Core::ICore::instance();
200     Core::ActionManager *am = core->actionManager();
201
202     Core::Command *command = am->command(Core::Id(Constants::PREFIX_MACRO+macro->displayName()));
203     if (command && command->shortcut())
204         command->shortcut()->setWhatsThis(description);
205 }
206
207 bool MacroManager::MacroManagerPrivate::executeMacro(Macro *macro)
208 {
209     macro->load();
210     bool error = false;
211     foreach (const MacroEvent &macroEvent, macro->events()) {
212         foreach (IMacroHandler *handler, handlers) {
213             if (handler->canExecuteEvent(macroEvent)) {
214                 if (!handler->executeEvent(macroEvent))
215                     error = true;
216                 break;
217             }
218         }
219         if (error)
220             break;
221     }
222
223     if (error) {
224         QMessageBox::warning(Core::ICore::instance()->mainWindow(),
225                              tr("Playing Macro"),
226                              tr("An error occured while replaying the macro, execution stopped."));
227     }
228
229     // Set the focus back to the editor
230     // TODO: is it really needed??
231     const Core::EditorManager *editorManager = Core::EditorManager::instance();
232     if (editorManager->currentEditor())
233         editorManager->currentEditor()->widget()->setFocus(Qt::OtherFocusReason);
234
235     return !error;
236 }
237
238 void MacroManager::MacroManagerPrivate::showSaveDialog()
239 {
240     QMainWindow *mainWindow = Core::ICore::instance()->mainWindow();
241     SaveDialog dialog(mainWindow);
242     if (dialog.exec()) {
243         if (dialog.name().isEmpty())
244             return;
245
246         // Save in the resource path
247         QString fileName = q->macrosDirectory() + '/' + dialog.name()
248                            + '.' + Constants::M_EXTENSION;
249         currentMacro->setDescription(dialog.description());
250         currentMacro->save(fileName);
251         addMacro(currentMacro);
252     }
253 }
254
255
256 // ---------- MacroManager ------------
257 MacroManager *MacroManager::m_instance = 0;
258
259 MacroManager::MacroManager(QObject *parent) :
260     QObject(parent),
261     d(new MacroManagerPrivate(this))
262 {
263     registerMacroHandler(d->actionHandler);
264     registerMacroHandler(d->findHandler);
265     registerMacroHandler(d->textEditorHandler);
266     m_instance = this;
267 }
268
269 MacroManager::~MacroManager()
270 {
271     // Cleanup macro
272     QStringList macroList = d->macros.keys();
273     foreach (const QString &name, macroList)
274         d->removeMacro(name);
275
276     // Cleanup handlers
277     qDeleteAll(d->handlers);
278
279     delete d;
280 }
281
282 void MacroManager::startMacro()
283 {
284     d->isRecording = true;
285     // Delete anonymous macro
286     if (d->currentMacro && d->currentMacro->displayName().isEmpty())
287         delete d->currentMacro;
288     d->currentMacro = new Macro;
289
290     Core::ActionManager *am = Core::ICore::instance()->actionManager();
291     am->command(Constants::START_MACRO)->action()->setEnabled(false);
292     am->command(Constants::END_MACRO)->action()->setEnabled(true);
293     am->command(Constants::EXECUTE_LAST_MACRO)->action()->setEnabled(false);
294     am->command(Constants::SAVE_LAST_MACRO)->action()->setEnabled(false);
295     foreach (IMacroHandler *handler, d->handlers)
296         handler->startRecording(d->currentMacro);
297
298     QString endShortcut = am->command(Constants::END_MACRO)->defaultKeySequence().toString();
299     QString executeShortcut = am->command(Constants::EXECUTE_LAST_MACRO)->defaultKeySequence().toString();
300     QString help = tr("Macro mode. Type \"%1\" to stop recording and \"%2\" to play it")
301         .arg(endShortcut).arg(executeShortcut);
302     Core::EditorManager::instance()->showEditorStatusBar(
303                 QLatin1String(Constants::M_STATUS_BUFFER),
304                 help,
305                 tr("Stop Recording Macro"), this, SLOT(endMacro()));
306 }
307
308 void MacroManager::endMacro()
309 {
310     Core::EditorManager::instance()->hideEditorStatusBar(QLatin1String(Constants::M_STATUS_BUFFER));
311
312     Core::ActionManager *am = Core::ICore::instance()->actionManager();
313     am->command(Constants::START_MACRO)->action()->setEnabled(true);
314     am->command(Constants::END_MACRO)->action()->setEnabled(false);
315     am->command(Constants::EXECUTE_LAST_MACRO)->action()->setEnabled(true);
316     am->command(Constants::SAVE_LAST_MACRO)->action()->setEnabled(true);
317     foreach (IMacroHandler *handler, d->handlers)
318         handler->endRecordingMacro(d->currentMacro);
319
320     d->isRecording = false;
321 }
322
323 void MacroManager::executeLastMacro()
324 {
325     if (d->currentMacro)
326         d->executeMacro(d->currentMacro);
327 }
328
329 bool MacroManager::executeMacro(const QString &name)
330 {
331     // Don't execute macro while recording
332     if (d->isRecording || !d->macros.contains(name))
333         return false;
334
335     Macro *macro = d->macros.value(name);
336     if (!d->executeMacro(macro))
337         return false;
338
339     // Delete anonymous macro
340     if (d->currentMacro && d->currentMacro->displayName().isEmpty())
341         delete d->currentMacro;
342     d->currentMacro = macro;
343
344     Core::ActionManager *am = Core::ICore::instance()->actionManager();
345     am->command(Constants::SAVE_LAST_MACRO)->action()->setEnabled(true);
346
347     return true;
348 }
349
350 void MacroManager::deleteMacro(const QString &name)
351 {
352     Macro *macro = d->macros.value(name);
353     if (macro) {
354         QString fileName = macro->fileName();
355         d->removeMacro(name);
356         QFile::remove(fileName);
357     }
358 }
359
360 const QMap<QString,Macro*> &MacroManager::macros() const
361 {
362     return d->macros;
363 }
364
365 void MacroManager::registerMacroHandler(IMacroHandler *handler)
366 {
367     d->handlers.prepend(handler);
368 }
369
370 MacroManager *MacroManager::instance()
371 {
372     return m_instance;
373 }
374
375 void MacroManager::changeMacro(const QString &name, const QString &description)
376 {
377     if (!d->macros.contains(name))
378         return;
379     Macro *macro = d->macros.value(name);
380
381     // Change description
382     if (macro->description() != description)
383         d->changeMacroDescription(macro, description);
384 }
385
386 void Macros::MacroManager::saveLastMacro()
387 {
388     if (d->currentMacro->events().count())
389         d->showSaveDialog();
390 }
391
392 QString Macros::MacroManager::macrosDirectory() const
393 {
394     const QString &path =
395         Core::ICore::instance()->userResourcePath() + QLatin1String("/macros");
396     if (QFile::exists(path) || QDir().mkpath(path))
397         return path;
398     return QString();
399 }