editormanager.cpp 67.4 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2
3
4
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
hjk's avatar
hjk committed
7
** Contact: Nokia Corporation (info@qt.nokia.com)
con's avatar
con committed
8
**
9
**
10
** GNU Lesser General Public License Usage
11
**
hjk's avatar
hjk committed
12
13
14
15
16
17
** 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.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21
22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23
24
25
26
27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28
** If you have questions regarding the use of this file, please contact
Tobias Hunger's avatar
Tobias Hunger committed
29
** Nokia at info@qt.nokia.com.
con's avatar
con committed
30
**
31
**************************************************************************/
hjk's avatar
hjk committed
32

con's avatar
con committed
33
#include "editormanager.h"
34
#include "editorview.h"
con's avatar
con committed
35
#include "openeditorswindow.h"
mae's avatar
mae committed
36
#include "openeditorsview.h"
37
#include "openeditorsmodel.h"
con's avatar
con committed
38
39
#include "openwithdialog.h"
#include "filemanager.h"
40
#include "icore.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
41
#include "ieditor.h"
con's avatar
con committed
42
43
#include "iversioncontrol.h"
#include "mimedatabase.h"
44
45
#include "tabpositionindicator.h"
#include "vcsmanager.h"
con's avatar
con committed
46

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

61
62
#include <extensionsystem/pluginmanager.h>

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

#include <QtCore/QDebug>
con's avatar
con committed
67
68
69
#include <QtCore/QFileInfo>
#include <QtCore/QMap>
#include <QtCore/QProcess>
hjk's avatar
hjk committed
70
71
#include <QtCore/QSet>
#include <QtCore/QSettings>
72
#include <QtCore/QTextCodec>
con's avatar
con committed
73
74

#include <QtGui/QAction>
75
#include <QtGui/QShortcut>
con's avatar
con committed
76
77
#include <QtGui/QApplication>
#include <QtGui/QFileDialog>
hjk's avatar
hjk committed
78
#include <QtGui/QLayout>
79
#include <QtGui/QMainWindow>
con's avatar
con committed
80
81
82
#include <QtGui/QMenu>
#include <QtGui/QMessageBox>
#include <QtGui/QPushButton>
hjk's avatar
hjk committed
83
#include <QtGui/QSplitter>
84
#include <QtGui/QStackedLayout>
con's avatar
con committed
85
86
87

enum { debugEditorManager=0 };

Friedemann Kleint's avatar
Friedemann Kleint committed
88
89
90
91
static const char kCurrentDocumentFilePath[] = "CurrentDocument:FilePath";
static const char kCurrentDocumentPath[] = "CurrentDocument:Path";
static const char kCurrentDocumentXPos[] = "CurrentDocument:XPos";
static const char kCurrentDocumentYPos[] = "CurrentDocument:YPos";
con's avatar
con committed
92

93
94
95
96
97
static inline ExtensionSystem::PluginManager *pluginManager()
{
    return ExtensionSystem::PluginManager::instance();
}

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
//===================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
138
139
140
141
142
143
144
145
146
147
148
//===================EditorManager=====================

EditorManagerPlaceHolder *EditorManagerPlaceHolder::m_current = 0;

EditorManagerPlaceHolder::EditorManagerPlaceHolder(Core::IMode *mode, QWidget *parent)
    : QWidget(parent), m_mode(mode)
{
    setLayout(new QVBoxLayout);
    layout()->setMargin(0);
    connect(Core::ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode *)),
            this, SLOT(currentModeChanged(Core::IMode *)));
149
150

    currentModeChanged(Core::ModeManager::instance()->currentMode());
con's avatar
con committed
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
}

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

void EditorManagerPlaceHolder::currentModeChanged(Core::IMode *mode)
{
    if (m_current == this) {
        m_current = 0;
        EditorManager::instance()->setParent(0);
        EditorManager::instance()->hide();
    }
    if (m_mode == mode) {
        m_current = this;
        layout()->addWidget(EditorManager::instance());
        EditorManager::instance()->show();
    }
}

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

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

182
namespace Core {
183
184


185
struct EditorManagerPrivate {
con's avatar
con committed
186
187
    explicit EditorManagerPrivate(ICore *core, QWidget *parent);
    ~EditorManagerPrivate();
188
    Internal::EditorView *m_view;
mae's avatar
mae committed
189
    Internal::SplitterOrView *m_splitter;
mae's avatar
mae committed
190
    QPointer<IEditor> m_currentEditor;
mae's avatar
mae committed
191
    QPointer<SplitterOrView> m_currentView;
192

con's avatar
con committed
193
194
195
196
197
198
199
200
201
    ICore *m_core;


    // actions
    QAction *m_revertToSavedAction;
    QAction *m_saveAction;
    QAction *m_saveAsAction;
    QAction *m_closeCurrentEditorAction;
    QAction *m_closeAllEditorsAction;
con's avatar
con committed
202
    QAction *m_closeOtherEditorsAction;
con's avatar
con committed
203
204
205
206
    QAction *m_gotoNextDocHistoryAction;
    QAction *m_gotoPreviousDocHistoryAction;
    QAction *m_goBackAction;
    QAction *m_goForwardAction;
207
208
    QAction *m_splitAction;
    QAction *m_splitSideBySideAction;
209
210
211
    QAction *m_removeCurrentSplitAction;
    QAction *m_removeAllSplitsAction;
    QAction *m_gotoOtherSplitAction;
con's avatar
con committed
212
213
214
215
216
217
218

