editormanager.cpp 91.4 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30
#include "editormanager.h"
31
#include "editorview.h"
32
#include "findplaceholder.h"
con's avatar
con committed
33
#include "openeditorswindow.h"
mae's avatar
mae committed
34
#include "openeditorsview.h"
35
#include "openeditorsmodel.h"
con's avatar
con committed
36
#include "openwithdialog.h"
37
38
39
#include "outputpane.h"
#include "outputpanemanager.h"
#include "rightpane.h"
40
#include "documentmanager.h"
41
#include "icore.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
42
#include "ieditor.h"
con's avatar
con committed
43
44
#include "iversioncontrol.h"
#include "mimedatabase.h"
45
#include "vcsmanager.h"
con's avatar
con committed
46

47
#include <coreplugin/actionmanager/actioncontainer.h>
hjk's avatar
hjk committed
48
49
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/coreconstants.h>
con's avatar
con committed
50
#include <coreplugin/editormanager/ieditorfactory.h>
51
#include <coreplugin/editormanager/iexternaleditor.h>
hjk's avatar
hjk committed
52
53
#include <coreplugin/editortoolbar.h>
#include <coreplugin/fileutils.h>
54
#include <coreplugin/icorelistener.h>
hjk's avatar
hjk committed
55
56
#include <coreplugin/infobar.h>
#include <coreplugin/modemanager.h>
57
#include <coreplugin/settingsdatabase.h>
58
#include <coreplugin/variablemanager.h>
59
#include <coreplugin/dialogs/readonlyfilesdialog.h>
con's avatar
con committed
60

61
62
#include <extensionsystem/pluginmanager.h>

63
#include <utils/hostosinfo.h>
hjk's avatar
hjk committed
64
65
#include <utils/qtcassert.h>

66
67
68
69
70
71
72
73
#include <QDateTime>
#include <QDebug>
#include <QFileInfo>
#include <QMap>
#include <QSet>
#include <QSettings>
#include <QTextCodec>
#include <QTimer>
con's avatar
con committed
74

75
76
77
78
79
80
81
82
#include <QAction>
#include <QShortcut>
#include <QApplication>
#include <QFileDialog>
#include <QMenu>
#include <QMessageBox>
#include <QPushButton>
#include <QSplitter>
con's avatar
con committed
83
84
85

enum { debugEditorManager=0 };

86
static const char kCurrentDocumentPrefix[] = "CurrentDocument";
Friedemann Kleint's avatar
Friedemann Kleint committed
87
88
static const char kCurrentDocumentXPos[] = "CurrentDocument:XPos";
static const char kCurrentDocumentYPos[] = "CurrentDocument:YPos";
89
static const char kMakeWritableWarning[] = "Core.EditorManager.MakeWritable";
con's avatar
con committed
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
//===================EditorClosingCoreListener======================

namespace Core {
namespace Internal {

class EditorClosingCoreListener : public ICoreListener
{
public:
    EditorClosingCoreListener(EditorManager *em);
    bool editorAboutToClose(IEditor *editor);
    bool coreAboutToClose();

private:
    EditorManager *m_em;
};

EditorClosingCoreListener::EditorClosingCoreListener(EditorManager *em)
        : m_em(em)
{
}

bool EditorClosingCoreListener::editorAboutToClose(IEditor *)
{
    return true;
}

bool EditorClosingCoreListener::coreAboutToClose()
{
    // Do not ask for files to save.
    // MainWindow::closeEvent has already done that.
    return m_em->closeAllEditors(false);
}

} // namespace Internal
} // namespace Core

using namespace Core;
using namespace Core::Internal;
using namespace Utils;

con's avatar
con committed
131
132
133
134
135
136
137
138
139
//===================EditorManager=====================

EditorManagerPlaceHolder *EditorManagerPlaceHolder::m_current = 0;

EditorManagerPlaceHolder::EditorManagerPlaceHolder(Core::IMode *mode, QWidget *parent)
    : QWidget(parent), m_mode(mode)
{
    setLayout(new QVBoxLayout);
    layout()->setMargin(0);
Robert Loehning's avatar
Robert Loehning committed
140
141
    connect(Core::ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode*)),
            this, SLOT(currentModeChanged(Core::IMode*)));
142

143
    currentModeChanged(ModeManager::currentMode());
con's avatar
con committed
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
}

EditorManagerPlaceHolder::~EditorManagerPlaceHolder()
{
    if (m_current == this) {
        EditorManager::instance()->setParent(0);
        EditorManager::instance()->hide();
    }
}

void EditorManagerPlaceHolder::currentModeChanged(Core::IMode *mode)
{
    if (m_mode == mode) {
        m_current = this;
        layout()->addWidget(EditorManager::instance());
        EditorManager::instance()->show();
160
161
    } else if (m_current == this) {
        m_current = 0;
con's avatar
con committed
162
163
164
165
166
167
168
169
170
171
    }
}

EditorManagerPlaceHolder* EditorManagerPlaceHolder::current()
{
    return m_current;
}

// ---------------- EditorManager

