OSDN Git Service

Introduce a currentEditorStateChanged signal.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / coreplugin / editormanager / editormanager.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** Commercial Usage
10 **
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
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 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at http://qt.nokia.com/contact.
27 **
28 **************************************************************************/
29
30 #include "editormanager.h"
31 #include "editorview.h"
32 #include "openeditorswindow.h"
33 #include "openeditorsview.h"
34 #include "openeditorsmodel.h"
35 #include "openwithdialog.h"
36 #include "filemanager.h"
37 #include "icore.h"
38 #include "ieditor.h"
39 #include "iversioncontrol.h"
40 #include "mimedatabase.h"
41 #include "tabpositionindicator.h"
42 #include "vcsmanager.h"
43
44 #include <coreplugin/editortoolbar.h>
45 #include <coreplugin/coreconstants.h>
46 #include <coreplugin/modemanager.h>
47 #include <coreplugin/actionmanager/actionmanager.h>
48 #include <coreplugin/actionmanager/actioncontainer.h>
49 #include <coreplugin/actionmanager/command.h>
50 #include <coreplugin/editormanager/ieditorfactory.h>
51 #include <coreplugin/editormanager/iexternaleditor.h>
52 #include <coreplugin/icorelistener.h>
53 #include <coreplugin/imode.h>
54 #include <coreplugin/settingsdatabase.h>
55 #include <coreplugin/variablemanager.h>
56 #include <coreplugin/uniqueidmanager.h>
57
58 #include <extensionsystem/pluginmanager.h>
59
60 #include <utils/consoleprocess.h>
61 #include <utils/qtcassert.h>
62
63 #include <QtCore/QDebug>
64 #include <QtCore/QFileInfo>
65 #include <QtCore/QMap>
66 #include <QtCore/QProcess>
67 #include <QtCore/QSet>
68 #include <QtCore/QSettings>
69 #include <QtCore/QTextCodec>
70
71 #include <QtGui/QAction>
72 #include <QtGui/QShortcut>
73 #include <QtGui/QApplication>
74 #include <QtGui/QFileDialog>
75 #include <QtGui/QLayout>
76 #include <QtGui/QMainWindow>
77 #include <QtGui/QMenu>
78 #include <QtGui/QMessageBox>
79 #include <QtGui/QPushButton>
80 #include <QtGui/QSplitter>
81 #include <QtGui/QStackedLayout>
82
83 Q_DECLARE_METATYPE(Core::IEditor*)
84
85 enum { debugEditorManager=0 };
86
87 static inline ExtensionSystem::PluginManager *pluginManager()
88 {
89     return ExtensionSystem::PluginManager::instance();
90 }
91
92 //===================EditorClosingCoreListener======================
93
94 namespace Core {
95 namespace Internal {
96
97 class EditorClosingCoreListener : public ICoreListener
98 {
99 public:
100     EditorClosingCoreListener(EditorManager *em);
101     bool editorAboutToClose(IEditor *editor);
102     bool coreAboutToClose();
103
104 private:
105     EditorManager *m_em;
106 };
107
108 EditorClosingCoreListener::EditorClosingCoreListener(EditorManager *em)
109         : m_em(em)
110 {
111 }
112
113 bool EditorClosingCoreListener::editorAboutToClose(IEditor *)
114 {
115     return true;
116 }
117
118 bool EditorClosingCoreListener::coreAboutToClose()
119 {
120     // Do not ask for files to save.
121     // MainWindow::closeEvent has already done that.
122     return m_em->closeAllEditors(false);
123 }
124
125 } // namespace Internal
126 } // namespace Core
127
128 using namespace Core;
129 using namespace Core::Internal;
130 using namespace Utils;
131
132 //===================EditorManager=====================
133
134 EditorManagerPlaceHolder *EditorManagerPlaceHolder::m_current = 0;
135
136 EditorManagerPlaceHolder::EditorManagerPlaceHolder(Core::IMode *mode, QWidget *parent)
137     : QWidget(parent), m_mode(mode)
138 {
139     setLayout(new QVBoxLayout);
140     layout()->setMargin(0);
141     connect(Core::ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode *)),
142             this, SLOT(currentModeChanged(Core::IMode *)));
143
144     currentModeChanged(Core::ModeManager::instance()->currentMode());
145 }
146
147 EditorManagerPlaceHolder::~EditorManagerPlaceHolder()
148 {
149     if (m_current == this) {
150         EditorManager::instance()->setParent(0);
151         EditorManager::instance()->hide();
152     }
153 }
154
155 void EditorManagerPlaceHolder::currentModeChanged(Core::IMode *mode)
156 {
157     if (m_current == this) {
158         m_current = 0;
159         EditorManager::instance()->setParent(0);
160         EditorManager::instance()->hide();
161     }
162     if (m_mode == mode) {
163         m_current = this;
164         layout()->addWidget(EditorManager::instance());
165         EditorManager::instance()->show();
166     }
167 }
168
169 EditorManagerPlaceHolder* EditorManagerPlaceHolder::current()
170 {
171     return m_current;
172 }
173
174 // ---------------- EditorManager
175
176 namespace Core {
177
178
179 struct EditorManagerPrivate {
180     explicit EditorManagerPrivate(ICore *core, QWidget *parent);
181     ~EditorManagerPrivate();
182     Internal::EditorView *m_view;
183     Internal::SplitterOrView *m_splitter;
184     QPointer<IEditor> m_currentEditor;
185     QPointer<SplitterOrView> m_currentView;
186
187     ICore *m_core;
188
189
190     // actions
191     QAction *m_revertToSavedAction;
192     QAction *m_saveAction;
193     QAction *m_saveAsAction;
194     QAction *m_closeCurrentEditorAction;
195     QAction *m_closeAllEditorsAction;
196     QAction *m_closeOtherEditorsAction;
197     QAction *m_gotoNextDocHistoryAction;
198     QAction *m_gotoPreviousDocHistoryAction;
199     QAction *m_goBackAction;
200     QAction *m_goForwardAction;
201     QAction *m_openInExternalEditorAction;
202     QAction *m_splitAction;
203     QAction *m_splitSideBySideAction;
204     QAction *m_removeCurrentSplitAction;
205     QAction *m_removeAllSplitsAction;
206     QAction *m_gotoOtherSplitAction;
207
208     Internal::OpenEditorsWindow *m_windowPopup;
209     Internal::EditorClosingCoreListener *m_coreListener;
210
211     QMap<QString, QVariant> m_editorStates;
212     Internal::OpenEditorsViewFactory *m_openEditorsFactory;
213
214     OpenEditorsModel *m_editorModel;
215     QString m_externalEditor;
216
217     IFile::ReloadSetting m_reloadSetting;
218     IFile::Utf8BomSetting m_utf8BomSetting;
219
220     QString m_titleAddition;
221 };
222 }
223
224 EditorManagerPrivate::EditorManagerPrivate(ICore *core, QWidget *parent) :
225     m_view(0),
226     m_splitter(0),
227     m_core(core),
228     m_revertToSavedAction(new QAction(EditorManager::tr("Revert to Saved"), parent)),
229     m_saveAction(new QAction(parent)),
230     m_saveAsAction(new QAction(parent)),
231     m_closeCurrentEditorAction(new QAction(EditorManager::tr("Close"), parent)),
232     m_closeAllEditorsAction(new QAction(EditorManager::tr("Close All"), parent)),
233     m_closeOtherEditorsAction(new QAction(EditorManager::tr("Close Others"), parent)),
234     m_gotoNextDocHistoryAction(new QAction(EditorManager::tr("Next Open Document in History"), parent)),
235     m_gotoPreviousDocHistoryAction(new QAction(EditorManager::tr("Previous Open Document in History"), parent)),
236     m_goBackAction(new QAction(QIcon(QLatin1String(Constants::ICON_PREV)), EditorManager::tr("Go Back"), parent)),
237     m_goForwardAction(new QAction(QIcon(QLatin1String(Constants::ICON_NEXT)), EditorManager::tr("Go Forward"), parent)),
238     m_openInExternalEditorAction(new QAction(EditorManager::tr("Open in External Editor"), parent)),
239     m_windowPopup(0),
240     m_coreListener(0),
241     m_reloadSetting(IFile::AlwaysAsk),
242     m_utf8BomSetting(IFile::OnlyKeep)
243 {
244     m_editorModel = new OpenEditorsModel(parent);
245 }
246
247 EditorManagerPrivate::~EditorManagerPrivate()
248 {
249 //    clearNavigationHistory();
250 }
251
252 EditorManager *EditorManager::m_instance = 0;
253
254 static Command *createSeparator(ActionManager *am, QObject *parent,
255                                 const QString &name,
256                                 const Context &context)
257 {
258     QAction *tmpaction = new QAction(parent);
259     tmpaction->setSeparator(true);
260     Command *cmd = am->registerAction(tmpaction, name, context);
261     return cmd;
262 }
263
264 EditorManager::EditorManager(ICore *core, QWidget *parent) :
265     QWidget(parent),
266     m_d(new EditorManagerPrivate(core, parent))
267 {
268     m_instance = this;
269
270     connect(m_d->m_core, SIGNAL(contextAboutToChange(Core::IContext *)),
271             this, SLOT(handleContextChange(Core::IContext *)));
272
273     const Context editManagerContext(Constants::C_EDITORMANAGER);
274     // combined context for edit & design modes
275     const Context editDesignContext(Constants::C_EDITORMANAGER, Constants::C_DESIGN_MODE);
276
277     ActionManager *am = m_d->m_core->actionManager();
278     ActionContainer *mfile = am->actionContainer(Constants::M_FILE);
279
280     // Revert to saved
281     m_d->m_revertToSavedAction->setIcon(QIcon::fromTheme(QLatin1String("document-revert")));
282     Command *cmd = am->registerAction(m_d->m_revertToSavedAction,
283                                        Constants::REVERTTOSAVED, editManagerContext);
284     cmd->setAttribute(Command::CA_UpdateText);
285     cmd->setDefaultText(tr("Revert File to Saved"));
286     mfile->addAction(cmd, Constants::G_FILE_SAVE);
287     connect(m_d->m_revertToSavedAction, SIGNAL(triggered()), this, SLOT(revertToSaved()));
288
289     // Save Action
290     am->registerAction(m_d->m_saveAction, Constants::SAVE, editManagerContext);
291     connect(m_d->m_saveAction, SIGNAL(triggered()), this, SLOT(saveFile()));
292
293     // Save As Action
294     am->registerAction(m_d->m_saveAsAction, Constants::SAVEAS, editManagerContext);
295     connect(m_d->m_saveAsAction, SIGNAL(triggered()), this, SLOT(saveFileAs()));
296
297     // Window Menu
298     ActionContainer *mwindow = am->actionContainer(Constants::M_WINDOW);
299
300     // Window menu separators
301     QAction *tmpaction = new QAction(this);
302     tmpaction->setSeparator(true);
303     cmd = am->registerAction(tmpaction, "QtCreator.Window.Sep.Split", editManagerContext);
304     mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
305
306     tmpaction = new QAction(this);
307     tmpaction->setSeparator(true);
308     cmd = am->registerAction(tmpaction, "QtCreator.Window.Sep.Navigate", editManagerContext);
309     mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
310
311     // Close Action
312     cmd = am->registerAction(m_d->m_closeCurrentEditorAction, Constants::CLOSE, editManagerContext);
313     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+W")));
314     cmd->setAttribute(Core::Command::CA_UpdateText);
315     cmd->setDefaultText(m_d->m_closeCurrentEditorAction->text());
316     mfile->addAction(cmd, Constants::G_FILE_CLOSE);
317     connect(m_d->m_closeCurrentEditorAction, SIGNAL(triggered()), this, SLOT(closeEditor()));
318
319 #ifdef Q_WS_WIN
320     // workaround for QTCREATORBUG-72
321     QShortcut *sc = new QShortcut(parent);
322     cmd = am->registerShortcut(sc, Constants::CLOSE_ALTERNATIVE, editManagerContext);
323     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+F4")));
324     cmd->setDefaultText(EditorManager::tr("Close"));
325     connect(sc, SIGNAL(activated()), this, SLOT(closeEditor()));
326 #endif
327
328     // Close All Action
329     cmd = am->registerAction(m_d->m_closeAllEditorsAction, Constants::CLOSEALL, editManagerContext);
330     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+W")));
331     mfile->addAction(cmd, Constants::G_FILE_CLOSE);
332     connect(m_d->m_closeAllEditorsAction, SIGNAL(triggered()), this, SLOT(closeAllEditors()));
333
334     // Close All Others Action
335     cmd = am->registerAction(m_d->m_closeOtherEditorsAction, Constants::CLOSEOTHERS, editManagerContext);
336     mfile->addAction(cmd, Constants::G_FILE_CLOSE);
337     cmd->setAttribute(Core::Command::CA_UpdateText);
338     connect(m_d->m_closeOtherEditorsAction, SIGNAL(triggered()), this, SLOT(closeOtherEditors()));
339
340     // Goto Previous In History Action
341     cmd = am->registerAction(m_d->m_gotoPreviousDocHistoryAction, Constants::GOTOPREVINHISTORY, editDesignContext);
342 #ifdef Q_WS_MAC
343     cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Tab")));
344 #else
345     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Tab")));
346 #endif
347     mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
348     connect(m_d->m_gotoPreviousDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoPreviousDocHistory()));
349
350     // Goto Next In History Action
351     cmd = am->registerAction(m_d->m_gotoNextDocHistoryAction, Constants::GOTONEXTINHISTORY, editDesignContext);
352 #ifdef Q_WS_MAC
353     cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Shift+Tab")));
354 #else
355     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+Tab")));
356 #endif
357     mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
358     connect(m_d->m_gotoNextDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoNextDocHistory()));
359
360     // Go back in navigation history
361     cmd = am->registerAction(m_d->m_goBackAction, Constants::GO_BACK, editDesignContext);
362 #ifdef Q_WS_MAC
363     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Left")));
364 #else
365     cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Left")));
366 #endif
367     mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
368     connect(m_d->m_goBackAction, SIGNAL(triggered()), this, SLOT(goBackInNavigationHistory()));
369
370     // Go forward in navigation history
371     cmd = am->registerAction(m_d->m_goForwardAction, Constants::GO_FORWARD, editDesignContext);
372 #ifdef Q_WS_MAC
373     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Right")));
374 #else
375     cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Right")));
376 #endif
377     mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
378     connect(m_d->m_goForwardAction, SIGNAL(triggered()), this, SLOT(goForwardInNavigationHistory()));
379
380 #ifdef Q_WS_MAC
381     QString prefix = tr("Meta+E");
382 #else
383     QString prefix = tr("Ctrl+E");
384 #endif
385
386     m_d->m_splitAction = new QAction(tr("Split"), this);
387     cmd = am->registerAction(m_d->m_splitAction, Constants::SPLIT, editManagerContext);
388     cmd->setDefaultKeySequence(QKeySequence(tr("%1,2").arg(prefix)));
389     mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
390     connect(m_d->m_splitAction, SIGNAL(triggered()), this, SLOT(split()));
391
392     m_d->m_splitSideBySideAction = new QAction(tr("Split Side by Side"), this);
393     cmd = am->registerAction(m_d->m_splitSideBySideAction, Constants::SPLIT_SIDE_BY_SIDE, editManagerContext);
394     cmd->setDefaultKeySequence(QKeySequence(tr("%1,3").arg(prefix)));
395     mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
396     connect(m_d->m_splitSideBySideAction, SIGNAL(triggered()), this, SLOT(splitSideBySide()));
397
398     m_d->m_removeCurrentSplitAction = new QAction(tr("Remove Current Split"), this);
399     cmd = am->registerAction(m_d->m_removeCurrentSplitAction, Constants::REMOVE_CURRENT_SPLIT, editManagerContext);
400     cmd->setDefaultKeySequence(QKeySequence(tr("%1,0").arg(prefix)));
401     mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
402     connect(m_d->m_removeCurrentSplitAction, SIGNAL(triggered()), this, SLOT(removeCurrentSplit()));
403
404     m_d->m_removeAllSplitsAction = new QAction(tr("Remove All Splits"), this);
405     cmd = am->registerAction(m_d->m_removeAllSplitsAction, Constants::REMOVE_ALL_SPLITS, editManagerContext);
406     cmd->setDefaultKeySequence(QKeySequence(tr("%1,1").arg(prefix)));
407     mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
408     connect(m_d->m_removeAllSplitsAction, SIGNAL(triggered()), this, SLOT(removeAllSplits()));
409
410     m_d->m_gotoOtherSplitAction = new QAction(tr("Go to Next Split"), this);
411     cmd = am->registerAction(m_d->m_gotoOtherSplitAction, Constants::GOTO_OTHER_SPLIT, editManagerContext);
412     cmd->setDefaultKeySequence(QKeySequence(tr("%1,o").arg(prefix)));
413     mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
414     connect(m_d->m_gotoOtherSplitAction, SIGNAL(triggered()), this, SLOT(gotoOtherSplit()));
415
416     ActionContainer *medit = am->actionContainer(Constants::M_EDIT);
417     ActionContainer *advancedMenu = am->createMenu(Constants::M_EDIT_ADVANCED);
418     medit->addMenu(advancedMenu, Constants::G_EDIT_ADVANCED);
419     advancedMenu->menu()->setTitle(tr("&Advanced"));
420     advancedMenu->appendGroup(Constants::G_EDIT_FORMAT);
421     advancedMenu->appendGroup(Constants::G_EDIT_COLLAPSING);
422     advancedMenu->appendGroup(Constants::G_EDIT_BLOCKS);
423     advancedMenu->appendGroup(Constants::G_EDIT_FONT);
424     advancedMenu->appendGroup(Constants::G_EDIT_EDITOR);
425
426     // Advanced menu separators
427     cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Collapsing"), editManagerContext);
428     advancedMenu->addAction(cmd, Constants::G_EDIT_COLLAPSING);
429     cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Blocks"), editManagerContext);
430     advancedMenu->addAction(cmd, Constants::G_EDIT_BLOCKS);
431     cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Font"), editManagerContext);
432     advancedMenu->addAction(cmd, Constants::G_EDIT_FONT);
433     cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Editor"), editManagerContext);
434     advancedMenu->addAction(cmd, Constants::G_EDIT_EDITOR);
435
436     cmd = am->registerAction(m_d->m_openInExternalEditorAction, Constants::OPEN_IN_EXTERNAL_EDITOR, editManagerContext);
437     cmd->setDefaultKeySequence(QKeySequence(tr("Alt+V,Alt+I")));
438     advancedMenu->addAction(cmd, Constants::G_EDIT_EDITOR);
439     connect(m_d->m_openInExternalEditorAction, SIGNAL(triggered()), this, SLOT(openInExternalEditor()));
440
441     // Connect to VariableManager for CURRENT_DOCUMENT variable setting
442     VariableManager::initEditorManagerConnections();
443     // other setup
444     m_d->m_splitter = new SplitterOrView(m_d->m_editorModel);
445     m_d->m_view = m_d->m_splitter->view();
446
447
448     QHBoxLayout *layout = new QHBoxLayout(this);
449     layout->setMargin(0);
450     layout->setSpacing(0);
451     layout->addWidget(m_d->m_splitter);
452
453     updateActions();
454
455     m_d->m_windowPopup = new OpenEditorsWindow(this);
456 }
457
458 EditorManager::~EditorManager()
459 {
460     m_instance = 0;
461     if (m_d->m_core) {
462         ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
463         if (m_d->m_coreListener) {
464             pm->removeObject(m_d->m_coreListener);
465             delete m_d->m_coreListener;
466         }
467         pm->removeObject(m_d->m_openEditorsFactory);
468         delete m_d->m_openEditorsFactory;
469     }
470     delete m_d;
471 }
472
473 void EditorManager::init()
474 {
475     m_d->m_coreListener = new EditorClosingCoreListener(this);
476     pluginManager()->addObject(m_d->m_coreListener);
477
478     m_d->m_openEditorsFactory = new OpenEditorsViewFactory();
479     pluginManager()->addObject(m_d->m_openEditorsFactory);
480 }
481
482
483 EditorToolBar *EditorManager::createToolBar(QWidget *parent)
484 {
485     return new EditorToolBar(parent);
486 }
487
488 QString EditorManager::defaultExternalEditor() const
489 {
490 #ifdef Q_OS_UNIX
491     return ConsoleProcess::defaultTerminalEmulator() + QLatin1String(
492 # ifdef Q_OS_MAC
493             " -async"
494 # endif
495             " -geom %Wx%H+%x+%y -e vi %f +%l +\"normal %c|\"");
496 #else
497     return QLatin1String("notepad %f");
498 #endif
499 }
500
501 void EditorManager::removeEditor(IEditor *editor)
502 {
503     bool isDuplicate = m_d->m_editorModel->isDuplicate(editor);
504     m_d->m_editorModel->removeEditor(editor);
505     if (!isDuplicate) {
506         m_d->m_core->fileManager()->removeFile(editor->file());
507     }
508     m_d->m_core->removeContextObject(editor);
509 }
510
511 void EditorManager::handleContextChange(Core::IContext *context)
512 {
513     if (debugEditorManager)
514         qDebug() << Q_FUNC_INFO;
515     IEditor *editor = context ? qobject_cast<IEditor*>(context) : 0;
516     if (editor) {
517         setCurrentEditor(editor);
518     } else {
519         updateActions();
520     }
521 }
522
523 void EditorManager::setCurrentEditor(IEditor *editor, bool ignoreNavigationHistory)
524 {
525     if (editor)
526         setCurrentView(0);
527
528     if (m_d->m_currentEditor == editor)
529         return;
530     if (m_d->m_currentEditor && !ignoreNavigationHistory)
531         addCurrentPositionToNavigationHistory();
532
533     m_d->m_currentEditor = editor;
534     if (editor) {
535         if (SplitterOrView *splitterOrView = m_d->m_splitter->findView(editor))
536             splitterOrView->view()->setCurrentEditor(editor);
537         m_d->m_view->updateEditorHistory(editor); // the global view should have a complete history
538     }
539     updateActions();
540     updateWindowTitle();
541     emit currentEditorChanged(editor);
542 }
543
544
545 void EditorManager::setCurrentView(Core::Internal::SplitterOrView *view)
546 {
547     if (view == m_d->m_currentView)
548         return;
549
550     SplitterOrView *old = m_d->m_currentView;
551     m_d->m_currentView = view;
552
553     if (old)
554         old->update();
555     if (view)
556         view->update();
557
558     if (view && !view->editor())
559         view->setFocus();
560 }
561
562 Core::Internal::SplitterOrView *EditorManager::currentSplitterOrView() const
563 {
564     SplitterOrView *view = m_d->m_currentView;
565     if (!view)
566         view = m_d->m_currentEditor?
567                m_d->m_splitter->findView(m_d->m_currentEditor):
568                m_d->m_splitter->findFirstView();
569     if (!view)
570         return m_d->m_splitter;
571     return view;
572 }
573
574 Core::Internal::EditorView *EditorManager::currentEditorView() const
575 {
576     return currentSplitterOrView()->view();
577 }
578
579 QList<IEditor *> EditorManager::editorsForFileName(const QString &filename) const
580 {
581     QList<IEditor *> found;
582     QString fixedname = FileManager::fixFileName(filename, FileManager::KeepLinks);
583     foreach (IEditor *editor, openedEditors()) {
584         if (fixedname == FileManager::fixFileName(editor->file()->fileName(), FileManager::KeepLinks))
585             found << editor;
586     }
587     return found;
588 }
589
590 QList<IEditor *> EditorManager::editorsForFile(IFile *file) const
591 {
592     QList<IEditor *> found;
593     foreach (IEditor *editor, openedEditors()) {
594         if (editor->file() == file)
595             found << editor;
596     }
597     return found;
598 }
599
600 IEditor *EditorManager::currentEditor() const
601 {
602     return m_d->m_currentEditor;
603 }
604
605 void EditorManager::emptyView(Core::Internal::EditorView *view)
606 {
607     if (!view)
608         return;
609
610     QList<IEditor *> editors = view->editors();
611     foreach (IEditor *editor, editors) {
612         if (!m_d->m_editorModel->isDuplicate(editor)) {
613             editors.removeAll(editor);
614             view->removeEditor(editor);
615             continue;
616         }
617         emit editorAboutToClose(editor);
618         removeEditor(editor);
619         view->removeEditor(editor);
620     }
621     emit editorsClosed(editors);
622     foreach (IEditor *editor, editors) {
623         delete editor;
624     }
625 }
626
627 void EditorManager::closeView(Core::Internal::EditorView *view)
628 {
629     if (!view)
630         return;
631
632     if (view == m_d->m_view) {
633         if (IEditor *e = view->currentEditor())
634             closeEditors(QList<IEditor *>() << e);
635         return;
636     }
637
638     if (IEditor *e = view->currentEditor()) {
639         /*
640            when we are closing a view with an original editor which has
641            duplicates, then make one of the duplicates the original.
642            Otherwise the original would be kept around and the user might
643            experience jumping to a missleading position within the file when
644            visiting the file again. With the code below, the position within
645            the file will be the position of the first duplicate which is still
646            around.
647         */
648         if (!m_d->m_editorModel->isDuplicate(e)) {
649             QList<IEditor *> duplicates = m_d->m_editorModel->duplicatesFor(e);
650             if (!duplicates.isEmpty()) {
651                 m_d->m_editorModel->makeOriginal(duplicates.first());
652             }
653         }
654     }
655
656     emptyView(view);
657
658     SplitterOrView *splitterOrView = m_d->m_splitter->findView(view);
659     Q_ASSERT(splitterOrView);
660     Q_ASSERT(splitterOrView->view() == view);
661     SplitterOrView *splitter = m_d->m_splitter->findSplitter(splitterOrView);
662     Q_ASSERT(splitterOrView->hasEditors() == false);
663     splitterOrView->hide();
664     delete splitterOrView;
665
666     splitter->unsplit();
667
668     SplitterOrView *newCurrent = splitter->findFirstView();
669     if (newCurrent) {
670         if (IEditor *e = newCurrent->editor()) {
671             activateEditor(newCurrent->view(), e);
672         } else {
673             setCurrentView(newCurrent);
674         }
675     }
676 }
677
678 QList<IEditor*>
679     EditorManager::editorsForFiles(QList<IFile*> files) const
680 {
681     const QList<IEditor *> editors = openedEditors();
682     QSet<IEditor *> found;
683     foreach (IFile *file, files) {
684         foreach (IEditor *editor, editors) {
685             if (editor->file() == file && !found.contains(editor)) {
686                     found << editor;
687             }
688         }
689     }
690     return found.toList();
691 }
692
693 QList<IFile *> EditorManager::filesForEditors(QList<IEditor *> editors) const
694 {
695     QSet<IEditor *> handledEditors;
696     QList<IFile *> files;
697     foreach (IEditor *editor, editors) {
698         if (!handledEditors.contains(editor)) {
699             files << editor->file();
700             handledEditors.insert(editor);
701         }
702     }
703     return files;
704 }
705
706 bool EditorManager::closeAllEditors(bool askAboutModifiedEditors)
707 {
708     m_d->m_editorModel->removeAllRestoredEditors();
709     if (closeEditors(openedEditors(), askAboutModifiedEditors)) {
710 //        m_d->clearNavigationHistory();
711         return true;
712     }
713     return false;
714 }
715
716 void EditorManager::closeOtherEditors(IEditor *editor)
717 {
718     m_d->m_editorModel->removeAllRestoredEditors();
719     QList<IEditor*> editors = openedEditors();
720     editors.removeAll(editor);
721     closeEditors(editors, true);
722 }
723
724 void EditorManager::closeOtherEditors()
725 {
726     IEditor *current = currentEditor();
727     QTC_ASSERT(current, return);
728     closeOtherEditors(current);
729 }
730
731 // SLOT connected to action
732 void EditorManager::closeEditor()
733 {
734     if (!m_d->m_currentEditor)
735         return;
736     addCurrentPositionToNavigationHistory();
737     closeEditor(m_d->m_currentEditor);
738 }
739
740 void EditorManager::closeEditor(Core::IEditor *editor)
741 {
742     if (!editor)
743         return;
744     closeEditors(QList<IEditor *>() << editor);
745 }
746
747 void EditorManager::closeEditor(const QModelIndex &index)
748 {
749     IEditor *editor = index.data(Qt::UserRole).value<Core::IEditor*>();
750     if (editor)
751         closeEditor(editor);
752     else
753         m_d->m_editorModel->removeEditor(index);
754 }
755
756 bool EditorManager::closeEditors(const QList<IEditor*> &editorsToClose, bool askAboutModifiedEditors)
757 {
758     if (editorsToClose.isEmpty())
759         return true;
760
761     SplitterOrView *currentSplitterOrView = this->currentSplitterOrView();
762
763     bool closingFailed = false;
764     QList<IEditor*> acceptedEditors;
765     //ask all core listeners to check whether the editor can be closed
766     const QList<ICoreListener *> listeners =
767         pluginManager()->getObjects<ICoreListener>();
768     foreach (IEditor *editor, editorsToClose) {
769         bool editorAccepted = true;
770         if (m_d->m_editorModel->isDuplicate(editor))
771             editor = m_d->m_editorModel->originalForDuplicate(editor);
772         foreach (ICoreListener *listener, listeners) {
773             if (!listener->editorAboutToClose(editor)) {
774                 editorAccepted = false;
775                 closingFailed = true;
776                 break;
777             }
778         }
779         if (editorAccepted)
780             acceptedEditors.append(editor);
781     }
782     if (acceptedEditors.isEmpty())
783         return false;
784     //ask whether to save modified files
785     if (askAboutModifiedEditors) {
786         bool cancelled = false;
787         QList<IFile*> list = m_d->m_core->fileManager()->
788             saveModifiedFiles(filesForEditors(acceptedEditors), &cancelled);
789         if (cancelled)
790             return false;
791         if (!list.isEmpty()) {
792             closingFailed = true;
793             QSet<IEditor*> skipSet = editorsForFiles(list).toSet();
794             acceptedEditors = acceptedEditors.toSet().subtract(skipSet).toList();
795         }
796     }
797     if (acceptedEditors.isEmpty())
798         return false;
799
800     // add duplicates
801     foreach(IEditor *editor, acceptedEditors)
802         acceptedEditors += m_d->m_editorModel->duplicatesFor(editor);
803
804     QList<EditorView*> closedViews;
805
806     // remove the editors
807     foreach (IEditor *editor, acceptedEditors) {
808         emit editorAboutToClose(editor);
809         if (!editor->file()->fileName().isEmpty()
810                 && !editor->isTemporary()) {
811             QByteArray state = editor->saveState();
812             if (!state.isEmpty())
813                 m_d->m_editorStates.insert(editor->file()->fileName(), QVariant(state));
814         }
815
816         removeEditor(editor);
817         if (SplitterOrView *view = m_d->m_splitter->findView(editor)) {
818             if (editor == view->view()->currentEditor())
819                 closedViews += view->view();
820             view->view()->removeEditor(editor);
821         }
822     }
823
824     foreach (EditorView *view, closedViews) {
825         IEditor *newCurrent = view->currentEditor();
826         if (!newCurrent)
827             newCurrent = pickUnusedEditor();
828         if (newCurrent) {
829             activateEditor(view, newCurrent, NoActivate);
830         } else {
831             QModelIndex idx = m_d->m_editorModel->firstRestoredEditor();
832             if (idx.isValid())
833                 activateEditor(idx, view, NoActivate);
834         }
835     }
836
837     emit editorsClosed(acceptedEditors);
838
839     foreach (IEditor *editor, acceptedEditors) {
840         delete editor;
841     }
842
843     if (currentSplitterOrView) {
844         if (IEditor *editor = currentSplitterOrView->editor())
845             activateEditor(currentSplitterOrView->view(), editor);
846     }
847
848     if (!currentEditor()) {
849         emit currentEditorChanged(0);
850         updateActions();
851         updateWindowTitle();
852     }
853
854     return !closingFailed;
855 }
856
857 void EditorManager::closeDuplicate(Core::IEditor *editor)
858 {
859
860     IEditor *original = editor;
861     if (m_d->m_editorModel->isDuplicate(editor))
862         original= m_d->m_editorModel->originalForDuplicate(editor);
863     QList<IEditor *> duplicates = m_d->m_editorModel->duplicatesFor(original);
864
865     if (duplicates.isEmpty()) {
866         closeEditor(editor);
867         return;
868     }
869
870     if (original== editor)
871         m_d->m_editorModel->makeOriginal(duplicates.first());
872
873     SplitterOrView *currentSplitterOrView = this->currentSplitterOrView();
874
875     emit editorAboutToClose(editor);
876
877     if(m_d->m_splitter->findView(editor)) {
878         EditorView *view = m_d->m_splitter->findView(editor)->view();
879         removeEditor(editor);
880         view->removeEditor(editor);
881
882         IEditor *newCurrent = view->currentEditor();
883         if (!newCurrent)
884             newCurrent = pickUnusedEditor();
885         if (newCurrent) {
886             activateEditor(view, newCurrent, NoActivate);
887         } else {
888             QModelIndex idx = m_d->m_editorModel->firstRestoredEditor();
889             if (idx.isValid())
890                 activateEditor(idx, view, NoActivate);
891         }
892     }
893
894     emit editorsClosed(QList<IEditor*>() << editor);
895     delete editor;
896     if (currentSplitterOrView) {
897         if (IEditor *currentEditor = currentSplitterOrView->editor())
898             activateEditor(currentSplitterOrView->view(), currentEditor);
899     }
900 }
901
902 Core::IEditor *EditorManager::pickUnusedEditor() const
903 {
904     foreach (IEditor *editor, openedEditors()) {
905         SplitterOrView *view = m_d->m_splitter->findView(editor);
906         if (!view || view->editor() != editor)
907             return editor;
908     }
909     return 0;
910 }
911
912 Core::IEditor *EditorManager::activateEditor(const QModelIndex &index, Internal::EditorView *view, OpenEditorFlags flags)
913 {
914     IEditor *editor = index.data(Qt::UserRole).value<IEditor*>();
915     if (editor)  {
916         return activateEditor(view, editor, flags);
917     }
918
919     QString fileName = index.data(Qt::UserRole + 1).toString();
920     QString id = index.data(Qt::UserRole + 2).toString();
921     return openEditor(view, fileName, id, flags);
922 }
923
924 Core::IEditor *EditorManager::placeEditor(Core::Internal::EditorView *view, Core::IEditor *editor)
925 {
926     Q_ASSERT(view && editor);
927
928     if (view->currentEditor() && view->currentEditor()->file() == editor->file())
929         editor = view->currentEditor();
930
931     if (!view->hasEditor(editor)) {
932         bool duplicateSupported = editor->duplicateSupported();
933         if (SplitterOrView *sourceView = m_d->m_splitter->findView(editor)) {
934             if (editor != sourceView->editor() || !duplicateSupported) {
935                 sourceView->view()->removeEditor(editor);
936                 view->addEditor(editor);
937                 view->setCurrentEditor(editor);
938                 if (!sourceView->editor()) {
939                     if (IEditor *replacement = pickUnusedEditor()) {
940                         sourceView->view()->addEditor(replacement);
941                     }
942                 }
943                 return editor;
944             } else if (duplicateSupported) {
945                 editor = duplicateEditor(editor);
946                 Q_ASSERT(editor);
947                 m_d->m_editorModel->makeOriginal(editor);
948             }
949         }
950         view->addEditor(editor);
951     }
952     return editor;
953 }
954
955 Core::IEditor *EditorManager::activateEditor(Core::IEditor *editor, OpenEditorFlags flags)
956 {
957     return activateEditor(0, editor, flags);
958 }
959
960 Core::IEditor *EditorManager::activateEditor(Core::Internal::EditorView *view, Core::IEditor *editor, OpenEditorFlags flags)
961 {
962     if (!view)
963         view = currentEditorView();
964
965     Q_ASSERT(view);
966
967     if (!editor) {
968         if (!m_d->m_currentEditor)
969             setCurrentEditor(0, (flags & IgnoreNavigationHistory));
970         return 0;
971     }
972
973     editor = placeEditor(view, editor);
974
975     if (!(flags & NoActivate)) {
976         setCurrentEditor(editor, (flags & IgnoreNavigationHistory));
977         if (flags & ModeSwitch) {
978             switchToPreferedMode();
979         }
980         if (isVisible())
981             editor->widget()->setFocus();
982     }
983     return editor;
984 }
985
986 Core::IEditor *EditorManager::activateEditor(Core::Internal::EditorView *view, Core::IFile *file, OpenEditorFlags flags)
987 {
988     const QList<IEditor*> editors = editorsForFile(file);
989     if (editors.isEmpty())
990         return 0;
991
992     return activateEditor(view, editors.first(), flags);
993 }
994
995 /* For something that has a 'QStringList mimeTypes' (IEditorFactory
996  * or IExternalEditor), find the one best matching the mimetype passed in.
997  *  Recurse over the parent classes of the mimetype to find them. */
998 template <class EditorFactoryLike>
999 static void mimeTypeFactoryRecursion(const MimeDatabase *db,
1000                                      const MimeType &mimeType,
1001                                      const QList<EditorFactoryLike*> &allFactories,
1002                                      bool firstMatchOnly,
1003                                      QList<EditorFactoryLike*> *list)
1004 {
1005     typedef typename QList<EditorFactoryLike*>::const_iterator EditorFactoryLikeListConstIterator;
1006     // Loop factories to find type
1007     const QString type = mimeType.type();
1008     const EditorFactoryLikeListConstIterator fcend = allFactories.constEnd();
1009     for (EditorFactoryLikeListConstIterator fit = allFactories.constBegin(); fit != fcend; ++fit) {
1010         // Exclude duplicates when recursing over xml or C++ -> C -> text.
1011         EditorFactoryLike *factory = *fit;
1012         if (!list->contains(factory) && factory->mimeTypes().contains(type)) {
1013             list->push_back(*fit);
1014             if (firstMatchOnly)
1015                 return;
1016             break;
1017         }
1018     }
1019     // Any parent mime type classes? -> recurse
1020     QStringList parentTypes = mimeType.subClassesOf();
1021     if (parentTypes.empty())
1022         return;
1023     const QStringList::const_iterator pcend = parentTypes .constEnd();
1024     for (QStringList::const_iterator pit = parentTypes .constBegin(); pit != pcend; ++pit) {
1025         if (const MimeType parent = db->findByType(*pit))
1026             mimeTypeFactoryRecursion(db, parent, allFactories, firstMatchOnly, list);
1027     }
1028 }
1029
1030 EditorManager::EditorFactoryList
1031     EditorManager::editorFactories(const MimeType &mimeType, bool bestMatchOnly) const
1032 {
1033     EditorFactoryList rc;
1034     const EditorFactoryList allFactories = pluginManager()->getObjects<IEditorFactory>();
1035     mimeTypeFactoryRecursion(m_d->m_core->mimeDatabase(), mimeType, allFactories, bestMatchOnly, &rc);
1036     if (debugEditorManager)
1037         qDebug() << Q_FUNC_INFO << mimeType.type() << " returns " << rc;
1038     return rc;
1039 }
1040
1041 EditorManager::ExternalEditorList
1042         EditorManager::externalEditors(const MimeType &mimeType, bool bestMatchOnly) const
1043 {
1044     ExternalEditorList rc;
1045     const ExternalEditorList allEditors = pluginManager()->getObjects<IExternalEditor>();
1046     mimeTypeFactoryRecursion(m_d->m_core->mimeDatabase(), mimeType, allEditors, bestMatchOnly, &rc);
1047     if (debugEditorManager)
1048         qDebug() << Q_FUNC_INFO << mimeType.type() << " returns " << rc;
1049     return rc;
1050 }
1051
1052 /* For something that has a 'QString id' (IEditorFactory
1053  * or IExternalEditor), find the one matching a id. */
1054 template <class EditorFactoryLike>
1055         inline EditorFactoryLike *findById(ExtensionSystem::PluginManager *pm,
1056                                              const QString &id)
1057 {
1058     const QList<EditorFactoryLike *> factories = pm->template getObjects<EditorFactoryLike>();
1059     foreach(EditorFactoryLike *efl, factories)
1060         if (id == efl->id())
1061             return efl;
1062     return 0;
1063 }
1064
1065 IEditor *EditorManager::createEditor(const QString &editorId,
1066                                      const QString &fileName)
1067 {
1068     if (debugEditorManager)
1069         qDebug() << Q_FUNC_INFO << editorId << fileName;
1070
1071     EditorFactoryList factories;
1072     if (editorId.isEmpty()) {
1073         const QFileInfo fileInfo(fileName);
1074         // Find by mime type
1075         MimeType mimeType = m_d->m_core->mimeDatabase()->findByFile(fileInfo);
1076         if (!mimeType) {
1077             qWarning("%s unable to determine mime type of %s/%s. Falling back to text/plain",
1078                      Q_FUNC_INFO, fileName.toUtf8().constData(), editorId.toUtf8().constData());
1079             mimeType = m_d->m_core->mimeDatabase()->findByType(QLatin1String("text/plain"));
1080         }
1081         // open text files > 48 MB in binary editor
1082         if (fileInfo.size() >  maxTextFileSize() && mimeType.type().startsWith(QLatin1String("text")))
1083             mimeType = m_d->m_core->mimeDatabase()->findByType(QLatin1String("application/octet-stream"));
1084         factories = editorFactories(mimeType, true);
1085     } else {
1086         // Find by editor id
1087         if (IEditorFactory *factory = findById<IEditorFactory>(pluginManager(), editorId))
1088             factories.push_back(factory);
1089     }
1090     if (factories.empty()) {
1091         qWarning("%s: unable to find an editor factory for the file '%s', editor Id '%s'.",
1092                  Q_FUNC_INFO, fileName.toUtf8().constData(), editorId.toUtf8().constData());
1093         return 0;
1094     }
1095
1096     IEditor *editor = factories.front()->createEditor(this);
1097     if (editor)
1098         connect(editor, SIGNAL(changed()), this, SLOT(handleEditorStateChange()));
1099     if (editor)
1100         emit editorCreated(editor, fileName);
1101     return editor;
1102 }
1103
1104 void EditorManager::addEditor(IEditor *editor, bool isDuplicate)
1105 {
1106     if (!editor)
1107         return;
1108     m_d->m_core->addContextObject(editor);
1109
1110     m_d->m_editorModel->addEditor(editor, isDuplicate);
1111     if (!isDuplicate) {
1112         const bool isTemporary = editor->isTemporary();
1113         const bool addWatcher = !isTemporary;
1114         m_d->m_core->fileManager()->addFile(editor->file(), addWatcher);
1115         if (!isTemporary)
1116             m_d->m_core->fileManager()->addToRecentFiles(editor->file()->fileName());
1117     }
1118     emit editorOpened(editor);
1119 }
1120
1121 // Run the OpenWithDialog and return the editor id
1122 // selected by the user.
1123 QString EditorManager::getOpenWithEditorId(const QString &fileName,
1124                                            bool *isExternalEditor) const
1125 {
1126     // Collect editors that can open the file
1127     const MimeType mt = m_d->m_core->mimeDatabase()->findByFile(fileName);
1128     if (!mt)
1129         return QString();
1130     QStringList allEditorIds;
1131     QStringList externalEditorIds;
1132     // Built-in
1133     const EditorFactoryList editors = editorFactories(mt, false);
1134     const int size = editors.size();
1135     for (int i = 0; i < size; i++) {
1136         allEditorIds.push_back(editors.at(i)->id());
1137     }
1138     // External editors
1139     const ExternalEditorList exEditors = externalEditors(mt, false);
1140     const int esize = exEditors.size();
1141     for (int i = 0; i < esize; i++) {
1142         externalEditorIds.push_back(exEditors.at(i)->id());
1143         allEditorIds.push_back(exEditors.at(i)->id());
1144     }
1145     if (allEditorIds.empty())
1146         return QString();
1147     // Run dialog.
1148     OpenWithDialog dialog(fileName, m_d->m_core->mainWindow());
1149     dialog.setEditors(allEditorIds);
1150     dialog.setCurrentEditor(0);
1151     if (dialog.exec() != QDialog::Accepted)
1152         return QString();
1153     const QString selectedId = dialog.editor();
1154     if (isExternalEditor)
1155         *isExternalEditor = externalEditorIds.contains(selectedId);
1156     return selectedId;
1157 }
1158
1159 IEditor *EditorManager::openEditor(const QString &fileName, const QString &editorId,
1160                                    OpenEditorFlags flags, bool *newEditor)
1161 {
1162     return openEditor(0, fileName, editorId, flags, newEditor);
1163 }
1164
1165 int extractLineNumber(QString *fileName)
1166 {
1167     int i = fileName->length() - 1;
1168     for (; i >= 0; --i) {
1169         if (!fileName->at(i).isNumber())
1170             break;
1171     }
1172     if (i == -1)
1173         return -1;
1174     if (fileName->at(i) == ':' || fileName->at(i) == '+') {
1175         int result = fileName->mid(i+1).toInt();
1176         *fileName = fileName->left(i);
1177         return result;
1178     }
1179     return -1;
1180 }
1181
1182 IEditor *EditorManager::openEditor(Core::Internal::EditorView *view, const QString &fileName,
1183                         const QString &editorId, OpenEditorFlags flags, bool *newEditor)
1184 {
1185     if (debugEditorManager)
1186         qDebug() << Q_FUNC_INFO << fileName << editorId;
1187
1188     QString fn = fileName;
1189     int lineNumber = -1;
1190     if (flags && EditorManager::CanContainLineNumber)
1191         lineNumber = extractLineNumber(&fn);
1192
1193     if (fn.isEmpty())
1194         return 0;
1195
1196     if (newEditor)
1197         *newEditor = false;
1198
1199     const QList<IEditor *> editors = editorsForFileName(fn);
1200     if (!editors.isEmpty()) {
1201         IEditor *editor = editors.first();
1202         if (flags && EditorManager::CanContainLineNumber)
1203             editor->gotoLine(lineNumber, -1);
1204         return activateEditor(view, editor, flags);
1205     }
1206
1207     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1208     IEditor *editor = createEditor(editorId, fn);
1209     // If we could not open the file in the requested editor, fall
1210     // back to the default editor:
1211     if (!editor)
1212         editor = createEditor(QString(), fn);
1213     if (!editor || !editor->open(fn)) {
1214         QApplication::restoreOverrideCursor();
1215         QMessageBox::critical(m_d->m_core->mainWindow(), tr("Opening File"), tr("Cannot open file %1!").arg(QDir::toNativeSeparators(fn)));
1216         delete editor;
1217         editor = 0;
1218         return 0;
1219     }
1220     addEditor(editor);
1221
1222     if (newEditor)
1223         *newEditor = true;
1224
1225     IEditor *result = activateEditor(view, editor, flags);
1226     if (editor == result)
1227         restoreEditorState(editor);
1228
1229     if (flags && EditorManager::CanContainLineNumber)
1230         editor->gotoLine(lineNumber, -1);
1231
1232     QApplication::restoreOverrideCursor();
1233     return result;
1234 }
1235
1236 bool EditorManager::openExternalEditor(const QString &fileName, const QString &editorId)
1237 {
1238     IExternalEditor *ee = findById<IExternalEditor>(pluginManager(), editorId);
1239     if (!ee)
1240         return false;
1241     QString errorMessage;
1242     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1243     const bool ok = ee->startEditor(fileName, &errorMessage);
1244     QApplication::restoreOverrideCursor();
1245     if (!ok)
1246         QMessageBox::critical(m_d->m_core->mainWindow(), tr("Opening File"), errorMessage);
1247     return ok;
1248 }
1249
1250 QStringList EditorManager::getOpenFileNames() const
1251 {
1252     QString selectedFilter;
1253     const QString &fileFilters = m_d->m_core->mimeDatabase()->allFiltersString(&selectedFilter);
1254     return ICore::instance()->fileManager()->getOpenFileNames(fileFilters,
1255                                                               QString(), &selectedFilter);
1256 }
1257
1258
1259 /// Empty mode == figure out the correct mode from the editor
1260 /// forcePrefered = true, switch to the mode even if the editor is visible in another mode
1261 /// forcePrefered = false, only switch if it is not visible
1262 void EditorManager::switchToPreferedMode()
1263 {
1264     QString preferedMode;
1265     // Figure out preferred mode for editor
1266     if (m_d->m_currentEditor)
1267         preferedMode = m_d->m_currentEditor->preferredModeType();
1268
1269     if (preferedMode.isEmpty())
1270         preferedMode = Constants::MODE_EDIT_TYPE;
1271
1272     m_d->m_core->modeManager()->activateModeType(preferedMode);
1273 }
1274
1275 IEditor *EditorManager::openEditorWithContents(const QString &editorId,
1276                                         QString *titlePattern,
1277                                         const QString &contents)
1278 {
1279     if (debugEditorManager)
1280         qDebug() << Q_FUNC_INFO << editorId << titlePattern << contents;
1281
1282     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1283
1284     QString title;
1285     if (titlePattern) {
1286         const QChar dollar = QLatin1Char('$');
1287
1288         QString base = *titlePattern;
1289         if (base.isEmpty())
1290             base = QLatin1String("unnamed$");
1291         if (base.contains(dollar)) {
1292             int i = 1;
1293             QSet<QString> docnames;
1294             foreach (IEditor *editor, openedEditors()) {
1295                 QString name = editor->file()->fileName();
1296                 if (name.isEmpty()) {
1297                     name = editor->displayName();
1298                 } else {
1299                     name = QFileInfo(name).completeBaseName();
1300                 }
1301                 docnames << name;
1302             }
1303
1304             do {
1305                 title = base;
1306                 title.replace(QString(dollar), QString::number(i++));
1307             } while (docnames.contains(title));
1308         } else {
1309             title = *titlePattern;
1310         }
1311         *titlePattern = title;
1312     }
1313
1314     IEditor *edt = createEditor(editorId, title);
1315     if (!edt) {
1316         QApplication::restoreOverrideCursor();
1317         return 0;
1318     }
1319
1320     if (!edt->createNew(contents)) {
1321         QApplication::restoreOverrideCursor();
1322         delete edt;
1323         edt = 0;
1324         return 0;
1325     }
1326
1327     if (title.isEmpty())
1328         title = edt->displayName();
1329
1330     edt->setDisplayName(title);
1331     addEditor(edt);
1332     QApplication::restoreOverrideCursor();
1333     return edt;
1334 }
1335
1336 bool EditorManager::hasEditor(const QString &fileName) const
1337 {
1338     return !editorsForFileName(fileName).isEmpty();
1339 }
1340
1341 void EditorManager::restoreEditorState(IEditor *editor)
1342 {
1343     QTC_ASSERT(editor, return);
1344     QString fileName = editor->file()->fileName();
1345     editor->restoreState(m_d->m_editorStates.value(fileName).toByteArray());
1346 }
1347
1348 bool EditorManager::saveEditor(IEditor *editor)
1349 {
1350     return saveFile(editor->file());
1351 }
1352
1353 bool EditorManager::saveFile(IFile *fileParam)
1354 {
1355     IFile *file = fileParam;
1356     if (!file && currentEditor())
1357         file = currentEditor()->file();
1358     if (!file)
1359         return false;
1360
1361     file->checkPermissions();
1362
1363     const QString &fileName = file->fileName();
1364
1365     if (fileName.isEmpty())
1366         return saveFileAs(file);
1367
1368     bool success = false;
1369
1370     // try saving, no matter what isReadOnly tells us
1371     m_d->m_core->fileManager()->blockFileChange(file);
1372     success = file->save(fileName);
1373     m_d->m_core->fileManager()->unblockFileChange(file);
1374
1375     if (!success) {
1376         MakeWritableResult answer =
1377                 makeFileWritable(file);
1378         if (answer == Failed)
1379             return false;
1380         if (answer == SavedAs)
1381             return true;
1382
1383         file->checkPermissions();
1384
1385         m_d->m_core->fileManager()->blockFileChange(file);
1386         success = file->save(fileName);
1387         m_d->m_core->fileManager()->unblockFileChange(file);
1388     }
1389
1390     if (success) {
1391         addFileToRecentFiles(file);
1392     }
1393
1394     return success;
1395 }
1396
1397 MakeWritableResult
1398 EditorManager::makeFileWritable(IFile *file)
1399 {
1400     if (!file)
1401         return Failed;
1402     QString directory = QFileInfo(file->fileName()).absolutePath();
1403     IVersionControl *versionControl = m_d->m_core->vcsManager()->findVersionControlForDirectory(directory);
1404     const QString &fileName = file->fileName();
1405
1406     switch (FileManager::promptReadOnlyFile(fileName, versionControl, m_d->m_core->mainWindow(), file->isSaveAsAllowed())) {
1407     case FileManager::RO_OpenVCS:
1408         if (!versionControl->vcsOpen(fileName)) {
1409             QMessageBox::warning(m_d->m_core->mainWindow(), tr("Failed!"), tr("Could not open the file for editing with SCC."));
1410             return Failed;
1411         }
1412         file->checkPermissions();
1413         return OpenedWithVersionControl;
1414     case FileManager::RO_MakeWriteable: {
1415         const bool permsOk = QFile::setPermissions(fileName, QFile::permissions(fileName) | QFile::WriteUser);
1416         if (!permsOk) {
1417             QMessageBox::warning(m_d->m_core->mainWindow(), tr("Failed!"),  tr("Could not set permissions to writable."));
1418             return Failed;
1419         }
1420     }
1421         file->checkPermissions();
1422         return MadeWritable;
1423     case FileManager::RO_SaveAs :
1424         return saveFileAs(file) ? SavedAs : Failed;
1425     case FileManager::RO_Cancel:
1426         break;
1427     }
1428     return Failed;
1429 }
1430
1431 bool EditorManager::saveFileAs(IFile *fileParam)
1432 {
1433     IFile *file = fileParam;
1434     if (!file && currentEditor())
1435         file = currentEditor()->file();
1436     if (!file)
1437         return false;
1438
1439     const QString &filter = m_d->m_core->mimeDatabase()->allFiltersString();
1440     QString selectedFilter =
1441         m_d->m_core->mimeDatabase()->findByFile(QFileInfo(file->fileName())).filterString();
1442     const QString &absoluteFilePath =
1443         m_d->m_core->fileManager()->getSaveAsFileName(file, filter, &selectedFilter);
1444
1445     if (absoluteFilePath.isEmpty())
1446         return false;
1447
1448     if (absoluteFilePath != file->fileName()) {
1449         // close existing editors for the new file name
1450         const QList<IEditor *> existList = editorsForFileName(absoluteFilePath);
1451         if (!existList.isEmpty()) {
1452             closeEditors(existList, false);
1453         }
1454     }
1455
1456     m_d->m_core->fileManager()->blockFileChange(file);
1457     const bool success = file->save(absoluteFilePath);
1458     m_d->m_core->fileManager()->unblockFileChange(file);
1459     file->checkPermissions();
1460
1461     // @todo: There is an issue to be treated here. The new file might be of a different mime
1462     // type than the original and thus require a different editor. An alternative strategy
1463     // would be to close the current editor and open a new appropriate one, but this is not
1464     // a good way out either (also the undo stack would be lost). Perhaps the best is to
1465     // re-think part of the editors design.
1466
1467     if (success) {
1468         addFileToRecentFiles(file);
1469     }
1470     updateActions();
1471     return success;
1472 }
1473
1474 /* Adds the file name to the recent files if there is at least one non-temporary editor for it */
1475 void EditorManager::addFileToRecentFiles(IFile *file)
1476 {
1477     bool isTemporary = true;
1478     QList<IEditor *> editors = editorsForFile(file);
1479     foreach (IEditor *editor, editors) {
1480         if (!editor->isTemporary()) {
1481             isTemporary = false;
1482             break;
1483         }
1484     }
1485     if (!isTemporary)
1486         m_d->m_core->fileManager()->addToRecentFiles(file->fileName());
1487 }
1488
1489 void EditorManager::gotoNextDocHistory()
1490 {
1491     OpenEditorsWindow *dialog = windowPopup();
1492     if (dialog->isVisible()) {
1493         dialog->selectNextEditor();
1494     } else {
1495         EditorView *view = currentEditorView();
1496         dialog->setEditors(m_d->m_view, view, m_d->m_editorModel);
1497         dialog->selectNextEditor();
1498         showPopupOrSelectDocument();
1499     }
1500 }
1501
1502 void EditorManager::gotoPreviousDocHistory()
1503 {
1504     OpenEditorsWindow *dialog = windowPopup();
1505     if (dialog->isVisible()) {
1506         dialog->selectPreviousEditor();
1507     } else {
1508         EditorView *view = currentEditorView();
1509         dialog->setEditors(m_d->m_view, view, m_d->m_editorModel);
1510         dialog->selectPreviousEditor();
1511         showPopupOrSelectDocument();
1512     }
1513 }
1514
1515 void EditorManager::makeCurrentEditorWritable()
1516 {
1517     if (IEditor* curEditor = currentEditor())
1518         makeFileWritable(curEditor->file());
1519 }
1520
1521 void EditorManager::updateWindowTitle()
1522 {
1523     QString windowTitle = tr("Qt Creator");
1524     if (!m_d->m_titleAddition.isEmpty()) {
1525         windowTitle.prepend(m_d->m_titleAddition + " - ");
1526     }
1527     IEditor *curEditor = currentEditor();
1528     if (curEditor) {
1529         QString editorName = curEditor->displayName();
1530         if (!editorName.isEmpty())
1531             windowTitle.prepend(editorName + " - ");
1532         QString filePath = QFileInfo(curEditor->file()->fileName()).absoluteFilePath();
1533         if (!filePath.isEmpty())
1534             m_d->m_core->mainWindow()->setWindowFilePath(filePath);
1535     } else {
1536         m_d->m_core->mainWindow()->setWindowFilePath(QString());
1537     }
1538     m_d->m_core->mainWindow()->setWindowTitle(windowTitle);
1539 }
1540
1541 void EditorManager::handleEditorStateChange()
1542 {
1543     updateActions();
1544     IEditor *currEditor = currentEditor();
1545     if (qobject_cast<IEditor *>(sender()) == currEditor) {
1546         updateWindowTitle();
1547         emit currentEditorStateChanged(currEditor);
1548     }
1549 }
1550
1551 void EditorManager::updateActions()
1552 {
1553     QString fName;
1554     IEditor *curEditor = currentEditor();
1555     int openedCount = openedEditors().count() + m_d->m_editorModel->restoredEditors().count();
1556
1557     if (curEditor) {
1558
1559         if (!curEditor->file()->fileName().isEmpty()) {
1560             QFileInfo fi(curEditor->file()->fileName());
1561             fName = fi.fileName();
1562         } else {
1563             fName = curEditor->displayName();
1564         }
1565
1566 #ifdef Q_WS_MAC
1567         window()->setWindowModified(curEditor->file()->isModified());
1568 #endif
1569         if (curEditor->file()->isModified() && curEditor->file()->isReadOnly()) {
1570             // we are about to change a read-only file, warn user
1571             showEditorInfoBar(QLatin1String("Core.EditorManager.MakeWritable"),
1572                 tr("<b>Warning:</b> You are changing a read-only file."),
1573                 tr("Make writable"), this, SLOT(makeCurrentEditorWritable()));
1574         } else {
1575             hideEditorInfoBar(QLatin1String("Core.EditorManager.MakeWritable"));
1576         }
1577 #ifdef Q_WS_MAC
1578     } else { // curEditor
1579         window()->setWindowModified(false);
1580 #endif
1581     }
1582
1583     m_d->m_saveAction->setEnabled(curEditor != 0 && curEditor->file()->isModified());
1584     m_d->m_saveAsAction->setEnabled(curEditor != 0 && curEditor->file()->isSaveAsAllowed());
1585     m_d->m_revertToSavedAction->setEnabled(curEditor != 0
1586         && !curEditor->file()->fileName().isEmpty() && curEditor->file()->isModified());
1587
1588     QString quotedName;
1589     if (!fName.isEmpty())
1590         quotedName = '"' + fName + '"';
1591
1592     m_d->m_saveAsAction->setText(tr("Save %1 &As...").arg(quotedName));
1593     m_d->m_saveAction->setText(tr("&Save %1").arg(quotedName));
1594     m_d->m_revertToSavedAction->setText(tr("Revert %1 to Saved").arg(quotedName));
1595
1596     m_d->m_closeCurrentEditorAction->setEnabled(curEditor != 0);
1597     m_d->m_closeCurrentEditorAction->setText(tr("Close %1").arg(quotedName));
1598     m_d->m_closeAllEditorsAction->setEnabled(openedCount > 0);
1599     m_d->m_closeOtherEditorsAction->setEnabled(openedCount > 1);
1600     m_d->m_closeOtherEditorsAction->setText((openedCount > 1 ? tr("Close All Except %1").arg(quotedName) : tr("Close Others")));
1601
1602     m_d->m_gotoNextDocHistoryAction->setEnabled(m_d->m_editorModel->rowCount() != 0);
1603     m_d->m_gotoPreviousDocHistoryAction->setEnabled(m_d->m_editorModel->rowCount() != 0);
1604     EditorView *view  = currentEditorView();
1605     m_d->m_goBackAction->setEnabled(view ? view->canGoBack() : false);
1606     m_d->m_goForwardAction->setEnabled(view ? view->canGoForward() : false);
1607
1608     bool hasSplitter = m_d->m_splitter->isSplitter();
1609     m_d->m_removeCurrentSplitAction->setEnabled(hasSplitter);
1610     m_d->m_removeAllSplitsAction->setEnabled(hasSplitter);
1611     m_d->m_gotoOtherSplitAction->setEnabled(hasSplitter);
1612
1613     m_d->m_openInExternalEditorAction->setEnabled(curEditor != 0);
1614 }
1615
1616 bool EditorManager::hasSplitter() const
1617 {
1618     return m_d->m_splitter->isSplitter();
1619 }
1620
1621 QList<IEditor*> EditorManager::openedEditors() const
1622 {
1623     return m_d->m_editorModel->editors();
1624 }
1625
1626 OpenEditorsModel *EditorManager::openedEditorsModel() const
1627 {
1628     return m_d->m_editorModel;
1629 }
1630
1631 void EditorManager::addCurrentPositionToNavigationHistory(IEditor *editor, const QByteArray &saveState)
1632 {
1633     currentEditorView()->addCurrentPositionToNavigationHistory(editor, saveState);
1634     updateActions();
1635 }
1636
1637 void EditorManager::cutForwardNavigationHistory()
1638 {
1639     currentEditorView()->cutForwardNavigationHistory();
1640     updateActions();
1641 }
1642
1643 void EditorManager::goBackInNavigationHistory()
1644 {
1645     currentEditorView()->goBackInNavigationHistory();
1646     updateActions();
1647     return;
1648 }
1649
1650 void EditorManager::goForwardInNavigationHistory()
1651 {
1652     currentEditorView()->goForwardInNavigationHistory();
1653     updateActions();
1654 }
1655
1656 OpenEditorsWindow *EditorManager::windowPopup() const
1657 {
1658     return m_d->m_windowPopup;
1659 }
1660
1661 void EditorManager::showPopupOrSelectDocument() const
1662 {
1663     if (QApplication::keyboardModifiers() == Qt::NoModifier) {
1664         windowPopup()->selectAndHide();
1665     } else {
1666         // EditorManager is invisible when invoked from Design Mode.
1667         const QPoint p = isVisible() ?
1668                          mapToGlobal(QPoint(0, 0)) :
1669                          m_d->m_core->mainWindow()->mapToGlobal(QPoint(0, 0));
1670         windowPopup()->move((width()-m_d->m_windowPopup->width())/2 + p.x(),
1671                             (height()-m_d->m_windowPopup->height())/2 + p.y());
1672         windowPopup()->setVisible(true);
1673     }
1674 }
1675
1676 // Save state of all non-teporary editors.
1677 QByteArray EditorManager::saveState() const
1678 {
1679     QByteArray bytes;
1680     QDataStream stream(&bytes, QIODevice::WriteOnly);
1681
1682     stream << QByteArray("EditorManagerV4");
1683
1684     QList<IEditor *> editors = openedEditors();
1685     foreach (IEditor *editor, editors) {
1686         if (!editor->file()->fileName().isEmpty()
1687                 && !editor->isTemporary()) {
1688             QByteArray state = editor->saveState();
1689             if (!state.isEmpty())
1690                 m_d->m_editorStates.insert(editor->file()->fileName(), QVariant(state));
1691         }
1692     }
1693
1694     stream << m_d->m_editorStates;
1695
1696     QList<OpenEditorsModel::Entry> entries = m_d->m_editorModel->entries();
1697     int entriesCount = 0;
1698     foreach (const OpenEditorsModel::Entry &entry, entries) {
1699         // The editor may be 0 if it was not loaded yet: In that case it is not temporary
1700         if (!entry.editor || !entry.editor->isTemporary())
1701             ++entriesCount;
1702     }
1703
1704     stream << entriesCount;
1705
1706     foreach (const OpenEditorsModel::Entry &entry, entries) {
1707         if (!entry.editor || !entry.editor->isTemporary())
1708             stream << entry.fileName() << entry.displayName() << entry.id().toUtf8();
1709     }
1710
1711     stream << m_d->m_splitter->saveState();
1712
1713     return bytes;
1714 }
1715
1716 bool EditorManager::restoreState(const QByteArray &state)
1717 {
1718     closeAllEditors(true);
1719     removeAllSplits();
1720     QDataStream stream(state);
1721
1722     QByteArray version;
1723     stream >> version;
1724
1725     if (version != "EditorManagerV4")
1726         return false;
1727
1728     QMap<QString, QVariant> editorstates;
1729
1730     QApplication::setOverrideCursor(Qt::WaitCursor);
1731
1732     stream >> editorstates;
1733
1734     QMapIterator<QString, QVariant> i(editorstates);
1735     while (i.hasNext()) {
1736         i.next();
1737         m_d->m_editorStates.insert(i.key(), i.value());
1738     }
1739
1740     int editorCount = 0;
1741     stream >> editorCount;
1742     while (--editorCount >= 0) {
1743         QString fileName;
1744         stream >> fileName;
1745         QString displayName;
1746         stream >> displayName;
1747         QByteArray id;
1748         stream >> id;
1749
1750         if (!fileName.isEmpty() && !displayName.isEmpty())
1751             m_d->m_editorModel->addRestoredEditor(fileName, displayName, QString::fromUtf8(id));
1752     }
1753
1754     QByteArray splitterstates;
1755     stream >> splitterstates;
1756     m_d->m_splitter->restoreState(splitterstates);
1757
1758     // splitting and stuff results in focus trouble, that's why we set the focus again after restoration
1759     if (m_d->m_currentEditor) {
1760         m_d->m_currentEditor->widget()->setFocus();
1761     } else if (Core::Internal::SplitterOrView *view = currentSplitterOrView()) {
1762         if (IEditor *e = view->editor())
1763             e->widget()->setFocus();
1764         else if (view->view())
1765             view->view()->setFocus();
1766     }
1767
1768     QApplication::restoreOverrideCursor();
1769
1770     return true;
1771 }
1772
1773 static const char * const documentStatesKey = "EditorManager/DocumentStates";
1774 static const char * const externalEditorKey = "EditorManager/ExternalEditorCommand";
1775 static const char * const reloadBehaviorKey = "EditorManager/ReloadBehavior";
1776 static const char * const utf8BomBehaviorKey = "EditorManager/Utf8BomBehavior";
1777
1778 void EditorManager::saveSettings()
1779 {
1780     SettingsDatabase *settings = m_d->m_core->settingsDatabase();
1781     settings->setValue(QLatin1String(documentStatesKey), m_d->m_editorStates);
1782     settings->setValue(QLatin1String(externalEditorKey), m_d->m_externalEditor);
1783     settings->setValue(QLatin1String(reloadBehaviorKey), m_d->m_reloadSetting);
1784     settings->setValue(QLatin1String(utf8BomBehaviorKey), m_d->m_utf8BomSetting);
1785 }
1786
1787 void EditorManager::readSettings()
1788 {
1789     // Backward compatibility to old locations for these settings
1790     QSettings *qs = m_d->m_core->settings();
1791     if (qs->contains(QLatin1String(documentStatesKey))) {
1792         m_d->m_editorStates = qs->value(QLatin1String(documentStatesKey))
1793             .value<QMap<QString, QVariant> >();
1794         qs->remove(QLatin1String(documentStatesKey));
1795     }
1796     if (qs->contains(QLatin1String(externalEditorKey))) {
1797         m_d->m_externalEditor = qs->value(QLatin1String(externalEditorKey)).toString();
1798         qs->remove(QLatin1String(externalEditorKey));
1799     }
1800
1801     SettingsDatabase *settings = m_d->m_core->settingsDatabase();
1802     if (settings->contains(QLatin1String(documentStatesKey)))
1803         m_d->m_editorStates = settings->value(QLatin1String(documentStatesKey))
1804             .value<QMap<QString, QVariant> >();
1805     if (settings->contains(QLatin1String(externalEditorKey)))
1806         m_d->m_externalEditor = settings->value(QLatin1String(externalEditorKey)).toString();
1807
1808     if (settings->contains(QLatin1String(reloadBehaviorKey)))
1809         m_d->m_reloadSetting = (IFile::ReloadSetting)settings->value(QLatin1String(reloadBehaviorKey)).toInt();
1810
1811     if (settings->contains(QLatin1String(utf8BomBehaviorKey)))
1812         m_d->m_utf8BomSetting = (IFile::Utf8BomSetting)settings->value(QLatin1String(utf8BomBehaviorKey)).toInt();
1813 }
1814
1815
1816 void EditorManager::revertToSaved()
1817 {
1818     IEditor *currEditor = currentEditor();
1819     if (!currEditor)
1820         return;
1821     const QString fileName =  currEditor->file()->fileName();
1822     if (fileName.isEmpty())
1823         return;
1824     if (currEditor->file()->isModified()) {
1825         QMessageBox msgBox(QMessageBox::Question, tr("Revert to Saved"),
1826                            tr("You will lose your current changes if you proceed reverting %1.").arg(QDir::toNativeSeparators(fileName)),
1827                            QMessageBox::Yes|QMessageBox::No, m_d->m_core->mainWindow());
1828         msgBox.button(QMessageBox::Yes)->setText(tr("Proceed"));
1829         msgBox.button(QMessageBox::No)->setText(tr("Cancel"));
1830         msgBox.setDefaultButton(QMessageBox::No);
1831         msgBox.setEscapeButton(QMessageBox::No);
1832         if (msgBox.exec() == QMessageBox::No)
1833             return;
1834
1835     }
1836     currEditor->file()->reload(IFile::FlagReload, IFile::TypeContents);
1837 }
1838
1839 void EditorManager::showEditorInfoBar(const QString &id,
1840                                       const QString &infoText,
1841                                       const QString &buttonText,
1842                                       QObject *object, const char *buttonPressMember,
1843                                       const char *cancelButtonPressMember)
1844 {
1845     currentEditorView()->showEditorInfoBar(id, infoText, buttonText, object, buttonPressMember, cancelButtonPressMember);
1846 }
1847
1848
1849 void EditorManager::hideEditorInfoBar(const QString &id)
1850 {
1851     Core::Internal::EditorView *cev = currentEditorView();
1852     if (cev)
1853         cev->hideEditorInfoBar(id);
1854 }
1855
1856 void EditorManager::showEditorStatusBar(const QString &id,
1857                                       const QString &infoText,
1858                                       const QString &buttonText,
1859                                       QObject *object, const char *member)
1860 {
1861
1862     currentEditorView()->showEditorStatusBar(id, infoText, buttonText, object, member);
1863 }
1864
1865 void EditorManager::hideEditorStatusBar(const QString &id)
1866 {
1867     currentEditorView()->hideEditorStatusBar(id);
1868 }
1869
1870 QString EditorManager::externalEditorHelpText() const
1871 {
1872     QString help = tr(
1873             "<table border=1 cellspacing=0 cellpadding=3>"
1874             "<tr><th>Variable</th><th>Expands to</th></tr>"
1875             "<tr><td>%f</td><td>file name</td></tr>"
1876             "<tr><td>%l</td><td>current line number</td></tr>"
1877             "<tr><td>%c</td><td>current column number</td></tr>"
1878             "<tr><td>%x</td><td>editor's x position on screen</td></tr>"
1879             "<tr><td>%y</td><td>editor's y position on screen</td></tr>"
1880             "<tr><td>%w</td><td>editor's width in pixels</td></tr>"
1881             "<tr><td>%h</td><td>editor's height in pixels</td></tr>"
1882             "<tr><td>%W</td><td>editor's width in characters</td></tr>"
1883             "<tr><td>%H</td><td>editor's height in characters</td></tr>"
1884             "<tr><td>%%</td><td>%</td></tr>"
1885             "</table>");
1886     return help;
1887 }
1888
1889 void EditorManager::openInExternalEditor()
1890 {
1891     QString command = m_d->m_externalEditor;
1892     if (command.isEmpty())
1893         command = defaultExternalEditor();
1894
1895     if (command.isEmpty())
1896         return;
1897
1898     IEditor *editor = currentEditor();
1899     if (!editor)
1900         return;
1901     if (editor->file()->isModified()) {
1902         bool cancelled = false;
1903         QList<IFile*> list = m_d->m_core->fileManager()->
1904                              saveModifiedFiles(QList<IFile*>() << editor->file(), &cancelled);
1905         if (cancelled)
1906             return;
1907     }
1908
1909     QRect rect = editor->widget()->rect();
1910     QFont font = editor->widget()->font();
1911     QFontMetrics fm(font);
1912     rect.moveTo(editor->widget()->mapToGlobal(QPoint(0,0)));
1913
1914     QString pre = command;
1915     QString cmd;
1916     for (int i = 0; i < pre.size(); ++i) {
1917         QChar c = pre.at(i);
1918         if (c == QLatin1Char('%') && i < pre.size()-1) {
1919             c = pre.at(++i);
1920             QString s;
1921             if (c == QLatin1Char('f'))
1922                 s = editor->file()->fileName();
1923             else if (c == QLatin1Char('l'))
1924                 s = QString::number(editor->currentLine());
1925             else if (c == QLatin1Char('c'))
1926                 s = QString::number(editor->currentColumn());
1927             else if (c == QLatin1Char('x'))
1928                 s = QString::number(rect.x());
1929             else if (c == QLatin1Char('y'))
1930                 s = QString::number(rect.y());
1931             else if (c == QLatin1Char('w'))
1932                 s = QString::number(rect.width());
1933             else if (c == QLatin1Char('h'))
1934                 s = QString::number(rect.height());
1935             else if (c == QLatin1Char('W'))
1936                 s = QString::number(rect.width() / fm.width(QLatin1Char('x')));
1937             else if (c == QLatin1Char('H'))
1938                 s = QString::number(rect.height() / fm.lineSpacing());
1939             else if (c == QLatin1Char('%'))
1940                 s = c;
1941             else {
1942                 s = QLatin1Char('%');
1943                 s += c;
1944             }
1945             cmd += s;
1946             continue;
1947
1948         }
1949         cmd += c;
1950     }
1951
1952     QProcess::startDetached(cmd);
1953 }
1954
1955 void EditorManager::setExternalEditor(const QString &editor)
1956 {
1957     if (editor.isEmpty() || editor == defaultExternalEditor())
1958         m_d->m_externalEditor = defaultExternalEditor();
1959     else
1960         m_d->m_externalEditor = editor;
1961 }
1962
1963 QString EditorManager::externalEditor() const
1964 {
1965     if (m_d->m_externalEditor.isEmpty())
1966         return defaultExternalEditor();
1967     return m_d->m_externalEditor;
1968 }
1969
1970 void EditorManager::setReloadSetting(IFile::ReloadSetting behavior)
1971 {
1972     m_d->m_reloadSetting = behavior;
1973 }
1974
1975 IFile::ReloadSetting EditorManager::reloadSetting() const
1976 {
1977     return m_d->m_reloadSetting;
1978 }
1979
1980 void EditorManager::setUtf8BomSetting(IFile::Utf8BomSetting behavior)
1981 {
1982     m_d->m_utf8BomSetting = behavior;
1983 }
1984
1985 IFile::Utf8BomSetting EditorManager::utf8BomSetting() const
1986 {
1987     return m_d->m_utf8BomSetting;
1988 }
1989
1990 QTextCodec *EditorManager::defaultTextEncoding() const
1991 {
1992     QSettings *settings = Core::ICore::instance()->settings();
1993     if (QTextCodec *candidate = QTextCodec::codecForName(
1994             settings->value(QLatin1String(Constants::SETTINGS_DEFAULTTEXTENCODING)).toByteArray()))
1995         return candidate;
1996     return QTextCodec::codecForLocale();
1997 }
1998
1999 Core::IEditor *EditorManager::duplicateEditor(Core::IEditor *editor)
2000 {
2001     if (!editor->duplicateSupported())
2002         return 0;
2003
2004     IEditor *duplicate = editor->duplicate(0);
2005     duplicate->restoreState(editor->saveState());
2006     connect(duplicate, SIGNAL(changed()), this, SLOT(handleEditorStateChange()));
2007     emit editorCreated(duplicate, duplicate->file()->fileName());
2008     addEditor(duplicate, true);
2009     return duplicate;
2010 }
2011
2012 void EditorManager::split(Qt::Orientation orientation)
2013 {
2014     SplitterOrView *view = m_d->m_currentView;
2015     if (!view)
2016             view = m_d->m_currentEditor ? m_d->m_splitter->findView(m_d->m_currentEditor)
2017                        : m_d->m_splitter->findFirstView();
2018     if (view && !view->splitter()) {
2019         view->split(orientation);
2020     }
2021     updateActions();
2022 }
2023
2024 void EditorManager::split()
2025 {
2026     split(Qt::Vertical);
2027 }
2028
2029 void EditorManager::splitSideBySide()
2030 {
2031     split(Qt::Horizontal);
2032 }
2033
2034 void EditorManager::removeCurrentSplit()
2035 {
2036     SplitterOrView *viewToClose = m_d->m_currentView;
2037     if (!viewToClose && m_d->m_currentEditor)
2038         viewToClose = m_d->m_splitter->findView(m_d->m_currentEditor);
2039
2040     if (!viewToClose || viewToClose->isSplitter() || viewToClose == m_d->m_splitter)
2041         return;
2042
2043     closeView(viewToClose->view());
2044     updateActions();
2045 }
2046
2047 void EditorManager::removeAllSplits()
2048 {
2049     if (!m_d->m_splitter->isSplitter())
2050         return;
2051     IEditor *editor = m_d->m_currentEditor;
2052     // trigger update below
2053     m_d->m_currentEditor = 0;
2054     if (editor && m_d->m_editorModel->isDuplicate(editor))
2055         m_d->m_editorModel->makeOriginal(editor);
2056     m_d->m_splitter->unsplitAll();
2057     if (!editor)
2058         editor = pickUnusedEditor();
2059     activateEditor(editor);
2060 }
2061
2062 void EditorManager::gotoOtherSplit()
2063 {
2064     if (m_d->m_splitter->isSplitter()) {
2065         SplitterOrView *currentView = m_d->m_currentView;
2066         if (!currentView && m_d->m_currentEditor)
2067             currentView = m_d->m_splitter->findView(m_d->m_currentEditor);
2068         if (!currentView)
2069             currentView = m_d->m_splitter->findFirstView();
2070         SplitterOrView *view = m_d->m_splitter->findNextView(currentView);
2071         if (!view)
2072             view = m_d->m_splitter->findFirstView();
2073         if (view) {
2074             if (IEditor *editor = view->editor()) {
2075                 setCurrentEditor(editor, true);
2076                 editor->widget()->setFocus();
2077             } else {
2078                 setCurrentView(view);
2079             }
2080         }
2081     }
2082 }
2083
2084 qint64 EditorManager::maxTextFileSize()
2085 {
2086     return (qint64(3) << 24);
2087 }
2088
2089 void EditorManager::setWindowTitleAddition(const QString &addition)
2090 {
2091     m_d->m_titleAddition = addition;
2092     updateWindowTitle();
2093 }
2094
2095 QString EditorManager::windowTitleAddition() const
2096 {
2097     return m_d->m_titleAddition;
2098 }
2099