    Internal::OpenEditorsWindow *m_windowPopup;
    Internal::EditorClosingCoreListener *m_coreListener;

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

219
    OpenEditorsModel *m_editorModel;
220

221
    IFile::ReloadSetting m_reloadSetting;
222
223

    QString m_titleAddition;
con's avatar
con committed
224
};
225
}
con's avatar
con committed
226
227

EditorManagerPrivate::EditorManagerPrivate(ICore *core, QWidget *parent) :
228
    m_view(0),
229
    m_splitter(0),
con's avatar
con committed
230
231
232
233
234
235
    m_core(core),
    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
236
    m_closeOtherEditorsAction(new QAction(EditorManager::tr("Close Others"), parent)),
mae's avatar
mae committed
237
238
    m_gotoNextDocHistoryAction(new QAction(EditorManager::tr("Next Open Document in History"), parent)),
    m_gotoPreviousDocHistoryAction(new QAction(EditorManager::tr("Previous Open Document in History"), parent)),
239
240
    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)),
con's avatar
con committed
241
    m_windowPopup(0),
242
    m_coreListener(0),
243
    m_reloadSetting(IFile::AlwaysAsk)
con's avatar
con committed
244
{
245
    m_editorModel = new OpenEditorsModel(parent);
con's avatar
con committed
246
247
248
249
}

EditorManagerPrivate::~EditorManagerPrivate()
{
250
//    clearNavigationHistory();
con's avatar
con committed
251
252
253
254
}

EditorManager *EditorManager::m_instance = 0;

255
256
static Command *createSeparator(ActionManager *am, QObject *parent,
                                const QString &name,
257
                                const Context &context)
258
259
260
261
262
263
264
{
    QAction *tmpaction = new QAction(parent);
    tmpaction->setSeparator(true);
    Command *cmd = am->registerAction(tmpaction, name, context);
    return cmd;
}

con's avatar
con committed
265
266
267
268
269
270
271
EditorManager::EditorManager(ICore *core, QWidget *parent) :
    QWidget(parent),
    m_d(new EditorManagerPrivate(core, parent))
{
    m_instance = this;

    connect(m_d->m_core, SIGNAL(contextAboutToChange(Core::IContext *)),
mae's avatar
mae committed
272
            this, SLOT(handleContextChange(Core::IContext *)));
con's avatar
con committed
273

274
    const Context editManagerContext(Constants::C_EDITORMANAGER);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
275
    // combined context for edit & design modes
276
    const Context editDesignContext(Constants::C_EDITORMANAGER, Constants::C_DESIGN_MODE);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
277

278
    ActionManager *am = m_d->m_core->actionManager();
279
    ActionContainer *mfile = am->actionContainer(Constants::M_FILE);
con's avatar
con committed
280

281
    // Revert to saved
282
    m_d->m_revertToSavedAction->setIcon(QIcon::fromTheme(QLatin1String("document-revert")));
con's avatar
con committed
283
    Command *cmd = am->registerAction(m_d->m_revertToSavedAction,
con's avatar
con committed
284
                                       Constants::REVERTTOSAVED, editManagerContext);
con's avatar
con committed
285
    cmd->setAttribute(Command::CA_UpdateText);
con's avatar
con committed
286
287
288
289
    cmd->setDefaultText(tr("Revert File to Saved"));
    mfile->addAction(cmd, Constants::G_FILE_SAVE);
    connect(m_d->m_revertToSavedAction, SIGNAL(triggered()), this, SLOT(revertToSaved()));

290
    // Save Action
con's avatar
con committed
291
292
293
    am->registerAction(m_d->m_saveAction, Constants::SAVE, editManagerContext);
    connect(m_d->m_saveAction, SIGNAL(triggered()), this, SLOT(saveFile()));

294
    // Save As Action
con's avatar
con committed
295
296
297
    am->registerAction(m_d->m_saveAsAction, Constants::SAVEAS, editManagerContext);
    connect(m_d->m_saveAsAction, SIGNAL(triggered()), this, SLOT(saveFileAs()));

298
    // Window Menu
299
    ActionContainer *mwindow = am->actionContainer(Constants::M_WINDOW);
con's avatar
con committed
300

301
    // Window menu separators
con's avatar
con committed
302
303
    QAction *tmpaction = new QAction(this);
    tmpaction->setSeparator(true);
hjk's avatar
hjk committed
304
    cmd = am->registerAction(tmpaction, "QtCreator.Window.Sep.Split", editManagerContext);
con's avatar
con committed
305
306
307
308
    mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);

    tmpaction = new QAction(this);
    tmpaction->setSeparator(true);
hjk's avatar
hjk committed
309
    cmd = am->registerAction(tmpaction, "QtCreator.Window.Sep.Navigate", editManagerContext);
con's avatar
con committed
310
311
    mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);

312
    // Close Action
313
    cmd = am->registerAction(m_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);
con's avatar
con committed
316
317
318
319
    cmd->setDefaultText(m_d->m_closeCurrentEditorAction->text());
    mfile->addAction(cmd, Constants::G_FILE_CLOSE);
    connect(m_d->m_closeCurrentEditorAction, SIGNAL(triggered()), this, SLOT(closeEditor()));