172
namespace Core {
173
174


175
class EditorManagerPrivate
hjk's avatar
hjk committed
176
{
177
public:
hjk's avatar
hjk committed
178
    explicit EditorManagerPrivate(QWidget *parent);
con's avatar
con committed
179
    ~EditorManagerPrivate();
180
    QList<EditLocation> m_globalHistory;
181
    QList<Internal::SplitterOrView *> m_root;
182
    QList<IContext *> m_rootContext;
mae's avatar
mae committed
183
    QPointer<IEditor> m_currentEditor;
184
    QPointer<IEditor> m_scheduledCurrentEditor;
185
    QPointer<EditorView> m_currentView;
186
    QTimer *m_autoSaveTimer;
187

con's avatar
con committed
188
189
190
191
192
193
    // actions
    QAction *m_revertToSavedAction;
    QAction *m_saveAction;
    QAction *m_saveAsAction;
    QAction *m_closeCurrentEditorAction;
    QAction *m_closeAllEditorsAction;
con's avatar
con committed
194
    QAction *m_closeOtherEditorsAction;
con's avatar
con committed
195
196
197
198
    QAction *m_gotoNextDocHistoryAction;
    QAction *m_gotoPreviousDocHistoryAction;
    QAction *m_goBackAction;
    QAction *m_goForwardAction;
199
200
    QAction *m_splitAction;
    QAction *m_splitSideBySideAction;
201
    QAction *m_splitNewWindowAction;
202
203
    QAction *m_removeCurrentSplitAction;
    QAction *m_removeAllSplitsAction;
204
    QAction *m_gotoNextSplitAction;
con's avatar
con committed
205

206
207
208
209
    QAction *m_saveCurrentEditorContextAction;
    QAction *m_saveAsCurrentEditorContextAction;
    QAction *m_revertToSavedCurrentEditorContextAction;

210
211
212
    QAction *m_closeCurrentEditorContextAction;
    QAction *m_closeAllEditorsContextAction;
    QAction *m_closeOtherEditorsContextAction;
Robert Loehning's avatar
Robert Loehning committed
213
214
    QAction *m_openGraphicalShellAction;
    QAction *m_openTerminalAction;
215
216
    QModelIndex m_contextMenuEditorIndex;

con's avatar
con committed
217
218
219
220
221
222
    Internal::OpenEditorsWindow *m_windowPopup;
    Internal::EditorClosingCoreListener *m_coreListener;

    QMap<QString, QVariant> m_editorStates;
    Internal::OpenEditorsViewFactory *m_openEditorsFactory;

223
    OpenEditorsModel *m_editorModel;
224

225
    IDocument::ReloadSetting m_reloadSetting;
226
227

    QString m_titleAddition;
228
229
230

    bool m_autoSaveEnabled;
    int m_autoSaveInterval;
con's avatar
con committed
231
};
232
}
con's avatar
con committed
233

hjk's avatar
hjk committed
234
EditorManagerPrivate::EditorManagerPrivate(QWidget *parent) :
235
    m_autoSaveTimer(0),
con's avatar
con committed
236
237
238
239
240
    m_revertToSavedAction(new QAction(EditorManager::tr("Revert to Saved"), parent)),
    m_saveAction(new QAction(parent)),
    m_saveAsAction(new QAction(parent)),
    m_closeCurrentEditorAction(new QAction(EditorManager::tr("Close"), parent)),
    m_closeAllEditorsAction(new QAction(EditorManager::tr("Close All"), parent)),
con's avatar
con committed
241
    m_closeOtherEditorsAction(new QAction(EditorManager::tr("Close Others"), parent)),
mae's avatar
mae committed
242
243
    m_gotoNextDocHistoryAction(new QAction(EditorManager::tr("Next Open Document in History"), parent)),
    m_gotoPreviousDocHistoryAction(new QAction(EditorManager::tr("Previous Open Document in History"), parent)),
244
245
    m_goBackAction(new QAction(QIcon(QLatin1String(Constants::ICON_PREV)), EditorManager::tr("Go Back"), parent)),
    m_goForwardAction(new QAction(QIcon(QLatin1String(Constants::ICON_NEXT)), EditorManager::tr("Go Forward"), parent)),
246
247
248
    m_saveCurrentEditorContextAction(new QAction(EditorManager::tr("&Save"), parent)),
    m_saveAsCurrentEditorContextAction(new QAction(EditorManager::tr("Save &As..."), parent)),
    m_revertToSavedCurrentEditorContextAction(new QAction(EditorManager::tr("Revert to Saved"), parent)),
249
250
251
    m_closeCurrentEditorContextAction(new QAction(EditorManager::tr("Close"), parent)),
    m_closeAllEditorsContextAction(new QAction(EditorManager::tr("Close All"), parent)),
    m_closeOtherEditorsContextAction(new QAction(EditorManager::tr("Close Others"), parent)),
Robert Loehning's avatar
Robert Loehning committed
252
253
    m_openGraphicalShellAction(new QAction(FileUtils::msgGraphicalShellAction(), parent)),
    m_openTerminalAction(new QAction(FileUtils::msgTerminalAction(), parent)),
con's avatar
con committed
254
    m_windowPopup(0),
255
    m_coreListener(0),
256
    m_reloadSetting(IDocument::AlwaysAsk),
257
258
    m_autoSaveEnabled(true),
    m_autoSaveInterval(5)
con's avatar
con committed
259
{
260
    m_editorModel = new OpenEditorsModel(parent);
con's avatar
con committed
261
262
263
264
}

EditorManagerPrivate::~EditorManagerPrivate()
{
265
//    clearNavigationHistory();
con's avatar
con committed
266
267
}

hjk's avatar
hjk committed
268
static EditorManager *m_instance = 0;
269
static EditorManagerPrivate *d;
hjk's avatar
hjk committed
270
271

EditorManager *EditorManager::instance() { return m_instance; }
con's avatar
con committed
272

hjk's avatar
hjk committed
273
EditorManager::EditorManager(QWidget *parent) :
274
    QWidget(parent)
