OSDN Git Service

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