320
321
322
323
324
325
326
327
328
#ifdef Q_WS_WIN
    // workaround for QTCREATORBUG-72
    QShortcut *sc = new QShortcut(parent);
    cmd = am->registerShortcut(sc, Constants::CLOSE_ALTERNATIVE, editManagerContext);
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+F4")));
    cmd->setDefaultText(EditorManager::tr("Close"));
    connect(sc, SIGNAL(activated()), this, SLOT(closeEditor()));
#endif

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

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

con's avatar
con committed
341
    // Goto Previous In History Action
Lasse Holmstedt's avatar
Lasse Holmstedt committed
342
    cmd = am->registerAction(m_d->m_gotoPreviousDocHistoryAction, Constants::GOTOPREVINHISTORY, editDesignContext);
con's avatar
con committed
343
344
345
346
347
348
349
350
351
#ifdef Q_WS_MAC
    cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Tab")));
#else
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Tab")));
#endif
    mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
    connect(m_d->m_gotoPreviousDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoPreviousDocHistory()));

    // Goto Next In History Action
Lasse Holmstedt's avatar
Lasse Holmstedt committed
352
    cmd = am->registerAction(m_d->m_gotoNextDocHistoryAction, Constants::GOTONEXTINHISTORY, editDesignContext);
con's avatar
con committed
353
354
355
356
357
358
359
360
361
#ifdef Q_WS_MAC
    cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Shift+Tab")));
#else
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+Tab")));
#endif
    mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
    connect(m_d->m_gotoNextDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoNextDocHistory()));

    // Go back in navigation history
Lasse Holmstedt's avatar
Lasse Holmstedt committed
362
    cmd = am->registerAction(m_d->m_goBackAction, Constants::GO_BACK, editDesignContext);
con's avatar
con committed
363
364
365
366
367
368
369
370
371
#ifdef Q_WS_MAC
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Left")));
#else
    cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Left")));
#endif
    mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
    connect(m_d->m_goBackAction, SIGNAL(triggered()), this, SLOT(goBackInNavigationHistory()));

    // Go forward in navigation history
Lasse Holmstedt's avatar
Lasse Holmstedt committed
372
    cmd = am->registerAction(m_d->m_goForwardAction, Constants::GO_FORWARD, editDesignContext);
con's avatar
con committed
373
374
375
376
377
378
379
380
#ifdef Q_WS_MAC
    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Right")));
#else
    cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Right")));
#endif
    mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
    connect(m_d->m_goForwardAction, SIGNAL(triggered()), this, SLOT(goForwardInNavigationHistory()));

con's avatar
con committed
381
382
383
384
385
386
#ifdef Q_WS_MAC
    QString prefix = tr("Meta+E");
#else
    QString prefix = tr("Ctrl+E");
#endif

387
388
    m_d->m_splitAction = new QAction(tr("Split"), this);
    cmd = am->registerAction(m_d->m_splitAction, Constants::SPLIT, editManagerContext);
con's avatar
con committed
389
    cmd->setDefaultKeySequence(QKeySequence(tr("%1,2").arg(prefix)));
390
391
392
393
394
    mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
    connect(m_d->m_splitAction, SIGNAL(triggered()), this, SLOT(split()));

    m_d->m_splitSideBySideAction = new QAction(tr("Split Side by Side"), this);
    cmd = am->registerAction(m_d->m_splitSideBySideAction, Constants::SPLIT_SIDE_BY_SIDE, editManagerContext);
con's avatar
con committed
395
    cmd->setDefaultKeySequence(QKeySequence(tr("%1,3").arg(prefix)));
396
397
398
    mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
    connect(m_d->m_splitSideBySideAction, SIGNAL(triggered()), this, SLOT(splitSideBySide()));

399
400
    m_d->m_removeCurrentSplitAction = new QAction(tr("Remove Current Split"), this);
    cmd = am->registerAction(m_d->m_removeCurrentSplitAction, Constants::REMOVE_CURRENT_SPLIT, editManagerContext);
con's avatar
con committed
401
    cmd->setDefaultKeySequence(QKeySequence(tr("%1,0").arg(prefix)));
402
    mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
403
    connect(m_d->m_removeCurrentSplitAction, SIGNAL(triggered()), this, SLOT(removeCurrentSplit()));
404

405
406
    m_d->m_removeAllSplitsAction = new QAction(tr("Remove All Splits"), this);
    cmd = am->registerAction(m_d->m_removeAllSplitsAction, Constants::REMOVE_ALL_SPLITS, editManagerContext);
con's avatar
con committed
407
    cmd->setDefaultKeySequence(QKeySequence(tr("%1,1").arg(prefix)));
408
    mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
409
    connect(m_d->m_removeAllSplitsAction, SIGNAL(triggered()), this, SLOT(removeAllSplits()));
410

con's avatar
con committed
411
    m_d->m_gotoOtherSplitAction = new QAction(tr("Go to Next Split"), this);
412
    cmd = am->registerAction(m_d->m_gotoOtherSplitAction, Constants::GOTO_OTHER_SPLIT, editManagerContext);
con's avatar
con committed
413
    cmd->setDefaultKeySequence(QKeySequence(tr("%1,o").arg(prefix)));
414
    mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
415
    connect(m_d->m_gotoOtherSplitAction, SIGNAL(triggered()), this, SLOT(gotoOtherSplit()));
416

417
418
    ActionContainer *medit = am->actionContainer(Constants::M_EDIT);
    ActionContainer *advancedMenu = am->createMenu(Constants::M_EDIT_ADVANCED);