con's avatar
con committed
275
{
276
    d = new EditorManagerPrivate(parent);
con's avatar
con committed
277
278
    m_instance = this;

279
280
    connect(ICore::instance(), SIGNAL(contextAboutToChange(QList<Core::IContext*>)),
            this, SLOT(handleContextChange(QList<Core::IContext*>)));
con's avatar
con committed
281

282
    const Context editManagerContext(Constants::C_EDITORMANAGER);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
283
    // combined context for edit & design modes
284
    const Context editDesignContext(Constants::C_EDITORMANAGER, Constants::C_DESIGN_MODE);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
285

Eike Ziller's avatar
Eike Ziller committed
286
    ActionContainer *mfile = ActionManager::actionContainer(Constants::M_FILE);
con's avatar
con committed
287

288
    // Revert to saved
hjk's avatar
hjk committed
289
    d->m_revertToSavedAction->setIcon(QIcon::fromTheme(QLatin1String("document-revert")));
Eike Ziller's avatar
Eike Ziller committed
290
    Command *cmd = ActionManager::registerAction(d->m_revertToSavedAction,
con's avatar
con committed
291
                                       Constants::REVERTTOSAVED, editManagerContext);
con's avatar
con committed
292
    cmd->setAttribute(Command::CA_UpdateText);
293
    cmd->setDescription(tr("Revert File to Saved"));
con's avatar
con committed
294
    mfile->addAction(cmd, Constants::G_FILE_SAVE);
hjk's avatar
hjk committed
295
    connect(d->m_revertToSavedAction, SIGNAL(triggered()), this, SLOT(revertToSaved()));
con's avatar
con committed
296

297
    // Save Action
Eike Ziller's avatar
Eike Ziller committed
298
    ActionManager::registerAction(d->m_saveAction, Constants::SAVE, editManagerContext);
299
    connect(d->m_saveAction, SIGNAL(triggered()), this, SLOT(saveDocument()));
con's avatar
con committed
300

301
    // Save As Action
Eike Ziller's avatar
Eike Ziller committed
302
    ActionManager::registerAction(d->m_saveAsAction, Constants::SAVEAS, editManagerContext);
303
    connect(d->m_saveAsAction, SIGNAL(triggered()), this, SLOT(saveDocumentAs()));
con's avatar
con committed
304

305
    // Window Menu
Eike Ziller's avatar
Eike Ziller committed
306
    ActionContainer *mwindow = ActionManager::actionContainer(Constants::M_WINDOW);
con's avatar
con committed
307

308
    // Window menu separators
309
310
    mwindow->addSeparator(editManagerContext, Constants::G_WINDOW_SPLIT);
    mwindow->addSeparator(editManagerContext, Constants::G_WINDOW_NAVIGATE);
con's avatar
con committed
311

312
    // Close Action
Eike Ziller's avatar
Eike Ziller committed
313
    cmd = ActionManager::registerAction(d->m_closeCurrentEditorAction, Constants::CLOSE, editManagerContext, true);
con's avatar
con committed
314
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+W")));
con's avatar
con committed
315
    cmd->setAttribute(Core::Command::CA_UpdateText);
316
    cmd->setDescription(d->m_closeCurrentEditorAction->text());
con's avatar
con committed
317
    mfile->addAction(cmd, Constants::G_FILE_CLOSE);
hjk's avatar
hjk committed
318
    connect(d->m_closeCurrentEditorAction, SIGNAL(triggered()), this, SLOT(closeEditor()));
con's avatar
con committed
319

320
321
322
323
324
325
326
327
    if (Utils::HostOsInfo::isWindowsHost()) {
        // workaround for QTCREATORBUG-72
        QShortcut *sc = new QShortcut(parent);
        cmd = ActionManager::registerShortcut(sc, Constants::CLOSE_ALTERNATIVE, editManagerContext);
        cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+F4")));
        cmd->setDescription(EditorManager::tr("Close"));
        connect(sc, SIGNAL(activated()), this, SLOT(closeEditor()));
    }
328

329
    // Close All Action
Eike Ziller's avatar
Eike Ziller committed
330
    cmd = ActionManager::registerAction(d->m_closeAllEditorsAction, Constants::CLOSEALL, editManagerContext, true);
con's avatar
con committed
331
332
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+W")));
    mfile->addAction(cmd, Constants::G_FILE_CLOSE);
hjk's avatar
hjk committed
333
    connect(d->m_closeAllEditorsAction, SIGNAL(triggered()), this, SLOT(closeAllEditors()));
con's avatar
con committed
334

335
    // Close All Others Action
Eike Ziller's avatar
Eike Ziller committed
336
    cmd = ActionManager::registerAction(d->m_closeOtherEditorsAction, Constants::CLOSEOTHERS, editManagerContext, true);
con's avatar
con committed
337
338
    mfile->addAction(cmd, Constants::G_FILE_CLOSE);
    cmd->setAttribute(Core::Command::CA_UpdateText);
hjk's avatar
hjk committed
339
    connect(d->m_closeOtherEditorsAction, SIGNAL(triggered()), this, SLOT(closeOtherEditors()));
con's avatar
con committed
340

341
342
343
344
345
    //Save XXX Context Actions
    connect(d->m_saveCurrentEditorContextAction, SIGNAL(triggered()), this, SLOT(saveDocumentFromContextMenu()));
    connect(d->m_saveAsCurrentEditorContextAction, SIGNAL(triggered()), this, SLOT(saveDocumentAsFromContextMenu()));
    connect(d->m_revertToSavedCurrentEditorContextAction, SIGNAL(triggered()), this, SLOT(revertToSavedFromContextMenu()));

346
    // Close XXX Context Actions
hjk's avatar
hjk committed
347
348
349
    connect(d->m_closeAllEditorsContextAction, SIGNAL(triggered()), this, SLOT(closeAllEditors()));
    connect(d->m_closeCurrentEditorContextAction, SIGNAL(triggered()), this, SLOT(closeEditorFromContextMenu()));
    connect(d->m_closeOtherEditorsContextAction, SIGNAL(triggered()), this, SLOT(closeOtherEditorsFromContextMenu()));
350

hjk's avatar
hjk committed
351
352
    connect(d->m_openGraphicalShellAction, SIGNAL(triggered()), this, SLOT(showInGraphicalShell()));
    connect(d->m_openTerminalAction, SIGNAL(triggered()), this, SLOT(openTerminal()));
Robert Loehning's avatar
Robert Loehning committed
353

con's avatar
con committed
354
    // Goto Previous In History Action
Eike Ziller's avatar
Eike Ziller committed
355
    cmd = ActionManager::registerAction(d->m_gotoPreviousDocHistoryAction, Constants::GOTOPREVINHISTORY, editDesignContext);
356
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Alt+Tab") : tr("Ctrl+Tab")));
con's avatar
con committed
357
    mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
hjk's avatar
hjk committed
358
    connect(d->m_gotoPreviousDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoPreviousDocHistory()));
