OSDN Git Service

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