419
    medit->addMenu(advancedMenu, Constants::G_EDIT_ADVANCED);
con's avatar
con committed
420
    advancedMenu->menu()->setTitle(tr("Ad&vanced"));
421
422
    advancedMenu->appendGroup(Constants::G_EDIT_FORMAT);
    advancedMenu->appendGroup(Constants::G_EDIT_COLLAPSING);
mae's avatar
mae committed
423
    advancedMenu->appendGroup(Constants::G_EDIT_BLOCKS);
424
425
426
427
428
429
    advancedMenu->appendGroup(Constants::G_EDIT_FONT);
    advancedMenu->appendGroup(Constants::G_EDIT_EDITOR);

    // Advanced menu separators
    cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Collapsing"), editManagerContext);
    advancedMenu->addAction(cmd, Constants::G_EDIT_COLLAPSING);
mae's avatar
mae committed
430
431
    cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Blocks"), editManagerContext);
    advancedMenu->addAction(cmd, Constants::G_EDIT_BLOCKS);
432
433
434
435
    cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Font"), editManagerContext);
    advancedMenu->addAction(cmd, Constants::G_EDIT_FONT);
    cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Editor"), editManagerContext);
    advancedMenu->addAction(cmd, Constants::G_EDIT_EDITOR);
hjk's avatar
hjk committed
436

con's avatar
con committed
437
    // other setup
mae's avatar
mae committed
438
439
440
    m_d->m_splitter = new SplitterOrView(m_d->m_editorModel);
    m_d->m_view = m_d->m_splitter->view();

con's avatar
con committed
441

442
443
444
445
    QHBoxLayout *layout = new QHBoxLayout(this);
    layout->setMargin(0);
    layout->setSpacing(0);
    layout->addWidget(m_d->m_splitter);
con's avatar
con committed
446
447
448
449
450
451
452
453

    updateActions();

    m_d->m_windowPopup = new OpenEditorsWindow(this);
}

EditorManager::~EditorManager()
{
454
    m_instance = 0;
con's avatar
con committed
455
    if (m_d->m_core) {
456
        ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
con's avatar
con committed
457
        if (m_d->m_coreListener) {
458
            pm->removeObject(m_d->m_coreListener);
con's avatar
con committed
459
460
            delete m_d->m_coreListener;
        }
461
        pm->removeObject(m_d->m_openEditorsFactory);
con's avatar
con committed
462
463
464
465
466
467
468
469
        delete m_d->m_openEditorsFactory;
    }
    delete m_d;
}

void EditorManager::init()
{
    m_d->m_coreListener = new EditorClosingCoreListener(this);
470
    pluginManager()->addObject(m_d->m_coreListener);
con's avatar
con committed
471
472

    m_d->m_openEditorsFactory = new OpenEditorsViewFactory();
473
    pluginManager()->addObject(m_d->m_openEditorsFactory);
con's avatar
con committed
474

con's avatar
con committed
475
476
477
478
479
480
481
482
483
484
    VariableManager *vm = VariableManager::instance();
    vm->registerVariable(QLatin1String(kCurrentDocumentFilePath),
        tr("Full path of the current document including file name."));
    vm->registerVariable(QLatin1String(kCurrentDocumentPath),
        tr("Full path of the current document excluding file name."));
    vm->registerVariable(QLatin1String(kCurrentDocumentXPos),
        tr("X-coordinate of the current editor's upper left corner, relative to screen."));
    vm->registerVariable(QLatin1String(kCurrentDocumentYPos),
        tr("Y-coordinate of the current editor's upper left corner, relative to screen."));
    connect(vm, SIGNAL(variableUpdateRequested(QString)),
con's avatar
con committed
485
            this, SLOT(updateVariable(QString)));
con's avatar
con committed
486
487
}

Lasse Holmstedt's avatar
Lasse Holmstedt committed
488

Lasse Holmstedt's avatar
Lasse Holmstedt committed
489
EditorToolBar *EditorManager::createToolBar(QWidget *parent)
Lasse Holmstedt's avatar
Lasse Holmstedt committed
490
{
Lasse Holmstedt's avatar
Lasse Holmstedt committed
491
    return new EditorToolBar(parent);
Lasse Holmstedt's avatar
Lasse Holmstedt committed
492
493
}

mae's avatar
mae committed
494
void EditorManager::removeEditor(IEditor *editor)
con's avatar
con committed
495
{
mae's avatar
mae committed
496
    bool isDuplicate = m_d->m_editorModel->isDuplicate(editor);
mae's avatar
mae committed
497
    m_d->m_editorModel->removeEditor(editor);
mae's avatar
mae committed
498
499
500
    if (!isDuplicate) {
        m_d->m_core->fileManager()->removeFile(editor->file());
    }
mae's avatar
mae committed
501
    m_d->m_core->removeContextObject(editor);
con's avatar
con committed
502
503
}

504
void EditorManager::handleContextChange(Core::IContext *context)
con's avatar
con committed
505
506
507
508
{
    if (debugEditorManager)
        qDebug() << Q_FUNC_INFO;
    IEditor *editor = context ? qobject_cast<IEditor*>(context) : 0;
509
510
511
512
513
    if (editor) {
        setCurrentEditor(editor);
    } else {
        updateActions();
    }
514
515
}