con's avatar
con committed
359
360

    // Goto Next In History Action
Eike Ziller's avatar
Eike Ziller committed
361
    cmd = ActionManager::registerAction(d->m_gotoNextDocHistoryAction, Constants::GOTONEXTINHISTORY, editDesignContext);
362
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Alt+Shift+Tab") : tr("Ctrl+Shift+Tab")));
con's avatar
con committed
363
    mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
hjk's avatar
hjk committed
364
    connect(d->m_gotoNextDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoNextDocHistory()));
con's avatar
con committed
365
366

    // Go back in navigation history
Eike Ziller's avatar
Eike Ziller committed
367
    cmd = ActionManager::registerAction(d->m_goBackAction, Constants::GO_BACK, editDesignContext);
368
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Alt+Left") : tr("Alt+Left")));
con's avatar
con committed
369
    mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
hjk's avatar
hjk committed
370
    connect(d->m_goBackAction, SIGNAL(triggered()), this, SLOT(goBackInNavigationHistory()));
con's avatar
con committed
371
372

    // Go forward in navigation history
Eike Ziller's avatar
Eike Ziller committed
373
    cmd = ActionManager::registerAction(d->m_goForwardAction, Constants::GO_FORWARD, editDesignContext);
374
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Alt+Right") : tr("Alt+Right")));
con's avatar
con committed
375
    mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
hjk's avatar
hjk committed
376
    connect(d->m_goForwardAction, SIGNAL(triggered()), this, SLOT(goForwardInNavigationHistory()));
con's avatar
con committed
377

hjk's avatar
hjk committed
378
    d->m_splitAction = new QAction(tr("Split"), this);
Eike Ziller's avatar
Eike Ziller committed
379
    cmd = ActionManager::registerAction(d->m_splitAction, Constants::SPLIT, editManagerContext);
380
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+E,2") : tr("Ctrl+E,2")));
381
    mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
hjk's avatar
hjk committed
382
    connect(d->m_splitAction, SIGNAL(triggered()), this, SLOT(split()));
383

hjk's avatar
hjk committed
384
    d->m_splitSideBySideAction = new QAction(tr("Split Side by Side"), this);
Eike Ziller's avatar
Eike Ziller committed
385
    cmd = ActionManager::registerAction(d->m_splitSideBySideAction, Constants::SPLIT_SIDE_BY_SIDE, editManagerContext);
386
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+E,3") : tr("Ctrl+E,3")));
387
    mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
hjk's avatar
hjk committed
388
    connect(d->m_splitSideBySideAction, SIGNAL(triggered()), this, SLOT(splitSideBySide()));
389

390
    d->m_splitNewWindowAction = new QAction(tr("Open in New Window"), this);
391
392
393
394
395
    cmd = ActionManager::registerAction(d->m_splitNewWindowAction, Constants::SPLIT_NEW_WINDOW, editManagerContext);
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+E,4") : tr("Ctrl+E,4")));
    mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
    connect(d->m_splitNewWindowAction, SIGNAL(triggered()), this, SLOT(splitNewWindow()));

hjk's avatar
hjk committed
396
    d->m_removeCurrentSplitAction = new QAction(tr("Remove Current Split"), this);
Eike Ziller's avatar
Eike Ziller committed
397
    cmd = ActionManager::registerAction(d->m_removeCurrentSplitAction, Constants::REMOVE_CURRENT_SPLIT, editManagerContext);
398
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+E,0") : tr("Ctrl+E,0")));
399
    mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
hjk's avatar
hjk committed
400
    connect(d->m_removeCurrentSplitAction, SIGNAL(triggered()), this, SLOT(removeCurrentSplit()));
401

hjk's avatar
hjk committed
402
    d->m_removeAllSplitsAction = new QAction(tr("Remove All Splits"), this);
Eike Ziller's avatar
Eike Ziller committed
403
    cmd = ActionManager::registerAction(d->m_removeAllSplitsAction, Constants::REMOVE_ALL_SPLITS, editManagerContext);
404
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+E,1") : tr("Ctrl+E,1")));
405
    mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
hjk's avatar
hjk committed
406
    connect(d->m_removeAllSplitsAction, SIGNAL(triggered()), this, SLOT(removeAllSplits()));
