OSDN Git Service

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