con's avatar
con committed
516
517
void EditorManager::setCurrentEditor(IEditor *editor, bool ignoreNavigationHistory)
{
518
519
520
    if (editor)
        setCurrentView(0);

mae's avatar
mae committed
521
    if (m_d->m_currentEditor == editor)
con's avatar
con committed
522
        return;
523
524
    if (m_d->m_currentEditor && !ignoreNavigationHistory)
        addCurrentPositionToNavigationHistory();
mae's avatar
mae committed
525

mae's avatar
mae committed
526
    m_d->m_currentEditor = editor;
con's avatar
con committed
527
    if (editor) {
528
529
        if (SplitterOrView *splitterOrView = m_d->m_splitter->findView(editor))
            splitterOrView->view()->setCurrentEditor(editor);
mae's avatar
mae committed
530
        m_d->m_view->updateEditorHistory(editor); // the global view should have a complete history
con's avatar
con committed
531
    }
mae's avatar
mae committed
532
    updateActions();
533
    updateWindowTitle();
mae's avatar
mae committed
534
    emit currentEditorChanged(editor);
con's avatar
con committed
535
536
}

mae's avatar
mae committed
537
538
539
540
541
542
543
544
545
546
547
548
549

void EditorManager::setCurrentView(Core::Internal::SplitterOrView *view)
{
    if (view == m_d->m_currentView)
        return;

    SplitterOrView *old = m_d->m_currentView;
    m_d->m_currentView = view;

    if (old)
        old->update();
    if (view)
        view->update();
550
551
552

    if (view && !view->editor())
        view->setFocus();
mae's avatar
mae committed
553
554
}

mae's avatar
mae committed
555
Core::Internal::SplitterOrView *EditorManager::currentSplitterOrView() const
mae's avatar
mae committed
556
{
557
558
    SplitterOrView *view = m_d->m_currentView;
    if (!view)
559
560
561
        view = m_d->m_currentEditor?
               m_d->m_splitter->findView(m_d->m_currentEditor):
               m_d->m_splitter->findFirstView();
mae's avatar
mae committed
562
563
    if (!view)
        return m_d->m_splitter;
564
    return view;
mae's avatar
mae committed
565
566
}

mae's avatar
mae committed
567
568
569
570
571
Core::Internal::EditorView *EditorManager::currentEditorView() const
{
    return currentSplitterOrView()->view();
}

con's avatar
con committed
572
573
574
QList<IEditor *> EditorManager::editorsForFileName(const QString &filename) const
{
    QList<IEditor *> found;
575
    QString fixedname = FileManager::fixFileName(filename, FileManager::KeepLinks);
con's avatar
con committed
576
    foreach (IEditor *editor, openedEditors()) {
577
        if (fixedname == FileManager::fixFileName(editor->file()->fileName(), FileManager::KeepLinks))
con's avatar
con committed
578
579
580
581
582
            found << editor;
    }
    return found;
}

583
584
585
586
587
588
589
590
591
592
QList<IEditor *> EditorManager::editorsForFile(IFile *file) const
{
    QList<IEditor *> found;
    foreach (IEditor *editor, openedEditors()) {
        if (editor->file() == file)
            found << editor;
    }
    return found;
}

con's avatar
con committed
593
594
IEditor *EditorManager::currentEditor() const
{
mae's avatar
mae committed
595
    return m_d->m_currentEditor;
con's avatar
con committed
596
597
}

mae's avatar
mae committed
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
void EditorManager::emptyView(Core::Internal::EditorView *view)
{
    if (!view)
        return;

    QList<IEditor *> editors = view->editors();
    foreach (IEditor *editor, editors) {
        if (!m_d->m_editorModel->isDuplicate(editor)) {
            editors.removeAll(editor);
            view->removeEditor(editor);
            continue;
        }
        emit editorAboutToClose(editor);
        removeEditor(editor);
        view->removeEditor(editor);
    }
    emit editorsClosed(editors);
    foreach (IEditor *editor, editors) {
        delete editor;
    }
}

mae's avatar
mae committed
620
void EditorManager::closeView(Core::Internal::EditorView *view)
con's avatar
con committed
621
{
mae's avatar
mae committed
622
    if (!view)
con's avatar
con committed
623
        return;
mae's avatar
mae committed
624

625
    if (view == m_d->m_view) {
626
627
        if (IEditor *e = view->currentEditor())
            closeEditors(QList<IEditor *>() << e);
mae's avatar
mae committed
628
629
630
        return;
    }

631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
    if (IEditor *e = view->currentEditor()) {
        /*
           when we are closing a view with an original editor which has
           duplicates, then make one of the duplicates the original.
           Otherwise the original would be kept around and the user might
           experience jumping to a missleading position within the file when
           visiting the file again. With the code below, the position within
           the file will be the position of the first duplicate which is still
           around.
        */
        if (!m_d->m_editorModel->isDuplicate(e)) {
            QList<IEditor *> duplicates = m_d->m_editorModel->duplicatesFor(e);
            if (!duplicates.isEmpty()) {
                m_d->m_editorModel->makeOriginal(duplicates.first());
            }
        }
    }

mae's avatar
mae committed
649
650
651
    emptyView(view);

    SplitterOrView *splitterOrView = m_d->m_splitter->findView(view);
652
    Q_ASSERT(splitterOrView);
mae's avatar
mae committed
653
654
655
    Q_ASSERT(splitterOrView->view() == view);
    SplitterOrView *splitter = m_d->m_splitter->findSplitter(splitterOrView);
    Q_ASSERT(splitterOrView->hasEditors() == false);
656
    splitterOrView->hide();
mae's avatar
mae committed
657
658
659
660
661
662
    delete splitterOrView;

    splitter->unsplit();

    SplitterOrView *newCurrent = splitter->findFirstView();
    if (newCurrent) {
663
664
665
        if (IEditor *e = newCurrent->editor()) {
            activateEditor(newCurrent->view(), e);
        } else {
mae's avatar
mae committed
666
            setCurrentView(newCurrent);
667
        }
mae's avatar
mae committed
668
    }
mae's avatar
mae committed
669
}
mae's avatar
mae committed
670

