OSDN Git Service

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