407

408
    d->m_gotoNextSplitAction = new QAction(tr("Go to Next Split or Window"), this);
409
    cmd = ActionManager::registerAction(d->m_gotoNextSplitAction, Constants::GOTO_NEXT_SPLIT, editManagerContext);
410
    cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+E,o") : tr("Ctrl+E,o")));
411
    mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
412
    connect(d->m_gotoNextSplitAction, SIGNAL(triggered()), this, SLOT(gotoNextSplit()));
413

Eike Ziller's avatar
Eike Ziller committed
414
415
    ActionContainer *medit = ActionManager::actionContainer(Constants::M_EDIT);
    ActionContainer *advancedMenu = ActionManager::createMenu(Constants::M_EDIT_ADVANCED);
416
    medit->addMenu(advancedMenu, Constants::G_EDIT_ADVANCED);
con's avatar
con committed
417
    advancedMenu->menu()->setTitle(tr("Ad&vanced"));
418
419
    advancedMenu->appendGroup(Constants::G_EDIT_FORMAT);
    advancedMenu->appendGroup(Constants::G_EDIT_COLLAPSING);
mae's avatar
mae committed
420
    advancedMenu->appendGroup(Constants::G_EDIT_BLOCKS);
421
422
423
424
    advancedMenu->appendGroup(Constants::G_EDIT_FONT);
    advancedMenu->appendGroup(Constants::G_EDIT_EDITOR);

    // Advanced menu separators
425
426
427
428
    advancedMenu->addSeparator(editManagerContext, Constants::G_EDIT_COLLAPSING);
    advancedMenu->addSeparator(editManagerContext, Constants::G_EDIT_BLOCKS);
    advancedMenu->addSeparator(editManagerContext, Constants::G_EDIT_FONT);
    advancedMenu->addSeparator(editManagerContext, Constants::G_EDIT_EDITOR);
hjk's avatar
hjk committed
429

con's avatar
con committed
430
    // other setup
431
432
    SplitterOrView *firstRoot = new SplitterOrView();
    d->m_root.append(firstRoot);
433
    d->m_rootContext.append(0);
434
    d->m_currentView = firstRoot->view();
con's avatar
con committed
435

436
437
438
    QHBoxLayout *layout = new QHBoxLayout(this);
    layout->setMargin(0);
    layout->setSpacing(0);
439
    layout->addWidget(firstRoot);
con's avatar
con committed
440
441
442

    updateActions();

hjk's avatar
hjk committed
443
    d->m_windowPopup = new OpenEditorsWindow(this);
444

hjk's avatar
hjk committed
445
446
    d->m_autoSaveTimer = new QTimer(this);
    connect(d->m_autoSaveTimer, SIGNAL(timeout()), SLOT(autoSave()));
447
    updateAutoSave();
con's avatar
con committed
448
449
450
451
}

EditorManager::~EditorManager()
{
452
    m_instance = 0;
hjk's avatar
hjk committed
453
    if (ICore::instance()) {
hjk's avatar
hjk committed
454
        if (d->m_coreListener) {
455
            ExtensionSystem::PluginManager::removeObject(d->m_coreListener);
hjk's avatar
hjk committed
456
            delete d->m_coreListener;
con's avatar
con committed
457
        }
458
        ExtensionSystem::PluginManager::removeObject(d->m_openEditorsFactory);
hjk's avatar
hjk committed
459
        delete d->m_openEditorsFactory;
con's avatar
con committed
460
    }
461
462
463
464
465

    // close all extra windows
    for (int i = 1; i < d->m_root.size(); ++i) {
        SplitterOrView *root = d->m_root.at(i);
        disconnect(root, SIGNAL(destroyed(QObject*)), this, SLOT(rootDestroyed(QObject*)));
466
467
        IContext *rootContext = d->m_rootContext.at(i);
        ICore::removeContextObject(rootContext);
468
        delete root;
469
        delete rootContext;
470
471
    }
    d->m_root.clear();
472
    d->m_rootContext.clear();
473

hjk's avatar
hjk committed
474
    delete d;
con's avatar
con committed
475
476
477
478
}

void EditorManager::init()
{
hjk's avatar
hjk committed
479
    d->m_coreListener = new EditorClosingCoreListener(this);
480
    ExtensionSystem::PluginManager::addObject(d->m_coreListener);
con's avatar
con committed
481

hjk's avatar
hjk committed
482
    d->m_openEditorsFactory = new OpenEditorsViewFactory();
483
    ExtensionSystem::PluginManager::addObject(d->m_openEditorsFactory);
con's avatar
con committed
484

Eike Ziller's avatar
Eike Ziller committed
485
486
    VariableManager::registerFileVariables(kCurrentDocumentPrefix, tr("Current document"));
    VariableManager::registerVariable(kCurrentDocumentXPos,
con's avatar
con committed
487
        tr("X-coordinate of the current editor's upper left corner, relative to screen."));
Eike Ziller's avatar
Eike Ziller committed
488
    VariableManager::registerVariable(kCurrentDocumentYPos,
con's avatar
con committed
489
        tr("Y-coordinate of the current editor's upper left corner, relative to screen."));
Eike Ziller's avatar
Eike Ziller committed
490
    connect(VariableManager::instance(), SIGNAL(variableUpdateRequested(QByteArray)),
hjk's avatar
hjk committed
491
            this, SLOT(updateVariable(QByteArray)));
con's avatar
con committed
492
493
}