con's avatar
con committed
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
QList<IEditor*>
    EditorManager::editorsForFiles(QList<IFile*> files) const
{
    const QList<IEditor *> editors = openedEditors();
    QSet<IEditor *> found;
    foreach (IFile *file, files) {
        foreach (IEditor *editor, editors) {
            if (editor->file() == file && !found.contains(editor)) {
                    found << editor;
            }
        }
    }
    return found.toList();
}

686
QList<IFile *> EditorManager::filesForEditors(QList<IEditor *> editors) const
con's avatar
con committed
687
688
689
690
691
692
{
    QSet<IEditor *> handledEditors;
    QList<IFile *> files;
    foreach (IEditor *editor, editors) {
        if (!handledEditors.contains(editor)) {
            files << editor->file();
693
            handledEditors.insert(editor);
con's avatar
con committed
694
695
696
697
698
699
700
        }
    }
    return files;
}

bool EditorManager::closeAllEditors(bool askAboutModifiedEditors)
{
701
    m_d->m_editorModel->removeAllRestoredEditors();
702
    if (closeEditors(openedEditors(), askAboutModifiedEditors)) {
703
//        m_d->clearNavigationHistory();
704
705
706
        return true;
    }
    return false;
con's avatar
con committed
707
708
}

709
void EditorManager::closeOtherEditors(IEditor *editor)
con's avatar
con committed
710
711
712
{
    m_d->m_editorModel->removeAllRestoredEditors();
    QList<IEditor*> editors = openedEditors();
713
    editors.removeAll(editor);
con's avatar
con committed
714
715
716
    closeEditors(editors, true);
}

717
718
719
720
721
722
723
void EditorManager::closeOtherEditors()
{
    IEditor *current = currentEditor();
    QTC_ASSERT(current, return);
    closeOtherEditors(current);
}

724
725
726
// SLOT connected to action
void EditorManager::closeEditor()
{
727
728
    if (!m_d->m_currentEditor)
        return;
729
    addCurrentPositionToNavigationHistory();
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
    closeEditor(m_d->m_currentEditor);
}

void EditorManager::closeEditor(Core::IEditor *editor)
{
    if (!editor)
        return;
    closeEditors(QList<IEditor *>() << editor);
}

void EditorManager::closeEditor(const QModelIndex &index)
{
    IEditor *editor = index.data(Qt::UserRole).value<Core::IEditor*>();
    if (editor)
        closeEditor(editor);
    else
        m_d->m_editorModel->removeEditor(index);
}

749
bool EditorManager::closeEditors(const QList<IEditor*> &editorsToClose, bool askAboutModifiedEditors)
con's avatar
con committed
750
751
752
{
    if (editorsToClose.isEmpty())
        return true;
753

mae's avatar
mae committed
754
    SplitterOrView *currentSplitterOrView = this->currentSplitterOrView();
755

con's avatar
con committed
756
757
758
759
    bool closingFailed = false;
    QList<IEditor*> acceptedEditors;
    //ask all core listeners to check whether the editor can be closed
    const QList<ICoreListener *> listeners =
760
        pluginManager()->getObjects<ICoreListener>();
con's avatar
con committed
761
762
    foreach (IEditor *editor, editorsToClose) {
        bool editorAccepted = true;
mae's avatar
mae committed
763
764
        if (m_d->m_editorModel->isDuplicate(editor))
            editor = m_d->m_editorModel->originalForDuplicate(editor);
con's avatar
con committed
765
766
767
        foreach (ICoreListener *listener, listeners) {
            if (!listener->editorAboutToClose(editor)) {
                editorAccepted = false;
768
                closingFailed = true;
con's avatar
con committed
769
770
771
772
773
774
775
776
777
778
779
                break;
            }
        }
        if (editorAccepted)
            acceptedEditors.append(editor);
    }
    if (acceptedEditors.isEmpty())
        return false;
    //ask whether to save modified files
    if (askAboutModifiedEditors) {
        bool cancelled = false;
780
        QList<IFile*> list = m_d->m_core->fileManager()->
con's avatar
con committed
781
782
783
784
            saveModifiedFiles(filesForEditors(acceptedEditors), &cancelled);
        if (cancelled)
            return false;
        if (!list.isEmpty()) {
785
            closingFailed = true;
con's avatar
con committed
786
787
788
789
790
791
            QSet<IEditor*> skipSet = editorsForFiles(list).toSet();
            acceptedEditors = acceptedEditors.toSet().subtract(skipSet).toList();
        }
    }
    if (acceptedEditors.isEmpty())
        return false;
mae's avatar
mae committed
792
793
794
795
796

    // add duplicates
    foreach(IEditor *editor, acceptedEditors)
        acceptedEditors += m_d->m_editorModel->duplicatesFor(editor);

797
    QList<EditorView*> closedViews;
mae's avatar
mae committed
798

con's avatar
con committed
799
800
801
    // remove the editors
    foreach (IEditor *editor, acceptedEditors) {
        emit editorAboutToClose(editor);
802
803
        if (!editor->file()->fileName().isEmpty()
                && !editor->isTemporary()) {
con's avatar
con committed
804
805
806
807
            QByteArray state = editor->saveState();
            if (!state.isEmpty())
                m_d->m_editorStates.insert(editor->file()->fileName(), QVariant(state));
        }
mae's avatar
mae committed
808

mae's avatar
mae committed
809
        removeEditor(editor);
mae's avatar
mae committed
810
        if (SplitterOrView *view = m_d->m_splitter->findView(editor)) {
811
812
            if (editor == view->view()->currentEditor())
                closedViews += view->view();
mae's avatar
mae committed
813
            view->view()->removeEditor(editor);
mae's avatar
mae committed
814
        }
con's avatar
con committed
815
    }
mae's avatar
mae committed
816

817
    foreach (EditorView *view, closedViews) {
mae's avatar
mae committed
818
819
820
        IEditor *newCurrent = view->currentEditor();
        if (!newCurrent)
            newCurrent = pickUnusedEditor();
821
        if (newCurrent) {
mae's avatar
mae committed
822
            activateEditor(view, newCurrent, NoActivate);
823
824
825
        } else {
            QModelIndex idx = m_d->m_editorModel->firstRestoredEditor();
            if (idx.isValid())
826
                activateEditorForIndex(view, idx, NoActivate);
827
        }
mae's avatar
mae committed
828
829
    }

con's avatar
con committed
830
    emit editorsClosed(acceptedEditors);
831

con's avatar
con committed
832
833
834
    foreach (IEditor *editor, acceptedEditors) {
        delete editor;
    }
mae's avatar
mae committed
835

836
837
838
    if (currentSplitterOrView) {
        if (IEditor *editor = currentSplitterOrView->editor())
            activateEditor(currentSplitterOrView->view(), editor);
839
    }
mae's avatar
mae committed
840

841
    if (!currentEditor()) {
842
        emit currentEditorChanged(0);
843
        updateActions();
844
        updateWindowTitle();
845
    }
846

con's avatar
con committed
847
848
849
    return !closingFailed;
}

850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
void EditorManager::closeDuplicate(Core::IEditor *editor)
{

    IEditor *original = editor;
    if (m_d->m_editorModel->isDuplicate(editor))
        original= m_d->m_editorModel->originalForDuplicate(editor);
    QList<IEditor *> duplicates = m_d->m_editorModel->duplicatesFor(original);

    if (duplicates.isEmpty()) {
        closeEditor(editor);
        return;
    }

    if (original== editor)
        m_d->m_editorModel->makeOriginal(duplicates.first());

mae's avatar
mae committed
866
    SplitterOrView *currentSplitterOrView = this->currentSplitterOrView();
867
868
869

    emit editorAboutToClose(editor);

Bill King's avatar
Bill King committed
870
871
872
873
    if(m_d->m_splitter->findView(editor)) {
        EditorView *view = m_d->m_splitter->findView(editor)->view();
        removeEditor(editor);
        view->removeEditor(editor);
874

Bill King's avatar
Bill King committed
875
876
877
878
879
880
881
882
        IEditor *newCurrent = view->currentEditor();
        if (!newCurrent)
            newCurrent = pickUnusedEditor();
        if (newCurrent) {
            activateEditor(view, newCurrent, NoActivate);
        } else {
            QModelIndex idx = m_d->m_editorModel->firstRestoredEditor();
            if (idx.isValid())
883
                activateEditorForIndex(view, idx, NoActivate);
Bill King's avatar
Bill King committed
884
        }
885
886
887
888
889
890
891
892
893
894
    }

    emit editorsClosed(QList<IEditor*>() << editor);
    delete editor;
    if (currentSplitterOrView) {
        if (IEditor *currentEditor = currentSplitterOrView->editor())
            activateEditor(currentSplitterOrView->view(), currentEditor);
    }
}

895
Core::IEditor *EditorManager::pickUnusedEditor() const
mae's avatar
mae committed
896
{
mae's avatar
mae committed
897
    foreach (IEditor *editor, openedEditors()) {
mae's avatar
mae committed
898
899
900
901
902
903
        SplitterOrView *view = m_d->m_splitter->findView(editor);
        if (!view || view->editor() != editor)
            return editor;
    }
    return 0;
}
con's avatar
con committed
904

905
void EditorManager::activateEditorForIndex(const QModelIndex &index, OpenEditorFlags flags)
906
{
907
908
909
910
911
912
    activateEditorForIndex(currentEditorView(), index, flags);
}

void EditorManager::activateEditorForIndex(Internal::EditorView *view, const QModelIndex &index, OpenEditorFlags flags)
{
    Q_ASSERT(view);
913
914
    IEditor *editor = index.data(Qt::UserRole).value<IEditor*>();
    if (editor)  {
915
916
        activateEditor(view, editor, flags);
        return;
917
918
919
    }

    QString fileName = index.data(Qt::UserRole + 1).toString();
920
    QString id = index.data(Qt::UserRole + 2).toString();
921
    openEditor(view, fileName, id, flags);
mae's avatar
mae committed
922
923
924
925
}