494
495
void EditorManager::updateAutoSave()
{
hjk's avatar
hjk committed
496
497
    if (d->m_autoSaveEnabled)
        d->m_autoSaveTimer->start(d->m_autoSaveInterval * (60 * 1000));
498
    else
hjk's avatar
hjk committed
499
        d->m_autoSaveTimer->stop();
500
}
Lasse Holmstedt's avatar
Lasse Holmstedt committed
501

Lasse Holmstedt's avatar
Lasse Holmstedt committed
502
EditorToolBar *EditorManager::createToolBar(QWidget *parent)
Lasse Holmstedt's avatar
Lasse Holmstedt committed
503
{
Lasse Holmstedt's avatar
Lasse Holmstedt committed
504
    return new EditorToolBar(parent);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
505
506
}

mae's avatar
mae committed
507
void EditorManager::removeEditor(IEditor *editor)
con's avatar
con committed
508
{
hjk's avatar
hjk committed
509
510
    bool isDuplicate = d->m_editorModel->isDuplicate(editor);
    d->m_editorModel->removeEditor(editor);
hjk's avatar
hjk committed
511
    if (!isDuplicate)
512
        DocumentManager::removeDocument(editor->document());
hjk's avatar
hjk committed
513
    ICore::removeContextObject(editor);
con's avatar
con committed
514
515
}

516
void EditorManager::handleContextChange(const QList<Core::IContext *> &context)
con's avatar
con committed
517
518
519
{
    if (debugEditorManager)
        qDebug() << Q_FUNC_INFO;
520
    d->m_scheduledCurrentEditor = 0;
521
522
523
524
    IEditor *editor = 0;
    foreach (IContext *c, context)
        if ((editor = qobject_cast<IEditor*>(c)))
            break;
525
526
527
528
529
530
531
532
533
    if (editor && editor != d->m_currentEditor) {
        // Delay actually setting the current editor to after the current event queue has been handled
        // Without doing this, e.g. clicking into projects tree or locator would always open editors
        // in the main window. That is because clicking anywhere in the main window (even over e.g.
        // the locator line edit) first activates the window and sets focus to its focus widget.
        // Only afterwards the focus is shifted to the widget that received the click.
        d->m_scheduledCurrentEditor = editor;
        QTimer::singleShot(0, this, SLOT(setCurrentEditorFromContextChange()));
    } else {
534
        updateActions();
535
    }
536
537
}

con's avatar
con committed
538
539
void EditorManager::setCurrentEditor(IEditor *editor, bool ignoreNavigationHistory)
{
540
541
542
    if (editor)
        setCurrentView(0);

hjk's avatar
hjk committed
543
    if (d->m_currentEditor == editor)
con's avatar
con committed
544
        return;
hjk's avatar
hjk committed
545
    if (d->m_currentEditor && !ignoreNavigationHistory)
546
        addCurrentPositionToNavigationHistory();
mae's avatar
mae committed
547

hjk's avatar
hjk committed
548
    d->m_currentEditor = editor;
con's avatar
con committed
549
    if (editor) {
550
551
        if (EditorView *view = viewForEditor(editor))
            view->setCurrentEditor(editor);
552
553
        // update global history
        EditorView::updateEditorHistory(editor, d->m_globalHistory);
con's avatar
con committed
554
    }
mae's avatar
mae committed
555
    updateActions();
556
    updateWindowTitle();
mae's avatar
mae committed
557
    emit currentEditorChanged(editor);
con's avatar
con committed
558
559
}

mae's avatar
mae committed
560

561
void EditorManager::setCurrentView(Internal::EditorView *view)
mae's avatar
mae committed
562
{
hjk's avatar
hjk committed
563
    if (view == d->m_currentView)
mae's avatar
mae committed
564
565
        return;

566
    EditorView *old = d->m_currentView;
hjk's avatar
hjk committed
567
    d->m_currentView = view;
mae's avatar
mae committed
568
569
570
571
572

    if (old)
        old->update();
    if (view)
        view->update();
573

574
    if (view && !view->currentEditor()) {
575
        view->setFocus();
576
        ICore::raiseWindow(view);
577
    }
mae's avatar
mae committed
578
579
}

580
Internal::EditorView *EditorManager::currentEditorView() const
mae's avatar
mae committed
581
{
582
    EditorView *view = d->m_currentView;
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
    if (!view) {
        if (d->m_currentEditor) {
            view = viewForEditor(d->m_currentEditor);
            QTC_ASSERT(view, view = d->m_root.first()->findFirstView());
        }
        QTC_CHECK(view);
        if (!view) { // should not happen, we should always have either currentview or currentdocument
            foreach (SplitterOrView *root, d->m_root) {
                if (root->window()->isActiveWindow()) {
                    view = root->findFirstView();
                    break;
                }
            }
            QTC_ASSERT(view, view = d->m_root.first()->findFirstView());
        }
    }
599
    return view;
mae's avatar
mae committed
600
601
}

602
603
604
605
606
607
608
609
610
611
612
EditorView *EditorManager::viewForEditor(IEditor *editor)
{
    QWidget *w = editor->widget();
    while (w) {
        w = w->parentWidget();
        if (EditorView *view = qobject_cast<EditorView *>(w))
            return view;
    }
    return 0;
}

613
SplitterOrView *EditorManager::findRoot(const EditorView *view, int *rootIndex)
614
615
{
    SplitterOrView *current = view->parentSplitterOrView();
616
    while (current) {
617
        int index = d->m_root.indexOf(current);
618
619
620
621
622
        if (index >= 0) {
            if (rootIndex)
                *rootIndex = index;
            return current;
        }
623
624
        current = current->findParentSplitter();
    }
625
626
    QTC_CHECK(false); // we should never have views without a root
    return 0;
627
628
}