Core::IEditor *EditorManager::placeEditor(Core::Internal::EditorView *view, Core::IEditor *editor)
{
mae's avatar
mae committed
926
927
928
929
930
    Q_ASSERT(view && editor);

    if (view->currentEditor() && view->currentEditor()->file() == editor->file())
        editor = view->currentEditor();

mae's avatar
mae committed
931
    if (!view->hasEditor(editor)) {
mae's avatar
mae committed
932
933
934
935
        bool duplicateSupported = editor->duplicateSupported();
        if (SplitterOrView *sourceView = m_d->m_splitter->findView(editor)) {
            if (editor != sourceView->editor() || !duplicateSupported) {
                sourceView->view()->removeEditor(editor);
mae's avatar
mae committed
936
937
938
939
940
941
942
943
                view->addEditor(editor);
                view->setCurrentEditor(editor);
                if (!sourceView->editor()) {
                    if (IEditor *replacement = pickUnusedEditor()) {
                        sourceView->view()->addEditor(replacement);
                    }
                }
                return editor;
mae's avatar
mae committed
944
945
946
            } else if (duplicateSupported) {
                editor = duplicateEditor(editor);
                Q_ASSERT(editor);
947
                m_d->m_editorModel->makeOriginal(editor);
mae's avatar
mae committed
948
949
            }
        }
mae's avatar
mae committed
950
951
        view->addEditor(editor);
    }
mae's avatar
mae committed
952
953
    return editor;
}
mae's avatar
mae committed
954

955
void EditorManager::activateEditor(Core::IEditor *editor, OpenEditorFlags flags)
956
{
con's avatar
con committed
957
958
    SplitterOrView *splitterOrView = m_d->m_splitter->findView(editor);
    EditorView *view = (splitterOrView ? splitterOrView->view() : 0);
959
960
961
962
    // TODO an IEditor doesn't have to belong to a view, which makes this method a bit funny
    if (!view)
        view = currentEditorView();
    activateEditor(view, editor, flags);
963
964
}

965
Core::IEditor *EditorManager::activateEditor(Core::Internal::EditorView *view, Core::IEditor *editor, OpenEditorFlags flags)
mae's avatar
mae committed
966
{
967
    Q_ASSERT(view);
mae's avatar
mae committed
968

969
970
971
972
    if (!editor) {
        if (!m_d->m_currentEditor)
            setCurrentEditor(0, (flags & IgnoreNavigationHistory));
        return 0;
mae's avatar
mae committed
973
974
    }

mae's avatar
mae committed
975
976
977
978
    editor = placeEditor(view, editor);

    if (!(flags & NoActivate)) {
        setCurrentEditor(editor, (flags & IgnoreNavigationHistory));
979
        if (flags & ModeSwitch) {
980
            switchToPreferedMode();
981
        }
982
983
        if (isVisible())
            editor->widget()->setFocus();
mae's avatar
mae committed
984
    }
985
    return editor;
mae's avatar
mae committed
986
987
}

988
Core::IEditor *EditorManager::activateEditorForFile(Core::Internal::EditorView *view, Core::IFile *file, OpenEditorFlags flags)
989
{
990
    Q_ASSERT(view);
991
992
993
994
    const QList<IEditor*> editors = editorsForFile(file);
    if (editors.isEmpty())
        return 0;

995
996
    activateEditor(view, editors.first(), flags);
    return editors.first();
997
998
}

999
1000
1001
1002
/* For something that has a 'QStringList mimeTypes' (IEditorFactory
 * or IExternalEditor), find the one best matching the mimetype passed in.
 *  Recurse over the parent classes of the mimetype to find them. */
template <class EditorFactoryLike>
con's avatar
con committed
1003
1004
static void mimeTypeFactoryRecursion(const MimeDatabase *db,
                                     const MimeType &mimeType,
1005
                                     const QList<EditorFactoryLike*> &allFactories,
con's avatar
con committed
1006
                                     bool firstMatchOnly,
1007
                                     QList<EditorFactoryLike*> *list)
con's avatar
con committed
1008
{
1009
    typedef typename QList<EditorFactoryLike*>::const_iterator EditorFactoryLikeListConstIterator;
con's avatar
con committed
1010
1011
    // Loop factories to find type
    const QString type = mimeType.type();
1012
1013
    const EditorFactoryLikeListConstIterator fcend = allFactories.constEnd();
    for (EditorFactoryLikeListConstIterator fit = allFactories.constBegin(); fit != fcend; ++fit) {
con's avatar
con committed
1014
        // Exclude duplicates when recursing over xml or C++ -> C -> text.
1015
        EditorFactoryLike *factory = *fit;
con's avatar
con committed
1016
1017
1018
1019
1020
1021
1022
        if (!list->contains(factory) && factory->mimeTypes().contains(type)) {
            list->push_back(*fit);
            if (firstMatchOnly)
                return;
            break;
        }
    }
1023
    // Any parent mime type classes? -> recurse
con's avatar
con committed
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
    QStringList parentTypes = mimeType.subClassesOf();
    if (parentTypes.empty())
        return;
    const QStringList::const_iterator pcend = parentTypes .constEnd();
    for (QStringList::const_iterator pit = parentTypes .constBegin(); pit != pcend; ++pit) {
        if (const MimeType parent = db->findByType(*pit))
            mimeTypeFactoryRecursion