con's avatar
con committed
629
630
631
QList<IEditor *> EditorManager::editorsForFileName(const QString &filename) const
{
    QList<IEditor *> found;
632
    QString fixedname = DocumentManager::fixFileName(filename, DocumentManager::KeepLinks);
con's avatar
con committed
633
    foreach (IEditor *editor, openedEditors()) {
634
        if (fixedname == DocumentManager::fixFileName(editor->document()->fileName(), DocumentManager::KeepLinks))
con's avatar
con committed
635
636
637
638
639
            found << editor;
    }
    return found;
}

640
QList<IEditor *> EditorManager::editorsForDocument(IDocument *document) const
641
642
643
{
    QList<IEditor *> found;
    foreach (IEditor *editor, openedEditors()) {
644
        if (editor->document() == document)
645
646
647
648
649
            found << editor;
    }
    return found;
}

hjk's avatar
hjk committed
650
IEditor *EditorManager::currentEditor()
con's avatar
con committed
651
{
652
    return d->m_currentEditor;
con's avatar
con committed
653
654
}

mae's avatar
mae committed
655
656
657
658
659
660
661
void EditorManager::emptyView(Core::Internal::EditorView *view)
{
    if (!view)
        return;

    QList<IEditor *> editors = view->editors();
    foreach (IEditor *editor, editors) {
hjk's avatar
hjk committed
662
        if (!d->m_editorModel->isDuplicate(editor)) {
663
664
665
666
667
668
669
670
671
672
673
674
675
676
            QList<IEditor *> duplicates = d->m_editorModel->duplicatesFor(editor);
            if (!duplicates.isEmpty()) {
                d->m_editorModel->makeOriginal(duplicates.first());
            } else {
                // it's the only editor for that file and it's not a duplicate,
                // so we need to keep it around (--> in the editor model)
                if (currentEditor() == editor) {
                    // we don't want a current editor that is not open in a view
                    setCurrentEditor(0);
                }
                editors.removeAll(editor);
                view->removeEditor(editor);
                continue; // don't close the editor
            }
mae's avatar
mae committed
677
678
679
680
681
        }
        emit editorAboutToClose(editor);
        removeEditor(editor);
        view->removeEditor(editor);
    }
682
683
684
685
686
    if (!editors.isEmpty()) {
        emit editorsClosed(editors);
        foreach (IEditor *editor, editors) {
            delete editor;
        }
mae's avatar
mae committed
687
688
689
    }
}

690
691
692
693
694
695
696
697
698
699
700
701
702
void EditorManager::splitNewWindow(Internal::EditorView *view)
{
    SplitterOrView *splitter;
    IEditor *editor = view->currentEditor();
    IEditor *newEditor = 0;
    if (editor && editor->duplicateSupported())
        newEditor = m_instance->duplicateEditor(editor);
    else
        newEditor = editor; // move to the new view
    splitter = new SplitterOrView;
    splitter->setAttribute(Qt::WA_DeleteOnClose);
    splitter->setAttribute(Qt::WA_QuitOnClose, false); // don't prevent Qt Creator from closing
    splitter->resize(QSize(800, 600));
703
704
705
706
    IContext *context = new IContext;
    context->setContext(Context(Constants::C_EDITORMANAGER));
    context->setWidget(splitter);
    ICore::addContextObject(context);
707
708
    d->m_root.append(splitter);
    d->m_rootContext.append(context);
Eike Ziller's avatar
Eike Ziller committed
709
    connect(splitter, SIGNAL(destroyed(QObject*)), m_instance, SLOT(rootDestroyed(QObject*)));
710
711
712
713
714
715
716
717
718
    splitter->show();
    ICore::raiseWindow(splitter);
    if (newEditor)
        m_instance->activateEditor(splitter->view(), newEditor, IgnoreNavigationHistory);
    else
        splitter->view()->setFocus();
    m_instance->updateActions();
}

mae's avatar
mae committed
719
void EditorManager::closeView(Core::Internal::EditorView *view)
con's avatar
con committed
720
{
mae's avatar
mae committed
721
    if (!view)
con's avatar
con committed
722
        return;
mae's avatar
mae committed
723

mae's avatar
mae committed
724
725
    emptyView(view);

726
    SplitterOrView *splitterOrView = view->parentSplitterOrView();
727
    Q_ASSERT(splitterOrView);
mae's avatar
mae committed
728
    Q_ASSERT(splitterOrView->view() == view);
729
    SplitterOrView *splitter = splitterOrView->findParentSplitter();
mae's avatar
mae committed
730
    Q_ASSERT(splitterOrView->hasEditors() == false);
731
    splitterOrView->hide();
mae's avatar
mae committed
732
733
734
735
    delete splitterOrView;

    splitter->unsplit();

736
    EditorView *newCurrent = splitter->findFirstView();
mae's avatar
mae committed
737
    if (newCurrent) {
738
739
        if (IEditor *e = newCurrent->currentEditor())
            activateEditor(newCurrent, e);
740
        else
mae's avatar
mae committed
741
            setCurrentView(newCurrent);
mae's avatar
mae committed
742
    }
mae's avatar
mae committed
743
}
mae's avatar
mae committed
744

con's avatar
con committed
745
QList<IEditor*>
746
    EditorManager::editorsForDocuments(QList<IDocument*> documents) const
con's avatar
con committed
747
748
749
{
    const QList<IEditor *> editors = openedEditors();
    QSet<IEditor *> found;
750
    foreach (IDocument *document, documents) {
con's avatar
con committed
751
        foreach (IEditor *editor, editors) {
752
            if (editor->document() == document && !found.contains(editor))
con's avatar
con committed
753
754
755
756
757
758
                    found << editor;
        }
    }
    return found.toList();
}

759
QList<IDocument *> EditorManager::documentsForEditors(QList<IEditor *> editors) const
con's avatar
con committed
760
761
{
    QSet<IEditor *> handledEditors;
762
    QList<IDocument *> documents;
con's avatar
con committed
763
764
    foreach (IEditor *editor, editors) {
        if (!handledEditors.contains(editor)) {
765
            documents << editor->document();
766
            handledEditors.insert(editor);
con's avatar
con committed
767
768
        }
    }
769
    return documents;
con's avatar
con committed
770
771
772
773
}

bool EditorManager::closeAllEditors(bool askAboutModifiedEditors)
{
hjk's avatar
hjk committed
774
    d->m_editorModel->removeAllRestoredEditors();
775
    if (closeEditors(openedEditors(), askAboutModifiedEditors)) {
hjk's avatar
hjk committed
776
//        d->clearNavigationHistory();
777
778
779
        return true;
    }
    return false;
con's avatar
con committed
780
781
}

782
void EditorManager::closeOtherEditors(IEditor *editor)
con's avatar
con committed
783
{
hjk's avatar
hjk committed
784
    d->m_editorModel->removeAllRestoredEditors();
con's avatar
con committed
785
    QList<IEditor*> editors = openedEditors();
786
    editors.removeAll(editor);
con's avatar
con committed
787
788
789
    closeEditors(editors, true);
}

790
791
792
793
794
795
796
void EditorManager::closeOtherEditors()
{
    IEditor *current = currentEditor();
    QTC_ASSERT(current, return);
    closeOtherEditors(current);
}

797
798
799
// SLOT connected to action
void EditorManager::closeEditor()
{
hjk's avatar
hjk committed
800
    if (!d->m_currentEditor)
801
        return;
802
    addCurrentPositionToNavigationHistory();
hjk's avatar
hjk committed
803
    closeEditor(d->m_currentEditor);
804
805
}

806
807
808
809
810
811
static void assignAction(QAction *self, QAction *other)
{
    self->setText(other->text());
    self->setIcon(other->icon());
    self->setShortcut(other->shortcut());
    self->setEnabled(other->isEnabled());
812
    self->setIconVisibleInMenu(other->isIconVisibleInMenu());
813
814
815
}

void EditorManager::addSaveAndCloseEditorActions(QMenu *contextMenu, const QModelIndex &editorIndex)
816
817
{
    QTC_ASSERT(contextMenu, return);
hjk's avatar
hjk committed
818
    d->m_contextMenuEditorIndex = editorIndex;
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837

    assignAction(d->m_saveCurrentEditorContextAction, ActionManager::command(Constants::SAVE)->action());
    assignAction(d->m_saveAsCurrentEditorContextAction, ActionManager::command(Constants::SAVEAS)->action());
    assignAction(d->m_revertToSavedCurrentEditorContextAction, ActionManager::command(Constants::REVERTTOSAVED)->action());

    IEditor *editor = d->m_contextMenuEditorIndex.data(Qt::UserRole).value<Core::IEditor*>();

    setupSaveActions(editor,
                     d->m_saveCurrentEditorContextAction,
                     d->m_saveAsCurrentEditorContextAction,
                     d->m_revertToSavedCurrentEditorContextAction);

    contextMenu->addAction(d->m_saveCurrentEditorContextAction);
    contextMenu->addAction(d->m_saveAsCurrentEditorContextAction);
    contextMenu->addAction(ActionManager::command(Constants::SAVEALL)->action());
    contextMenu->addAction(d->m_revertToSavedCurrentEditorContextAction);

    contextMenu->addSeparator();

hjk's avatar
hjk committed
838
    d->m_closeCurrentEditorContextAction->setText(editorIndex.isValid()
839
840
                                                    ? tr("Close \"%1\"").arg(editorIndex.data().toString())
                                                    : tr("Close Editor"));
hjk's avatar
hjk committed
841
    d->m_closeOtherEditorsContextAction->setText(editorIndex.isValid()
842
843
                                                   ? tr("Close All Except \"%1\"").arg(editorIndex.data().toString())
                                                   : tr("Close Other Editors"));
hjk's avatar
hjk committed
844
845
846
847
848
849
    d->m_closeCurrentEditorContextAction->setEnabled(editorIndex.isValid());
    d->m_closeOtherEditorsContextAction->setEnabled(editorIndex.isValid());
    d->m_closeAllEditorsContextAction->setEnabled(!openedEditors().isEmpty());
    contextMenu->addAction(d->m_closeCurrentEditorContextAction);
    contextMenu->addAction(d->m_closeAllEditorsContextAction);
    contextMenu->addAction(d->m_closeOtherEditorsContextAction);
850
851
}

Robert Loehning's avatar
Robert Loehning committed
852
853
854
void EditorManager::addNativeDirActions(QMenu *contextMenu, const QModelIndex &editorIndex)
{
    QTC_ASSERT(contextMenu, return);
hjk's avatar
hjk committed
855
856
857
858
    d->m_openGraphicalShellAction->setEnabled(editorIndex.isValid());
    d->m_openTerminalAction->setEnabled(editorIndex.isValid());
    contextMenu->addAction(d->m_openGraphicalShellAction);
    contextMenu->addAction(d->m_openTerminalAction);
Robert Loehning's avatar
Robert Loehning committed
859
860
}

861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885